(IN PROGRESS)
Rollup can be configured to build the necessary parts to do SSR with JS frameworks. I've only tested w/ Solid but with some modifications, you can also adapt the following for things like Svelte and perhaps other frameworks.
This is actually based largely off of LiveSvelte but I wanted to use something more common these days like Rollup - this is however just gonna be Rollup since we don't need the other Vite parts for this.
You'll need
- a build script
- the Elixir Node package
- Optionally a Rollup config file.
(adjust as needed / desired - these were used to keep things simple-ish)
- @babel/core
- @rollup/plugin-babel
- @rollup/plugin-commonjs
- @rollup/plugin-node-resolve
- babel-preset-solid
- chokidar or some other watcher package.
- See the docs for an example.
- Refer to the Phoenix docs for how to add a new watcher for your build script
- You can use the config loader functionality or just do everything in the build script itself.
- Note that when loading a config, the format property of the second argument is the output format you want; the loader seemingly ignores current settings inside the config. For LiveView stuff, you'll want
umd
as other options will attempt to overwrite thetop
variable of the browser for some reason. Alternatively you can compile each Phoenix component separately and add script tags for each.
- Note that when loading a config, the format property of the second argument is the output format you want; the loader seemingly ignores current settings inside the config. For LiveView stuff, you'll want
- Elixir-Node requires you to have an export of functions using the old cjs format, ie
// in <module name>.js
module.exports.<function name> = function (){}
When called, it will end up looking something like
NodeJS.call!({"<module name>", "<function>"}, [<arguments])
-
To trigger rebuilds of the JS on change, you may still need something like chokidar.
- As of 5.29.2024, Rollup is "supposed" to have watch functionality but for some reason it's returning undefined.
-
You can trigger the browser to reload when you change a file by modifying the
live_reload
field inconfig/dev.exs
-
Solid JS SSR Docs
defmodule LiveSolid do
def render() do
# server = file/module name
# :render = refers to the function within the module to call
# [] is for any arguments you need to pass to the Nodejs side.
try do
NodeJS.call!({"server", :render}, [], binary: true)
catch
:exit, {:noproc, message} ->
IO.inspect(message)
end
end
# defines where to look for the module.
# call this for the path parameter when you add the NodeJS supervisor (provided by elixir-nodejs)
def server_path() do
{:ok, path} = :application.get_application()
Application.app_dir(path,"priv/server")
end
end
Ok! Turns out it seems like the Babel path has issues when trying to build tsx for some reason. All the solutions I could find would work withjsx
but nottsx
for some strange reason so switching to Vite eventually even though you won't need like 90% of what it provides.Will update file once I work out everything.Turns out Rollup is fine after all. Confusingly enough, even there is a Babel preset package for Typescript, you still have to "turn on" the reading of Typescript files in the Babel plugin itself; I was expecting the preset to automatically do that.
Here is a sample build function