diff --git a/CHANGELOG.md b/CHANGELOG.md
index fdc962d..914f0e2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,11 +5,98 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## Unreleased
+## 0.18.0 - 2026-03-06
+
+> **Note:** Many of the features in this release were backported from
+> [live_vue](https://github.com/Valian/live_vue) by
+> [Jakub Skalecki](https://github.com/Valian). A huge thank you to Jakub
+> for the excellent architecture and implementation that served as the
+> foundation for props diffing, composables, streams support, Vite
+> integration, Igniter installer, and more.
+
+### Breaking Changes
+
+- **esbuild removed** — LiveSvelte no longer supports esbuild. Migrate to
+ Vite + `phoenix_vite`. See the [Upgrade Guide](guides/upgrade_guide.html)
+ for step-by-step instructions.
+
+- **live_json / live_json_props removed** — The `live_json` hex dependency
+ and `live_json_props` attribute have been removed. Replace with `props={...}`;
+ built-in JSON Patch diffing provides the same optimization by default.
+
+- **phoenix_vite now required** — Add `{:phoenix_vite, "~> 0.4"}` to your
+ `mix.exs` dependencies.
+
+### Added
+
+- **Vite integration** — Full Vite build pipeline replaces esbuild.
+ `phoenix_vite` handles client and SSR builds with a single `vite.config.mjs`.
+
+- **Vite HMR** — Hot Module Replacement for Svelte components and CSS in
+ development. Zero extra config when using `phoenix_vite` — just run
+ `mix phx.server`.
+
+- **ViteJS SSR mode** — New `LiveSvelte.SSR.ViteJS` backend sends SSR render
+ requests to the Vite dev server over HTTP. New `.svelte` files are picked up
+ immediately without running `mix assets.build`.
+
+- **SSR telemetry** — SSR render events emit telemetry under
+ `[:live_svelte, :ssr, :render, :start]` / `[:live_svelte, :ssr, :render, :stop]`
+ for performance monitoring.
+
+- **Igniter installer** — `mix live_svelte.install` (powered by
+ [Igniter](https://hex.pm/packages/igniter)) sets up LiveSvelte automatically
+ in an existing Phoenix project, including Vite config, endpoint changes, and
+ JavaScript entrypoint.
+
+- **Props diffing (JSON Patch)** — Server-side props are diffed using RFC 6902
+ JSON Patch, sending only changed values to the client. Enabled by default;
+ disable with `config :live_svelte, enable_props_diff: false`.
+
+- **Svelte encoder** — New `LiveSvelte.Encoder` protocol for custom JSON
+ serialization of Svelte props. Replaces the need for `@derive Jason.Encoder`
+ on Elixir structs.
+
+- **Streams support** — Phoenix `stream/3` now works with Svelte components.
+ Stream operations are sent as JSON Patch ops via the `data-streams-diff`
+ attribute.
+
+- **Live form support** — New `useLiveForm` composable for Ecto
+ changeset-backed forms in Svelte with server-side validation feedback.
+
+- **File upload support** — New `useLiveUpload` composable for Phoenix
+ LiveView file uploads with progress tracking.
+
+- **Event reply** — New `useEventReply` composable for handling `push_reply`
+ responses from the server.
+
+- **Live navigation** — New `useLiveNavigation` composable exposing `patch()`
+ and `navigate()` for client-side routing from Svelte.
+
+- **TypeScript rewrite** — Library source (`assets/js/live_svelte/*.ts`) is
+ now written in TypeScript with full type definitions exported via
+ `package.json`.
+
+- **Hot-apply new components** — New `.svelte` files added during development
+ are automatically discovered by the ViteJS SSR mode and Vite plugin without
+ restarting the Phoenix server.
+
+- **CI/CD** — GitHub Actions workflows for Elixir (tests + Coveralls coverage
+ reporting) and frontend (Vitest unit tests).
+
+- **Documentation** — `ex_doc` integration; all public modules now have
+ HexDocs entries.
+
+- **New examples** — Drag & Drop, Rich Text Editor (Editor.js), Runed state
+ management, Svelte Stores.
### Removed
-- **live_json** — The `live_json` hex dependency and `live_json_props` feature have been removed from the library and example project. Use built-in props diffing and JSON Patch (see Configuration) for efficient prop updates instead.
+- **esbuild** — Removed `esbuild` mix dependency, `assets/build.js`, and all
+ related `config :esbuild` configuration.
+
+- **live_json / live_json_props** — Removed in favor of built-in props
+ diffing (enabled by default).
## 0.17.4 - 2026-02-18
diff --git a/example_project/mix.exs b/example_project/mix.exs
index 3beb6ed..680bd16 100644
--- a/example_project/mix.exs
+++ b/example_project/mix.exs
@@ -4,8 +4,9 @@ defmodule Example.MixProject do
def project do
[
app: :example,
- version: "0.1.0",
- elixir: "~> 1.16",
+ name: "LiveSvelte Example",
+ version: "0.18.0",
+ elixir: "~> 1.18",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
listeners: [Phoenix.CodeReloader],
@@ -37,7 +38,7 @@ defmodule Example.MixProject do
{:gettext, "~> 0.20"},
{:json_diff_ex, "~> 0.6", override: true},
{:live_svelte, path: ".."},
- # {:live_svelte, "~> 0.17.4"},
+ # {:live_svelte, "~> 0.18.0"},
{:phoenix, "~> 1.8.0"},
{:phoenix_ecto, "~> 4.4"},
{:phoenix_html, "~> 4.1"},
diff --git a/guides/upgrade_guide.md b/guides/upgrade_guide.md
new file mode 100644
index 0000000..25dd105
--- /dev/null
+++ b/guides/upgrade_guide.md
@@ -0,0 +1,207 @@
+# Upgrade Guide
+
+## Upgrading to 0.18.0
+
+Version 0.18.0 migrates the build toolchain from esbuild to Vite and removes
+the `live_json` dependency. Follow the steps below to update your project.
+
+### 1. Replace esbuild with Vite
+
+#### `mix.exs` — swap deps
+
+```elixir
+# Remove:
+{:esbuild, "~> 0.8", runtime: Mix.env() == :dev}
+
+# Add:
+{:phoenix_vite, "~> 0.4"}
+```
+
+Also remove any `config :esbuild` block from `config/config.exs`:
+
+```elixir
+# Remove entirely:
+config :esbuild, :default,
+ args: ~w(js/app.js --bundle ...),
+ cd: Path.expand("../assets", __DIR__),
+ env: %{"NODE_PATH" => ...}
+```
+
+Run `mix deps.get` after updating `mix.exs`.
+
+#### `assets/package.json` — add Vite and Svelte plugin
+
+```json
+{
+ "devDependencies": {
+ "vite": "^6.0.0",
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
+ "@tailwindcss/vite": "^4.0.0"
+ }
+}
+```
+
+Run `npm install` (or `cd assets && npm install`) after updating.
+
+#### Create `assets/vite.config.mjs`
+
+Delete the old `assets/build.js` and create `assets/vite.config.mjs`:
+
+```javascript
+import { defineConfig } from "vite"
+import { svelte } from "@sveltejs/vite-plugin-svelte"
+import liveSveltePlugin from "live_svelte/vitePlugin"
+import tailwindcss from "@tailwindcss/vite"
+
+export default defineConfig({
+ server: {
+ host: "127.0.0.1",
+ port: 5173,
+ strictPort: true,
+ cors: { origin: "http://localhost:4000" },
+ },
+ optimizeDeps: {
+ include: ["live_svelte", "phoenix", "phoenix_html", "phoenix_live_view"],
+ },
+ ssr: { noExternal: process.env.NODE_ENV === "production" ? true : undefined },
+ build: {
+ manifest: false,
+ ssrManifest: false,
+ rollupOptions: { input: ["js/app.js", "css/app.css"] },
+ outDir: "../priv/static",
+ emptyOutDir: true,
+ },
+ plugins: [
+ tailwindcss(),
+ svelte({ compilerOptions: { css: "injected" } }),
+ liveSveltePlugin({ entrypoint: "./js/server.js" }),
+ ],
+})
+```
+
+The `liveSveltePlugin` is exported from `live_svelte/vitePlugin` and handles
+SSR component discovery automatically — no separate SSR build config is needed.
+
+#### Update `config/dev.exs` — replace esbuild watcher with Vite
+
+```elixir
+# Remove from watchers:
+esbuild: {Esbuild, :install_and_run, [:default, ~w(--bundle ...)]}
+
+# Update the endpoint config block:
+config :my_app, MyAppWeb.Endpoint,
+ http: [ip: {127, 0, 0, 1}, port: 4000],
+ check_origin: false,
+ code_reloader: true,
+ debug_errors: true,
+ secret_key_base: "...",
+ # Assets are now served by the Vite dev server on port 5173:
+ static_url: [host: "localhost", port: 5173],
+ watchers: [
+ tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]},
+ vite: {PhoenixVite.Npm, :run, [:vite, ~w(dev)]}
+ ]
+```
+
+Setting `static_url` to the Vite dev server port is important — it ensures
+LiveView generates asset URLs that point to the Vite dev server (which provides
+HMR) rather than Phoenix's static file serving.
+
+Add ViteJS SSR for development at the bottom of `config/dev.exs`. This means
+new `.svelte` files are discovered automatically without needing to rebuild assets
+after every addition:
+
+```elixir
+config :live_svelte, ssr_module: LiveSvelte.SSR.ViteJS, vite_host: "http://localhost:5173"
+```
+
+Production continues to use NodeJS SSR with the pre-built `priv/svelte/server.js`
+(the default), so no production config change is needed.
+
+#### Update `lib/my_app_web/endpoint.ex`
+
+Import `PhoenixVite.Plug` and add the favicon plug. The favicon plug proxies the
+browser favicon request to the Vite dev server in development:
+
+```elixir
+defmodule MyAppWeb.Endpoint do
+ use Phoenix.Endpoint, otp_app: :my_app
+ import PhoenixVite.Plug # <-- add this
+
+ # ... socket declarations ...
+
+ # Add before Plug.Static:
+ plug :favicon, dev_server: {PhoenixVite.Components, :has_vite_watcher?, [__MODULE__]}
+
+ plug Plug.Static,
+ at: "/",
+ from: :my_app,
+ gzip: false,
+ only: MyAppWeb.static_paths()
+
+ # ... rest of plugs unchanged ...
+end
+```
+
+#### Update `lib/my_app_web/components/layouts/root.html.heex`
+
+Replace the static asset tags with `PhoenixVite.Components.assets`. This single
+component handles both development (proxying to the Vite dev server with HMR)
+and production (emitting hashed `
+
+<%# Replace with: %>
+ static_url(@conn, p) end}
+/>
+```
+
+Replace `:my_app` and `MyAppWeb.Endpoint` with your own OTP app name and
+endpoint module.
+
+### 2. Remove live_json (if used)
+
+Remove the dependency from `mix.exs`:
+
+```elixir
+# Remove:
+{:live_json, "~> 0.4"}
+```
+
+In your LiveViews, replace the `live_json_props` attribute with the standard
+`props` attribute. Props diffing via JSON Patch is enabled by default in 0.18.0,
+so payloads remain optimized — only changed values are sent over the wire:
+
+```heex
+<%# Before: %>
+<.svelte name="MyComponent" live_json_props={@json_props} socket={@socket} />
+
+<%# After: %>
+<.svelte name="MyComponent" props={@my_props} socket={@socket} />
+```
+
+If you want to disable props diffing globally (not recommended):
+
+```elixir
+# config/config.exs
+config :live_svelte, enable_props_diff: false
+```
+
+### 3. Verify the upgrade
+
+After completing the steps above:
+
+```bash
+mix deps.get
+cd assets && npm install && cd ..
+mix phx.server # Should start Phoenix + Vite dev server together
+mix test # Library unit tests
+cd example_project && mix assets.build && mix test --only phoenix_test
+```
diff --git a/mix.exs b/mix.exs
index de2bd8e..27f163d 100644
--- a/mix.exs
+++ b/mix.exs
@@ -1,7 +1,7 @@
defmodule LiveSvelte.MixProject do
use Mix.Project
- @version "0.17.4"
+ @version "0.18.0"
@repo_url "https://github.com/woutdp/live_svelte"
def project do
@@ -38,6 +38,7 @@ defmodule LiveSvelte.MixProject do
# Getting Started
"guides/installation.md": [title: "Installation"],
+ "guides/upgrade_guide.md": [title: "Upgrade Guide"],
"guides/basic_usage.md": [title: "Basic Usage"],
# Core Usage
@@ -59,7 +60,7 @@ defmodule LiveSvelte.MixProject do
"guides/troubleshooting.md": [title: "Troubleshooting"]
],
groups_for_extras: [
- "Getting Started": ~r/guides\/(installation|basic_usage)/,
+ "Getting Started": ~r/guides\/(installation|upgrade_guide|basic_usage)/,
"Core Usage": ~r/guides\/(forms|uploads|streams|ssr|configuration)/,
Reference: ~r/guides\/api_reference/,
"Advanced Topics": ~r/guides\/(introduction|testing|deployment)/,
diff --git a/package.json b/package.json
index 8b8d5bb..c283983 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "live_svelte",
- "version": "0.17.4",
+ "version": "0.18.0",
"description": "",
"license": "MIT",
"types": "./assets/js/live_svelte/types.d.ts",