Skip to content

Commit

Permalink
Remove fingerprints from socket and track it in state
Browse files Browse the repository at this point in the history
  • Loading branch information
josevalim committed Jan 17, 2025
1 parent ee8602e commit 312fcbd
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 160 deletions.
14 changes: 9 additions & 5 deletions lib/phoenix_live_view/channel.ex
Original file line number Diff line number Diff line change
Expand Up @@ -950,34 +950,37 @@ defmodule Phoenix.LiveView.Channel do
defp render_diff(state, socket, force?) do
changed? = Utils.changed?(socket)

{socket, diff, components} =
{socket, diff, fingerprints, components} =
if force? or changed? do
:telemetry.span(
[:phoenix, :live_view, :render],
%{socket: socket, force?: force?, changed?: changed?},
fn ->
rendered = Phoenix.LiveView.Renderer.to_rendered(socket, socket.view)
{socket, diff, components} = Diff.render(socket, rendered, state.components)

{diff, fingerprints, components} =
Diff.render(socket, rendered, state.fingerprints, state.components)

socket =
socket
|> Lifecycle.after_render()
|> Utils.clear_changed()

{
{socket, diff, components},
{socket, diff, fingerprints, components},
%{socket: socket, force?: force?, changed?: changed?}
}
end
)
else
{socket, %{}, state.components}
{socket, %{}, state.fingerprints, state.components}
end

diff = Diff.render_private(socket, diff)
new_socket = Utils.clear_temp(socket)

{:diff, diff, %{state | socket: new_socket, components: components}}
{:diff, diff,
%{state | socket: new_socket, fingerprints: fingerprints, components: components}}
end

defp reply(state, {ref, extra}, status, payload) do
Expand Down Expand Up @@ -1373,6 +1376,7 @@ defmodule Phoenix.LiveView.Channel do
socket: lv_socket,
topic: phx_socket.topic,
components: Diff.new_components(),
fingerprints: Diff.new_fingerprints(),
upload_names: %{},
upload_pids: %{}
}
Expand Down
71 changes: 37 additions & 34 deletions lib/phoenix_live_view/diff.ex
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,16 @@ defmodule Phoenix.LiveView.Diff do
Renders a diff for the rendered struct in regards to the given socket.
"""
def render(
%{fingerprints: {expected, _}} = socket,
socket,
%Rendered{fingerprint: actual} = rendered,
{expected, _},
{_, _, uuids}
)
when expected != nil and expected != actual do
render(%{socket | fingerprints: new_fingerprints()}, rendered, new_components(uuids))
render(socket, rendered, new_fingerprints(), new_components(uuids))
end

def render(%{fingerprints: prints} = socket, %Rendered{} = rendered, components) do
def render(socket, %Rendered{} = rendered, prints, components) do
{diff, prints, pending, components, nil} =
traverse(socket, rendered, prints, %{}, components, nil, true)

Expand All @@ -142,10 +143,9 @@ defmodule Phoenix.LiveView.Diff do
{cdiffs, components} =
render_pending_components(socket, pending, cid_to_component, %{}, components)

socket = %{socket | fingerprints: prints}
diff = maybe_put_title(diff, socket)
{diff, cdiffs} = extract_events({diff, cdiffs})
{socket, maybe_put_cdiffs(diff, cdiffs), components}
{maybe_put_cdiffs(diff, cdiffs), prints, components}
end

defp maybe_put_cdiffs(diff, cdiffs) when cdiffs == %{}, do: diff
Expand Down Expand Up @@ -202,16 +202,16 @@ defmodule Phoenix.LiveView.Diff do
{cids, _, _} = components

case cids do
%{^cid => {component, id, assigns, private, fingerprints}} ->
%{^cid => {component, id, assigns, private, prints}} ->
{csocket, extra} =
socket
|> configure_socket_for_component(assigns, private, fingerprints)
|> configure_socket_for_component(assigns, private)
|> fun.(component)

diff = render_private(csocket, %{})

{pending, cdiffs, components} =
render_component(csocket, component, id, cid, false, cids, %{}, components)
render_component(csocket, component, id, prints, cid, false, cids, %{}, components)

{cdiffs, components} =
render_pending_components(socket, pending, cids, cdiffs, components)
Expand All @@ -233,9 +233,9 @@ defmodule Phoenix.LiveView.Diff do
{cid_to_component, _id_to_cid, _} = components

case cid_to_component do
%{^cid => {component, _id, assigns, private, fingerprints}} ->
%{^cid => {component, _id, assigns, private, _prints}} ->
socket
|> configure_socket_for_component(assigns, private, fingerprints)
|> configure_socket_for_component(assigns, private)
|> fun.(component)

%{} ->
Expand Down Expand Up @@ -658,21 +658,21 @@ defmodule Phoenix.LiveView.Diff do
"for component #{inspect(component)} when rendering template"
end

{socket, components} =
{socket, components, prints} =
case cids do
%{^cid => {_component, _id, assigns, private, prints}} ->
{private, components} = unmark_for_deletion(private, components)
{configure_socket_for_component(socket, assigns, private, prints), components}
{configure_socket_for_component(socket, assigns, private), components, prints}

%{} ->
myself_assigns = %{myself: %Phoenix.LiveComponent.CID{cid: cid}}

{mount_component(socket, component, myself_assigns),
put_cid(components, component, id, cid)}
put_cid(components, component, id, cid), new_fingerprints()}
end

assigns_sockets = [{new_assigns, socket} | assigns_sockets]
metadata = [{cid, id, new?} | metadata]
metadata = [{cid, id, prints, new?} | metadata]
seen_ids = Map.put(seen_ids, [component | id], true)
{assigns_sockets, metadata, components, seen_ids}
end)
Expand Down Expand Up @@ -709,15 +709,15 @@ defmodule Phoenix.LiveView.Diff do

defp zip_components(
[%{__struct__: Phoenix.LiveView.Socket} = socket | sockets],
[{cid, id, new?} | metadata],
[{cid, id, prints, new?} | metadata],
component,
cids,
{pending, diffs, components}
) do
diffs = maybe_put_events(diffs, socket)

{new_pending, diffs, components} =
render_component(socket, component, id, cid, new?, cids, diffs, components)
render_component(socket, component, id, prints, cid, new?, cids, diffs, components)

pending = Map.merge(pending, new_pending, fn _, v1, v2 -> v2 ++ v1 end)
zip_components(sockets, metadata, component, cids, {pending, diffs, components})
Expand Down Expand Up @@ -768,17 +768,17 @@ defmodule Phoenix.LiveView.Diff do
"as the list of assigns given, got: #{inspect(preloaded)}"
end

defp render_component(socket, component, id, cid, new?, cids, diffs, components) do
defp render_component(socket, component, id, prints, cid, new?, cids, diffs, components) do
changed? = new? or Utils.changed?(socket)

{socket, pending, diff, {cid_to_component, id_to_cid, uuids}} =
{socket, prints, pending, diff, components} =
if changed? do
rendered = component_to_rendered(socket, component, id)

{changed?, linked_cid, prints} =
maybe_reuse_static(rendered, socket, component, cids, components)
maybe_reuse_static(rendered, component, prints, cids, components)

{diff, component_prints, pending, components, nil} =
{diff, prints, pending, components, nil} =
traverse(socket, rendered, prints, %{}, components, nil, changed?)

children_cids =
Expand All @@ -790,13 +790,12 @@ defmodule Phoenix.LiveView.Diff do

socket =
put_in(socket.private.children_cids, children_cids)
|> Map.replace!(:fingerprints, component_prints)
|> Lifecycle.after_render()
|> Utils.clear_changed()

{socket, pending, diff, components}
{socket, prints, pending, diff, components}
else
{socket, %{}, %{}, components}
{socket, prints, %{}, %{}, components}
end

diffs =
Expand All @@ -806,8 +805,13 @@ defmodule Phoenix.LiveView.Diff do
diffs
end

socket = Utils.clear_temp(socket)
cid_to_component = Map.put(cid_to_component, cid, dump_component(socket, component, id))
dump =
socket
|> Utils.clear_temp()
|> dump_component(component, id, prints)

{cid_to_component, id_to_cid, uuids} = components
cid_to_component = Map.put(cid_to_component, cid, dump)
{pending, diffs, {cid_to_component, id_to_cid, uuids}}
end

Expand Down Expand Up @@ -850,18 +854,18 @@ defmodule Phoenix.LiveView.Diff do
# that will be changed before it is sent to the client.
#
# We don't want to traverse all of the components, so we will try it @attempts times.
defp maybe_reuse_static(rendered, socket, component, old_cids, components) do
defp maybe_reuse_static(rendered, component, prints, old_cids, components) do
{new_cids, id_to_cid, _uuids} = components
{current_print, _} = prints
%{fingerprint: print} = rendered
%{fingerprints: {socket_print, _} = socket_prints} = socket

with true <- socket_print != print,
with true <- current_print != print,
iterator = :maps.iterator(Map.fetch!(id_to_cid, component)),
{cid, existing_prints} <-
find_same_component_print(print, iterator, old_cids, new_cids, @attempts) do
{false, cid, existing_prints}
else
_ -> {true, nil, socket_prints}
_ -> {true, nil, prints}
end
end

Expand Down Expand Up @@ -921,23 +925,22 @@ defmodule Phoenix.LiveView.Diff do
|> Map.put(:lifecycle, %Phoenix.LiveView.Lifecycle{})

socket =
configure_socket_for_component(socket, assigns, private, new_fingerprints())
configure_socket_for_component(socket, assigns, private)
|> Utils.assign(:flash, %{})

Utils.maybe_call_live_component_mount!(socket, component)
end

defp configure_socket_for_component(socket, assigns, private, prints) do
defp configure_socket_for_component(socket, assigns, private) do
%{
socket
| assigns: Map.put(assigns, :__changed__, %{}),
private: private,
fingerprints: prints,
redirected: nil
}
end

defp dump_component(socket, component, id) do
{component, id, socket.assigns, socket.private, socket.fingerprints}
defp dump_component(socket, component, id, prints) do
{component, id, socket.assigns, socket.private, prints}
end
end
4 changes: 0 additions & 4 deletions lib/phoenix_live_view/socket.ex
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ defmodule Phoenix.LiveView.Socket do
router: nil,
assigns: %{__changed__: %{}},
private: %{live_temp: %{}},
fingerprints: Phoenix.LiveView.Diff.new_fingerprints(),
redirected: nil,
host_uri: nil,
transport_pid: nil
Expand All @@ -78,8 +77,6 @@ defmodule Phoenix.LiveView.Socket do
@typedoc "The data in a LiveView as stored in the socket."
@type assigns :: map | assigns_not_in_socket()

@type fingerprints :: {nil, map} | {binary, map}

@type t :: %__MODULE__{
id: binary(),
endpoint: module(),
Expand All @@ -89,7 +86,6 @@ defmodule Phoenix.LiveView.Socket do
router: module(),
assigns: assigns,
private: map(),
fingerprints: fingerprints,
redirected: nil | tuple(),
host_uri: URI.t() | :not_mounted_at_router,
transport_pid: pid() | nil
Expand Down
5 changes: 4 additions & 1 deletion lib/phoenix_live_view/static.ex
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,10 @@ defmodule Phoenix.LiveView.Static do

defp to_rendered_content_tag(socket, tag, view, attrs) do
rendered = Phoenix.LiveView.Renderer.to_rendered(socket, view)
{_, diff, _} = Diff.render(socket, rendered, Diff.new_components())

{diff, _, _} =
Diff.render(socket, rendered, Diff.new_fingerprints(), Diff.new_components())

content_tag(tag, attrs, Diff.to_iodata(diff))
end

Expand Down
4 changes: 3 additions & 1 deletion lib/phoenix_live_view/test/live_view_test.ex
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,9 @@ defmodule Phoenix.LiveViewTest do
end

defp rendered_to_diff_string(rendered, socket) do
{_, diff, _} = Diff.render(socket, rendered, Diff.new_components())
{diff, _, _} =
Diff.render(socket, rendered, Diff.new_fingerprints(), Diff.new_components())

diff |> Diff.to_iodata() |> IO.iodata_to_binary()
end

Expand Down
Loading

0 comments on commit 312fcbd

Please sign in to comment.