Installation

View Source

LiveVue replaces esbuild with Vite for both client side code and SSR to achieve an amazing development experience.

Why Vite?

  • Vite provides a best-in-class Hot-Reload functionality and offers many benefits
  • esbuild package doesn't support plugins, so we would need to setup a custom build process anyway
  • In production, we'll use elixir-nodejs for SSR

If you don't need SSR, you can easily disable it with one line of configuration.

Prerequisites

  • Node.js installed (version 19 or later recommended)
  • Phoenix 1.7+ project
  • Elixir 1.13+

Setup Steps

Installation with Igniter

I'm aware that installation process takes a moment to complete, but it's worth it! 🫣 There's also ongoing work to create an igniter installer for LiveVue, should be ready in the next version 🤞

  1. Add LiveVue to your dependencies:
def deps do
  [
    {:live_vue, "~> 0.7"}
  ]
end
  1. Configure environments:
# in config/dev.exs
config :live_vue,
  vite_host: "http://localhost:5173",
  ssr_module: LiveVue.SSR.ViteJS,
  # if you want to disable SSR by default, set this to false
  ssr: true

# in config/prod.exs
config :live_vue,
  ssr_module: LiveVue.SSR.NodeJS,
  ssr: true
  1. Add LiveVue to your html_helpers in lib/my_app_web.ex:
defp html_helpers do
  quote do
    # ... existing code ...

    # Add support for Vue components
    use LiveVue

    # Generate component for each vue file, so you can use <.ComponentName> syntax
    # instead of <.vue v-component="ComponentName">
    use LiveVue.Components, vue_root: ["./assets/vue", "./lib/my_app_web"]
  end
end
  1. Run the setup command to generate required files:
mix deps.get
mix live_vue.setup
cd assets && npm install

The live_vue.setup command will create:

  • package.json with required dependencies
  • Vite, TypeScript, and PostCSS configs
  • Server entrypoint for SSR
  • Vue entrypoint files
  1. Update your JavaScript configuration:
// app.js
import topbar from "topbar" // instead of ../vendor/topbar
import {getHooks} from "live_vue"
import liveVueApp from "../vue"

// remember to import your css here
import "../css/app.css"

let liveSocket = new LiveSocket("/live", Socket, {
    // ... existing options ...
    hooks: getHooks(liveVueApp),
})
  1. Configure Tailwind to include Vue files:
// tailwind.config.js
module.exports = {
    content: [
        // ... existing patterns
        "./vue/**/*.vue",
        "../lib/**/*.vue",
    ],
}
  1. Update root.html.heex for Vite:
<LiveVue.Reload.vite_assets assets={["/js/app.js", "/css/app.css"]}>
  <link phx-track-static rel="stylesheet" href="/assets/app.css" />
  <script type="module" phx-track-static type="text/javascript" src="/assets/app.js">
  </script>
</LiveVue.Reload.vite_assets>
  1. Remove esbuild and tailwind packages from your dependencies in mix.exs:
defp deps do
  [
    # Remove these lines:
    # {:esbuild, "~> 0.8", runtime: Mix.env() == :dev},
    # {:tailwind, "~> 0.2", runtime: Mix.env() == :dev},

    # ... other dependencies ...
  ]
end
  1. Update your mix.exs aliases:
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
  1. Remove esbuild and tailwind config from config/config.exs

  2. Configure watchers in config/dev.exs:

config :my_app, MyAppWeb.Endpoint,
  watchers: [
    npm: ["--silent", "run", "dev", cd: Path.expand("../assets", __DIR__)]
  ]
  1. Setup SSR for production in application.ex:
children = [
  {NodeJS.Supervisor, [path: LiveVue.SSR.NodeJS.server_path(), pool_size: 4]},
  # ... other children
]
  1. Confirm everything is working by rendering an example Vue component in one of your LiveViews:
~H"""
<.vue
  count={@count}
  v-component="Counter"
  v-socket={@socket}
  v-on:inc={JS.push("inc")}
/>
"""
  1. (Optional) Enable stateful hot reload for LiveViews:

This provides a superior development experience by preserving the LiveView's state (e.g., form data, temporary assigns) while Vite instantly updates the Vue component's code on the client. You get the best of both worlds: state persistence from the server and immediate UI updates from the client.

# config/dev.exs
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)$"
    ]
  ]

Manually Adjusting package.json

If you need to set up your package.json manually instead of using mix live_vue.setup, follow these steps:

  1. Install the required packages:
cd assets

# vite
npm install -D vite @vitejs/plugin-vue

# tailwind
npm install -D tailwindcss autoprefixer postcss @tailwindcss/forms

# typescript
npm install -D typescript vue-tsc

# runtime dependencies
npm install --save vue topbar ../deps/live_vue ../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
  1. Add these scripts to your package.json:
{
    "private": true,
    "type": "module",
    "scripts": {
        "dev": "vite --host -l warn",
        "build": "vue-tsc && vite build",
        "build-server": "vue-tsc && vite build --ssr js/server.js --out-dir ../priv/vue --minify esbuild --ssrManifest && echo '{\"type\": \"module\" } ' > ../priv/vue/package.json"
    }
}

Troubleshooting

TypeScript Compatibility Issues

There's a known bug where recent versions of TypeScript are not compatible with the latest version of vue-tsc. If you encounter an error like:

npm install typescript@5.5.4 vue-tsc@2.10.0

You'll need to downgrade TypeScript and vue-tsc to specific versions:

npm install typescript@5.5.4 vue-tsc@2.10.0

This issue has been documented in LiveVue issue #43.

Protocol.UndefinedError with Custom Structs

If you encounter a Protocol.UndefinedError mentioning LiveVue.Encoder when passing custom structs as props, you need to implement the encoder protocol:

# Add this to your struct definitions
defmodule User do
  @derive LiveVue.Encoder
  defstruct [:name, :email, :age]
end

This is a safety feature to prevent accidental exposure of sensitive data. For more details, see Component Reference.

Next Steps

Now that you have LiveVue installed, check out our Getting Started Guide to create your first Vue component!