I’m trying to figure out how to plug in a custom compiler for Phoenix LiveView.
tl;dr:
- The mix task runs successfully
- The custom-compiled modules are picked by LiveView
- A custom file watcher picks up the files and compiles them on change
- The new changes are not picked up by LiveView
What works:
The mix task works:
- Create a compiler. Could be as easy as:
defmodule Custom.Compiler do
def compile_and_reload(files) do
Code.compiler_options(ignore_module_conflict: true)
for template_with_path <- files do
module_name = # create the module name any way you want
{:ok, content} = File.read(template_with_path)
module = """
defmodule CustomWeb.#{module_name} do
use Phoenix.LiveView
def render(assigns) do
~H\"#{content}\"
end
def mount(_params, _p, socket) do
temperature = 10
{:ok, assign(socket, :temperature, temperature)}
end
end
"""
Code.compile_string(module, template_with_path)
end
end
end
- Define a
Mix.Task.Compile.Custom
in your project:
defmodule Mix.Tasks.Compile.Custom do
use Mix.Task
@recursive true
def run(args) do
Code.ensure_compiled(Custom.Compiler)
templates = Path.join("lib/**", "/*.*custom")
|> Path.wildcard()
Custom.Compiler.compile_and_reload(templates)
:ok
end
end
- Add it to
mix.exs
:
compilers: Mix.compilers() ++ [:custom],
- Add to your
router.ex
(given that your custom module name isCustomWeb.Live.Test
):
scope "/", CustomWeb do
live "/thermostat", CustomWeb.Live.Test
end
- Run
iex -S mix phx.server
and open http://localhost:4000/thermostat
What doesn’t work
Expanding the above to a file watcher that recompiles custom code with the custom compiler… doesn’t trigger Phoenix LiveView to reload the module
- Add a watcher to
config/dev.exs
:
watchers: [
...
svx: {Custom.Compiler, :watch, []}
]
- Add
watch/0
to your compiler, and set up a file watch however you want (I’m usingfile_system
defmodule Custom.Compiler do
require Logger
use GenServer
def watch() do
# setup file watching in any way you need
end
....
end
- ??? Now what ???
- Simply calling
Code.compile
on a string with changed contents compiles… but doesn’t reload the module. - Calling
:code.purge
returnsfalse
and also does nothing -
Phoenix.CodeReloader.Server.reload!
? I can’t figure out what to pass to it - something else?
In any case so far when the file changes, and I recompile it, LiveView remains oblivious to the changes, and even reloading the pages doesn’t reload the module.
Hjälp!