autumn-plugin-svelte
Svelte 5 islands for Autumn
(autumn-web 0.10). The server renders an island in a Maud page. A small
loader mounts a compiled Svelte component into it. When htmx swaps HTML, the
loader mounts new islands and unmounts removed islands.
- You need no Node at run time. You deploy one binary.
- Autumn
PluginAssetsgives fingerprinted URLs,immutablecache and SRI hashes. - The loader works with the default Autumn CSP (
script-src 'self'). - The page shows the server fallback when JavaScript is off or a mount fails.
Install
After the first release on crates.io:
[]
= "0.3"
Before the release, use the Git repository:
[]
= { = "https://github.com/autumn-foundation/autumn-plugin-svelte" }
1. Build your components
Use Vite and Svelte 5. The
frontend/
directory is a complete reference project. These are the important parts:
// vite.config.js
import from "vite";
import from "@sveltejs/vite-plugin-svelte";
export default ;
// src/main.js: register the components with the loader.
import from "svelte";
import Counter from "./Counter.svelte";
let queue = window.;
if
queue.;
Run npm run build. Commit the output.
An ES module build (formats: ["es"]) also works. Name the file
islands.mjs, and do not split it into chunks.
2. Embed the bundle and install the plugin
This code is in src/main.rs. The Vite output is in islands/ at the crate
root, so the path is ../islands/.
use SveltePlugin;
use PluginAssets;
static ISLANDS: PluginAssets = from_files;
async
With the embed-assets feature, autumn_web::plugin_assets! can embed the
whole directory.
A library crate can install its own SveltePlugin with its own bundles. The
plugin name includes the bundle namespaces, so the two plugins do not
collide.
3. Render islands
use ;
use *;
async
Island method |
Effect |
|---|---|
new(name) |
Sets the registered component name. |
props(&value) |
Sets the JSON props. If the value is not a JSON object, props returns PropsError. ? changes it to AutumnError. |
mount_when(MountWhen::…) |
Sets the trigger: Load (default), Idle or Visible. |
fallback(markup) |
Sets the server content. The page shows it before the mount, without JavaScript and after an error. |
id(…), class(…) |
Set the attributes of the island element. |
Lifecycle
The loader keeps one record for each island element.
data-svelte-state |
Meaning |
|---|---|
pending |
The loader waits for the trigger or for the component registration. |
mounted |
The component is mounted. |
error |
The props, the mount or the nesting depth failed. The loader shows the fallback. |
| Event | Target | detail |
|---|---|---|
autumn:svelte:mount |
island (bubbles) | { name } |
autumn:svelte:error |
island (bubbles) | { name, error } |
autumn:svelte:unmount |
document |
{ name, element } |
- The loader mounts islands that htmx or a script adds later.
- The loader unmounts an island when it leaves the DOM. A moved island and
an
hx-preserveisland stay mounted. - When a morph (idiomorph) changes the island attributes or replaces its content, the loader unmounts the old component and mounts a new one.
- The loader keeps the fallback in a
<template data-svelte-fallback>child. When htmx restores a page from history, the loader mounts its islands again. - A bundle can register before or after the loader runs. A late registration mounts the islands that wait for it.
- The first registration of a name stays. A second one writes a console error.
- Errors in
onMountor$effectoccur after the mount. The island staysmounted. window.autumnSvelte.scan(root)mounts new islands inroot. You usually do not need it.
Security
-
An island element mounts a real component with its props. Thus user HTML must not make islands. Put user HTML in an element with
data-svelte-ignore(like htmxhx-disable). The loader does not mount islands in it:html!Also tell your sanitizer to remove
data-svelte-*attributes. -
A component that renders islands of itself stops at a depth of 16. The deepest island gets the
errorstate. -
Props are JSON in an attribute. Maud escapes them, and the loader uses only
JSON.parse.
CSP
- The loader uses no
eval, no inline script and no HTML parser. Thus it works withscript-src 'self'. - In Autumn nonce mode,
style-srchas no'unsafe-inline'. Then inlinestyle=attributes in components do not work. Use component<style>blocks (they go intoislands.css). - With Trusted Types, allow the
svelte-trusted-htmlpolicy of the Svelte runtime. svelte_script()has nononce. A'strict-dynamic'policy blocks it.
Limits
- The server does not render the component (Rust cannot run the Svelte compiler). The fallback is the first paint.
- You need Node to build your components.
- Props are in an HTML attribute. Keep them small.
svelte_bundlemakes tags for.css,.jsand.mjsfiles only.
Example
Open http://127.0.0.1:3000. See
examples/svelte_demo.rs.
Tests
Design
License
Apache-2.0.