A Mix compiler that finds the icons your compiled code uses and writes a pruned SVG sprite containing only those icons. Tree-shaking, but without all the messy JS.
It reads the modules the Elixir compiler just built, so it must run after compilation:
# mix.exs
compilers: Mix.compilers() ++ [:iconex]The sprite is written to priv/static/images/iconex.svg in the current
project, which Phoenix's Plug.Static serves at /images/iconex.svg. It
holds the icons of every set, as symbols named <set>-<name>.
Dynamic icon names
For most usage, simply calling a set's component, such as Iconex.lucide/1,
with a literal string is sufficient. However, if icon names are dynamically
constructed at runtime (such as a conditional on which icon to display), you
must "hint" the compiler with Iconex.hint/2.
See Iconex.hint/2 for more details.
What gets found
Every call to a set's component, such as Iconex.lucide/1, whose name is
a literal string, however it was written: <Iconex.lucide name="house" />,
<.lucide name={"house"} /> through import Iconex, an alias, or a
template loaded with embed_templates. Calls to other components, such as
the icon in a generated Phoenix CoreComponents, are not counted.
Names only known at runtime, such as name={@icon}, are invisible at build
time. List them in the set's :extra_icons or pass a literal list to
Iconex.hint/2:
Iconex.hint(:lucide, ["chevron-up", "chevron-down"])A name that doesn't exist in its set fails the build, pointing at the file
and line that referenced it. So does any use of a set that is not enabled in
config :iconex, :sets.
Scanning needs the modules' debug info, which Mix includes by default. A module compiled without it is skipped with a warning.
Configuration
# config/config.exs
config :iconex,
# Extra icon names to always include (for fully dynamic usages)
lucide: [extra_icons: ~w[loader circle x]],
# Where the sprite is written, relative to the project root
output_path: "priv/static/images/iconex.svg"Recompilation
The manifest records the icons found in each compiled module. Only modules
whose .beam changed are read again, and the sprite is only rewritten when
the overall set of icons changes.