Migrating from SvelteKit
These tables map the form and mutation features of SvelteKit to Silgi. They cover forms and handlers only; the tables on pages, data and the server in Migrating from Nuxt apply to any app. none means Silgi has no equivalent today.
The shape is one thing in Silgi: a handler, a typed function that runs on the server, exported from server/index.ts. A form posts to it (Form action={fn}), a component calls it (useAction(fn), useAsyncData(fn, input)), and with a route a URL answers it. It works without JavaScript, it is a public endpoint that must check who calls it, and it needs no directive.
Form actions
| SvelteKit | Silgi | Differences |
|---|---|---|
+page.server.ts with export const actions | a handler for each action, exported from server/index.ts | one handler per intent, or a field in input; there is no ?/name |
actions = { default } | one handler | |
async ({ request }) => { const data = await request.formData() } | defineHandler({ input, handler(input) }) | the form is decoded by formToObject before the handler; with raw: true and a route, await event.request.formData() |
fail(400, { errors }) | fail(400, { errors }) | status 400 to 499 only; the page gets it from useAction(fn).failure |
redirect(303, "/x") | redirect("/x") | status is the optional second argument, 302 by default; a form post is answered with 303 |
error(404, "x") | throw createError({ status: 404, message: "x" }) | |
form prop of the page, $page.form | useAction(fn) and useForm(fn) | state, failure, error, pending and result; typed from the handler |
use:enhance | Form (@silgi/svelte), or enhance(form, options) from silgi/app | Form renders a plain form that works with JavaScript off; onSubmit replaces the callback form of enhance |
invalidateAll() | useRouter().refresh() | after a successful handler call the page's data is read again without a call |
data-sveltekit-reload | reloadDocument on Form, or data-silgi-reload | |
a submitting variable set in the use:enhance callback | useForm(fn).pending, useFormStatus() | useNavigation().state is idle or loading and tells navigations only |
| a Standard Schema validated by hand in the action | defineHandler({ input, handler }) | issues and the typed values come back as a 400 with data: { issues, values }; useForm spreads them on the fields |
request.formData() and a file field | form: { maxFileSize, maxFiles, onFile } | streaming parser, 413 for limits |
Remote functions
| SvelteKit | Silgi | Differences |
|---|---|---|
*.remote.ts, query(schema, fn) | defineHandler({ method: "GET", input, handler }) | a GET handler is cacheable; add cache: { maxAge } |
query.batch | defineHandler({ batch: true, handler(inputs) }) | calls of one tick are one request |
command(schema, fn) | defineHandler({ input, handler }) | a POST; call it from useAction(fn) for pending state and the refresh |
form(schema, fn) | <Form action={fn}> | works without JavaScript: the form posts to the page with ?_fn=<id> |
getRequestEvent() | ctx.event | the handler's second argument |
.refresh() and single-flight mutations | refresh(event, getPost, input) in the handler | the answer carries the value of that read, and the client's next read sends nothing |
prerender(fn) | prerender: true | { inputs } on a GET handler | the static preset writes the answers as files |
| the experimental flag | none | handlers need no flag |
import { x } from "./data.remote" | import { x } from "#server" | the import becomes a stub in the browser; server/index.ts has to export x |