diff --git a/CHANGELOG.md b/CHANGELOG.md index adc6747..55a6dc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,22 @@ 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.17.0 - 2026-01-22 + +### Breaking Changes + +- **Minimum OTP version is now 27** - LiveSvelte now uses Erlang's native `:json` module by default +- **Minimum Elixir version is now 1.17** - Required for OTP 27 support +- **Jason is now optional** - Add `{:jason, "~> 1.2"}` to your deps if you want to use Jason instead of native JSON + +### Changed + +- Default JSON library changed from Jason to native Erlang `:json` module (`LiveSvelte.JSON`) +- Structs are automatically converted to maps by the native JSON encoder (no `@derive` needed) + +### Added + +- New `LiveSvelte.JSON` module that wraps Erlang's native `:json` module with a Jason-compatible interface ## 0.16.0 - 2025-04-18 diff --git a/README.md b/README.md index 76b17df..90a21ef 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ _If you're updating from an older version, make sure to check the `CHANGELOG.md` ```elixir defp deps do [ - {:live_svelte, "~> 0.16.0"} + {:live_svelte, "~> 0.17.0"} ] end ``` @@ -487,6 +487,43 @@ To disable SSR on a specific component, set the `ssr` property to false. Like so <.svelte name="Example" ssr={false} /> ``` +### JSON Library + +LiveSvelte uses Erlang/OTP 27's native `:json` module by default for JSON encoding. +This provides excellent performance without requiring external dependencies. + +**Note:** LiveSvelte requires Elixir 1.17+ and OTP 27+ for the native JSON module. + +#### Using Jason or Poison + +If you prefer to use Jason, Poison, or another JSON library, configure it in your `config.exs`: + +```elixir +# config/config.exs +config :live_svelte, json_library: Jason +``` + +Add the dependency to your `mix.exs`: + +```elixir +# mix.exs +defp deps do + [ + {:live_svelte, "~> 0.17"}, + {:jason, "~> 1.2"} # or {:poison, "~> 5.0"} + ] +end +``` + +The JSON library must implement `encode!/1` that accepts any Elixir term and returns a JSON string. + +#### Struct Encoding + +The native JSON encoder automatically converts structs to maps before encoding. This means +you don't need `@derive Jason.Encoder` when using the default native JSON encoder. + +If you're using Jason and need custom struct encoding behavior, see the +[Structs and Ecto](#structs-and-ecto) section for details on `@derive Jason.Encoder`. ### live_json @@ -527,12 +564,15 @@ You can find an example [here](https://github.com/woutdp/live_svelte/blob/master ### Structs and Ecto -We use [Jason](https://github.com/michalmuskala/jason) to serialize any data you pass in the props so it can be handled by Javascript. -Jason doesn't know how to handle structs by default, so you need to define it yourself. +LiveSvelte serializes data passed in props to JSON so it can be handled by JavaScript. -#### Structs +**With native JSON (default):** Structs are automatically converted to maps. No additional configuration needed. -For example, if you have a regular struct like this: +**With Jason:** Jason doesn't know how to handle structs by default, so you need to define it yourself using `@derive`. + +#### Structs (Jason only) + +If you're using Jason and have a struct like this: ```elixir defmodule User do @@ -558,9 +598,9 @@ defmodule User do end ``` -#### Ecto +#### Ecto (Jason only) -In ecto's case it's important to _also_ omit the `__meta__` field as it's not serializable. +When using Jason with Ecto schemas, it's important to _also_ omit the `__meta__` field as it's not serializable. Check out the following example: diff --git a/assets/package-lock.json b/assets/package-lock.json index 569705a..abffe6a 100644 --- a/assets/package-lock.json +++ b/assets/package-lock.json @@ -31,7 +31,6 @@ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -454,7 +453,6 @@ "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -480,7 +478,6 @@ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6.0.0" } @@ -508,8 +505,7 @@ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/acorn": { "version": "8.14.0", @@ -531,7 +527,6 @@ "integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "acorn": ">=8.9.0" } @@ -542,7 +537,6 @@ "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", "dev": true, "license": "Apache-2.0", - "peer": true, "engines": { "node": ">= 0.4" } @@ -553,7 +547,6 @@ "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "engines": { "node": ">= 0.4" } @@ -565,6 +558,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -620,8 +614,7 @@ "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.1.4.tgz", "integrity": "sha512-oO82nKPHKkzIj/hbtuDYy/JHqBHFlMIW36SDiPCVsj87ntDLcWN+sJ1erdVryd4NxODacFTsdrIE3b7IamqbOg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/esrap": { "version": "1.2.2", @@ -629,7 +622,6 @@ "integrity": "sha512-F2pSJklxx1BlQIQgooczXCPHmcWpn6EsP5oo73LQfonG9fIlIENQ8vMmfGXeojP9MrkzUNAfyU5vdFlR9shHAw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15", "@types/estree": "^1.0.1" @@ -641,7 +633,6 @@ "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "*" } @@ -651,8 +642,7 @@ "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/magic-string": { "version": "0.30.12", @@ -660,7 +650,6 @@ "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } @@ -708,8 +697,7 @@ "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" } } } diff --git a/config/config.exs b/config/config.exs index 80a2033..7a1435a 100644 --- a/config/config.exs +++ b/config/config.exs @@ -3,6 +3,7 @@ import Config config :live_svelte, ssr_module: LiveSvelte.SSR.NodeJS, ssr: true + # json_library defaults to LiveSvelte.JSON (native Erlang :json module) # if Mix.env() == :dev do # esbuild = fn args -> diff --git a/lib/live_svelte.ex b/lib/live_svelte.ex index 9618cd5..3729d4e 100644 --- a/lib/live_svelte.ex +++ b/lib/live_svelte.ex @@ -94,19 +94,20 @@ defmodule LiveSvelte do -
Map.keys() |> json() - } - data-slots={@slots |> Slots.base_encode_64() |> json} - phx-update="ignore" - phx-hook="SvelteHook" - class={@class} - > + <% svelte_id = id(@name) %> +
Map.keys() |> json() + } + data-slots={@slots |> Slots.base_encode_64() |> json} + phx-hook="SvelteHook" + class={@class} + > +
<%= raw(@ssr_render["head"]) %>