Phoenix LiveView sends bigger payload than expected with conditional parent

Hello everyone. I’m building an application streaming AI responses using LiveView. When checking websocket payload I noticed something unexpected.

This is a minimal replication example - process is receiving a lot of update events (coming as response from LLM is being streamed).

defmodule AppWeb.TestLive do
  use AppWeb, :live_view

  def handle_params(_params, _url, socket) do
    socket =
      socket
      # faking a big data structure
      |> assign(audience: %{test: Enum.to_list(1..1000)})
      |> assign(selected_node: nil)

    # faking frequent updates
    Process.send_after(self(), "this is test", 30)

    {:noreply, socket}
  end

  def handle_info(node, socket) do
    # this is happening very frequently, ~50 times a second. I'm updating only selected_node
    socket = assign(socket, :selected_node, node)
    Process.send_after(self(), "this is test #{Enum.random(1..1000)}", 30)
    {:noreply, socket}
  end

  def render(assigns) do
    ~H"""
    <div :if={@audience}>
      <script><%= Jason.encode!(@audience) |> raw %></script>
      <div :if={@selected_node}>
        <%= @selected_node %>
      </div>
    </div>
    """
  end
end

My expectations is that payload sent to client will be tiny, only content of the

      <div :if={@selected_node}>
        <%= @selected_node %>
      </div>

but for unknown reason also <%= Jason.encode!(@audience) |> raw %> part is also sent as a payload. I’m not sure why, since it’s not in assigns.__changed__ LiveView should know nothing changed there?

Diff from DevTools

If I move :if={@audience} to graph-data, it works as expected

  def render(assigns) do
    ~H"""
    <div>
      <script id="graph-data" :if={@audience}>
        <%= Jason.encode!(@audience) |> raw %>
      </script>
      ...
    </div>
    """
  end

In my case I was using @audience assign in multiple places inside root node, that’s why I had it there. Working around this just to have smaller payload shouldn’t be needed? What do you think, are my expectations wrong and it just have to be that way?

I was thinking about creating issue on Github but posting here first seems less intrusive.

2 Likes

Anyone? :sweat_smile: @chrismccord is it an unreasonable expectation?

Gah, this left me puzzled but it is a very silly detail. LiveView is considering raw to be a variable and marking that piece of code as tainted. I will push a fix for it. Write raw() and you should be good.

6 Likes

So it was about missing parenthesis? :see_no_evil: I wouldn’t have guessed. Thanks!

Also fixed in main.

3 Likes