LiveReact replaces hex esbuild
with Vite for both client side code and SSR to achieve a better development experience. Why ?
- Vite provides a best-in-class Hot-Reload functionality and offers many benefits not present in esbuild
hex esbuild
package doesn't support plugins, while it's possible to do ssr withhex esbuild
(check v0.2.0-rc-0) the SSR in development is broken.- the integration to react and ssr is more documented with Vite
In production, we'll use elixir-nodejs for SSR. If you don't need SSR, you can disable it with one line of code. TypeScript will be supported as well.
-
install nodejs (I recommend mise)
-
Add
live_react
to your list of dependencies inmix.exs
and runmix deps.get
def deps do
[
{:live_react, "~> 1.0.0-rc.3"},
{:nodejs, "~> 3.1.2"} # if you want to use SSR in production
]
end
- Add a config entry to your
config/dev.exs
config :live_react,
vite_host: "http://localhost:5173",
ssr_module: LiveReact.SSR.ViteJS,
ssr: true
- Add a config entry to your
config/prod.exs
config :live_react,
ssr_module: LiveReact.SSR.NodeJS,
ssr: true # or false if you don't want SSR in production
- Add
import LiveReact
inhtml_helpers/0
inside/lib/<app_name>_web.ex
like so:
# /lib/<app_name>_web.ex
defp html_helpers do
quote do
# ...
import LiveReact # <-- Add this line
# ...
end
end
- LiveReact comes with a handy mix task to setup all the required files. It won't alter any files you already have in your project, you need to adjust them on your own by looking at the sources. Additional instructions how to adjust
package.json
can be found at the end of this page.
It will create:
package.json
- vite, typescript and postcss configs
- server entrypoint
- react components root
- Run the following in your terminal
mix deps.get
mix live_react.setup
npm install --prefix assets
- Add the following to your
assets/js/app.js
file
...
import topbar from "topbar" // instead of ../vendor/topbar
import { getHooks } from "live_react";
import components from "../react-components";
import "../css/app.css" // the css file is handled by vite
const hooks = {
// ... your other hooks
...getHooks(components),
};
...
let liveSocket = new LiveSocket("/live", Socket, {
hooks: hooks, // <- pass the hooks
longPollFallbackMs: 2500,
params: { _csrf_token: csrfToken },
});
...
- For tailwind support, make some addition to
content
in theassets/tailwind.config.js
file
content: [
...
"./react-components/**/*.jsx", // <- if you are using jsx
"./react-components/**/*.tsx" // <- if you are using tsx
],
- Let's update
root.html.heex
to use Vite files in development. There's a handy wrapper for it.
<LiveReact.Reload.vite_assets assets={["/js/app.js", "/css/app.css"]}>
<link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
<script type="module" phx-track-static type="text/javascript" src={~p"/assets/app.js"}>
</script>
</LiveReact.Reload.vite_assets>
- Update
mix.exs
aliases and removetailwind
andesbuild
packages
defp aliases do
[
setup: ["deps.get", "assets.setup", "assets.build"],
"assets.setup": ["cmd --cd assets npm install"],
"assets.build": [
"cmd --cd assets npm run build",
"cmd --cd assets npm run build-server"
],
"assets.deploy": [
"cmd --cd assets npm run build",
"cmd --cd assets npm run build-server",
"phx.digest"
]
]
end
defp deps do
[
# remove these lines, we don't need esbuild or tailwind here anymore
# {:esbuild, "~> 0.8", runtime: Mix.env() == :dev},
# {:tailwind, "~> 0.2", runtime: Mix.env() == :dev},
]
end
-
Remove esbuild and tailwind config from
config/config.exs
-
Update watchers in
config/dev.exs
to look like this
config :my_app, MyAppWeb.Endpoint,
# ...
watchers: [
npm: ["run", "dev", cd: Path.expand("../assets", __DIR__)]
]
- To make SSR working with
LiveReact.SSR.NodeJS
in production, you have to add this entry to yourapplication.ex
supervision tree to run the NodeJS server
If you don't want SSR in production, you can skip this step.
children = [
...
{NodeJS.Supervisor, [path: LiveReact.SSR.NodeJS.server_path(), pool_size: 4]},
# note Adjust the pool_size depending of the machine
]
- Confirm everything is working by rendering the default React component anywhere in your Dead or Live Views
<.react name="Simple" />
- (Optional) enable stateful hot reload of phoenix LiveViews - it allows for stateful reload across the whole stack 🤯. Just adjust your
dev.exs
to look like this - addnotify
section and removelive|components
from patterns.
# Watch static and templates for browser reloading.
config :my_app, MyAppWeb.Endpoint,
live_reload: [
notify: [
live_view: [
~r"lib/my_app_web/core_components.ex$",
~r"lib/my_app_web/(live|components)/.*(ex|heex)$"
]
],
patterns: [
~r"priv/static/(?!uploads/).*(js|css|png|jpeg|jpg|gif|svg)$",
~r"lib/my_app_web/controllers/.*(ex|heex)$"
]
]
Profit! 💸
Install these packages
cd assets
# vite
npm install -D vite @vitejs/plugin-react
# tailwind
npm install -D tailwindcss autoprefixer postcss @tailwindcss/forms
# typescript
npm install -D typescript @types/react @types/react-dom
# runtime dependencies
npm install --save react react-dom topbar ../deps/live_react ../deps/phoenix ../deps/phoenix_html ../deps/phoenix_live_view
# remove topbar from vendor, since we'll use it from node_modules
rm vendor/topbar.js
and add these scripts used by watcher and mix assets.build
command
{
"private": true,
"type": "module",
"scripts": {
"dev": "vite --host -l warn",
"build": "tsc && vite build",
"build-server": "tsc && vite build --ssr js/server.js --out-dir ../priv/react-components --minify esbuild && echo '{\"type\": \"module\" } ' > ../priv/react-components/package.json"
}
}