From 0726bf67819cab62336819faabfe6756d75a03a3 Mon Sep 17 00:00:00 2001 From: Max Veytsman Date: Fri, 2 Sep 2022 21:01:48 -0400 Subject: [PATCH] Optimize Phoenix Component caching --- lib/heroicons/cache.ex | 55 ++++++++++---------------------------- lib/heroicons/generator.ex | 37 +++++++++++++++++++------ 2 files changed, 43 insertions(+), 49 deletions(-) diff --git a/lib/heroicons/cache.ex b/lib/heroicons/cache.ex index c7b85a0..7e83689 100644 --- a/lib/heroicons/cache.ex +++ b/lib/heroicons/cache.ex @@ -12,69 +12,42 @@ defmodule Heroicons.Cache do @doc false def start_link(_), do: GenServer.start_link(__MODULE__, [], name: @name) - @doc "Fetch a pre-compiled Phoenix Component from the cache or disk, given a `path`" - def fetch_component(path) do - case :ets.lookup(@name.Components, path) do - [{^path, component}] -> - component - - [] -> - GenServer.call(@name, {:cache_component, path}) - end - end - - @doc "Fetch a icon's body from the cache or disk, given a `path`" - def fetch_body(path) do + @doc "Fetch a icon's body and fingerprint from the cache or disk, given a `path`" + def fetch_icon(path) do case :ets.lookup(@name, path) do - [{^path, body}] -> - body + [{^path, icon_body, fingerprint}] -> + {icon_body, fingerprint} [] -> - GenServer.call(@name, {:cache_body, path}) + GenServer.call(@name, {:cache_icon, path}) end end @impl true def init(_) do :ets.new(@name, [:set, :protected, :named_table]) - :ets.new(@name.Components, [:set, :protected, :named_table]) {:ok, []} end @impl true - def handle_call({:cache_body, path}, _ref, state) do - body = read_body(path) + def handle_call({:cache_icon, path}, _ref, state) do + {icon_body, fingerprint} = read_icon(path) - :ets.insert_new(@name, {path, body}) + :ets.insert_new(@name, {path, icon_body, fingerprint}) - {:reply, body, state} + {:reply, {icon_body, fingerprint}, state} end - def handle_call({:cache_component, path}, _ref, state) do - body = read_body(path) - - component = - EEx.compile_string(" body, - engine: Phoenix.LiveView.HTMLEngine, - file: __ENV__.file, - line: __ENV__.line + 1, - module: __ENV__.module, - indentation: 0 - ) - - :ets.insert_new(@name.Components, {path, component}) - - {:reply, component, state} - end - - defp read_body(path) do + defp read_icon(path) do icon = Path.join(:code.priv_dir(:heroicons), path) |> File.read!() - <<"> = icon + <<"> = icon - body + <> = :erlang.md5(icon) + + {icon_body, fingerprint} end end diff --git a/lib/heroicons/generator.ex b/lib/heroicons/generator.ex index b921fd5..34bd170 100644 --- a/lib/heroicons/generator.ex +++ b/lib/heroicons/generator.ex @@ -71,13 +71,33 @@ defmodule Heroicons.Generator do attrs = @assigns_to_attrs_mod.assigns_to_attributes(assigns) assigns = @assign_mod.assign(assigns, :attrs, attrs) - {component, _binding} = - Code.eval_quoted( - Heroicons.Cache.fetch_component(path), - assigns: assigns - ) + dynamic = fn track_changes? -> + changed = + case assigns do + %{__changed__: changed} when track_changes? -> changed + _ -> nil + end - component + attrs = + case Phoenix.LiveView.Engine.changed_assign?(changed, :attrs) do + true -> elem(Phoenix.HTML.attributes_escape(assigns.attrs), 1) + false -> nil + end + + [attrs] + end + + {icon_body, fingerprint} = Heroicons.Cache.fetch_icon(path) + + %Phoenix.LiveView.Rendered{ + static: [ + "