Mix compiler that vendors PhoenixKit's JS hooks into the host app.
A LiveView JS hook must be present in the host's single LiveSocket at
construction time — a nested LiveView cannot register one at runtime. This
compiler keeps two vendored files current on every mix compile:
priv/static/assets/vendor/phoenix_kit.js— a straight copy of PhoenixKit's own core hooks file. Previously this was only copied once, bymix phoenix_kit.install/mix phoenix_kit.update(File.cp/2inPhoenixKit.Install.JsIntegration) — a deploy that doesrm -rf priv/static+ rebuild without re-runningphoenix_kit.update(i.e. most CI/CD pipelines) shipped a 404 on this file, silently breaking every PhoenixKit JS hook. Vendoring it from a compiler makes it self-healing: it comes back on the nextmix compile, with zero dependency onphoenix_kit.updateever having run again after install.priv/static/assets/vendor/phoenix_kit_modules.js— external modules declare prebuilt hook bundles viajs_sources/0(seePhoenixKit.Module); this compiler discovers them viaPhoenixKit.ModuleDiscovery, resolves each bundle's absolute path via:code.priv_dir/1(works for Hex installs and path deps alike), and concatenates them (each wrapped in an IIFE so their top-level scopes can't collide) into this file, followed by a merge that folds each bundle'swindow.<Global>intowindow.PhoenixKitHooks(which the host spreads intoLiveSocket).
Both writes are diffed against the existing file first, so a mix compile
that changes nothing doesn't touch either file (avoids live-reload thrash).
The two <script> tags are stable: adding or removing a JS-bearing
module only changes phoenix_kit_modules.js's content on the next compile —
never the host's layout — so it stays zero-config like css_sources/0.
Setup (one-time, by mix phoenix_kit.install)
# mix.exs
compilers: [:phoenix_kit_js_sources, :phoenix_live_view] ++ Mix.compilers()
# root.html.heex, before app.js
<script src={~p"/assets/vendor/phoenix_kit.js"}></script>
<script src={~p"/assets/vendor/phoenix_kit_modules.js"}></script>Failures are loud: a missing core JS file (corrupted/incomplete dependency fetch) or a declared module bundle that can't be resolved raises a compile error rather than silently shipping "unknown hook" console errors.