Cache icon bodies and components

This commit is contained in:
Max Veytsman
2022-09-02 07:20:50 -04:00
parent c61b1b39c4
commit 63b0668dcf
4 changed files with 81 additions and 14 deletions

View File

@ -18,12 +18,23 @@ defmodule Heroicons do
"""
# https://github.com/tailwindlabs/heroicons/releases
@latest_version "2.0.10"
@tmp_dir_name "heroicons-elixir"
use Application
require Logger
@doc false
def start(_type, _args) do
children = [
{Heroicons.IconCache, []}
]
opts = [strategy: :one_for_one, name: Heroicons.Supervisor]
Supervisor.start_link(children, opts)
end
@doc false
# Latest known version at the time of publishing.
def latest_version, do: @latest_version

View File

@ -66,14 +66,13 @@ defmodule Heroicons.Generator do
attrs = @assigns_to_attrs_mod.assigns_to_attributes(assigns)
assigns = @assign_mod.assign(assigns, :attrs, attrs)
EEx.compile_string("<svg {@attrs}" <> Heroicons.IconCache.icon_body(path),
engine: Phoenix.LiveView.HTMLEngine,
file: __ENV__.file,
line: __ENV__.line + 1,
module: __ENV__.module,
indentation: 0,
assigns: assigns
)
{component, _binding} =
Code.eval_quoted(
Heroicons.IconCache.fetch_component(path),
assigns: assigns
)
component
end
@doc false
@ -93,7 +92,7 @@ defmodule Heroicons.Generator do
"<svg",
Phoenix.HTML.Safe.to_iodata(attrs),
" ",
Heroicons.IconCache.icon_body(path)
Heroicons.IconCache.fetch_body(path)
]}
end
end

View File

@ -1,8 +1,64 @@
defmodule Heroicons.IconCache do
@doc "Get's an icon's body from the filesystem"
# TODO implement ETS-based caching & benchmark
def icon_body(path) do
use GenServer
@name __MODULE__
def start_link(_), do: GenServer.start_link(__MODULE__, [], name: @name)
def fetch_component(path) do
case :ets.lookup(@name.Components, path) do
[{^path, component}] ->
component
[] ->
GenServer.call(@name, {:cache_component, path})
end
end
def fetch_body(path) do
case :ets.lookup(@name, path) do
[{^path, body}] ->
body
[] ->
GenServer.call(@name, {:cache_body, path})
end
end
def init(_) do
:ets.new(@name, [:set, :protected, :named_table])
:ets.new(@name.Components, [:set, :protected, :named_table])
{:ok, []}
end
def handle_call({:cache_body, path}, _ref, state) do
body = read_body(path)
:ets.insert_new(@name, {path, body})
{:reply, body, state}
end
def handle_call({:cache_component, path}, _ref, state) do
body = read_body(path)
component =
EEx.compile_string("<svg {@attrs}" <> 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
icon = File.read!(path)
<<"<svg ", body::binary>> = icon

View File

@ -20,7 +20,8 @@ defmodule HeroiconsElixir.MixProject do
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
extra_applications: [:logger],
mod: {Heroicons, []}
]
end