Skip to content
This repository was archived by the owner on Dec 5, 2025. It is now read-only.

Commit 6a325e4

Browse files
authored
Merge pull request #19 from fastify/svelte-support
Svelte support
2 parents fd190d1 + 98c3390 commit 6a325e4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2190
-13
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,23 @@ Try out the [**alpha release** of Fastify DX for Vue](https://github.com/fastify
3939
</table>
4040

4141

42+
<table>
43+
<tr>
44+
<td width="200px" valign="top">
45+
46+
### [fastify-dx-svelte](https://github.com/fastify/fastify-dx/tree/main/packages/fastify-dx-svelte)<br><br>[![NPM version](https://img.shields.io/npm/v/fastify-dx-svelte.svg?style=flat)](https://www.npmjs.com/package/fastify-dx-svelte)
47+
48+
</td>
49+
<td width="500px"><br>
50+
51+
Try out the [**alpha release** of Fastify DX for Svelte](https://github.com/fastify/fastify-dx/blob/main/packages/fastify-dx-svelte/README.md).
52+
53+
</td>
54+
</tr>
55+
</table>
56+
57+
58+
4259
## Status
4360

4461
Fastify DX is currently in **alpha**.

docs/svelte/basic-setup.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<sub>**Go back to the [index](https://github.com/fastify/fastify-dx/blob/main/packages/fastify-dx-svelte/README.md).**</sub>
2+
3+
<br>
4+
5+
## Basic setup
6+
7+
The [starter template](https://github.com/fastify/fastify-dx/tree/dev/starters/svelte) follows [fastify-vite](https://github.com/fastify/fastify-vite)'s convention of having a `client` folder with an `index.js` file, which is automatically resolved as your `clientModule` setting.
8+
9+
If you want flat directory setup, where server and client files are mixed together, you can manually set `clientModule` to something else. Note that in this case you'll also need to update `root` in your `vite.config.js` file.
10+
11+
When deploying to production, bear in mind the `client/dist` directory, generated when you run `npm run build`, needs to be included. You'll also want to enable Fastify's [built-in logging](https://www.fastify.io/docs/latest/Reference/Logging/):
12+
13+
```js
14+
const server = Fastify({ logger: true })
15+
```
16+
17+
The starter template's `server.js` file:
18+
19+
```js
20+
import Fastify from 'fastify'
21+
import FastifyVite from 'fastify-vite'
22+
import FastifyDXSvelte from 'fastify-dx-svelte'
23+
24+
const server = Fastify()
25+
26+
await server.register(FastifyVite, {
27+
root: import.meta.url,
28+
renderer: FastifyDXSvelte,
29+
})
30+
31+
await server.vite.ready()
32+
await server.listen(3000)
33+
```
34+
35+
The starter template's [`vite.config.js`](https://github.com/fastify/fastify-dx/blob/main/starters/svelte/vite.config.js) file:
36+
37+
```js
38+
import { join, dirname } from 'path'
39+
import { fileURLToPath } from 'url'
40+
41+
import { svelte as viteSvelte } from '@sveltejs/vite-plugin-svelte'
42+
import viteSvelteFastifyDX from 'fastify-dx-svelte/plugin'
43+
import unocss from 'unocss/vite'
44+
import { extractorSvelte } from '@unocss/core'
45+
46+
const path = fileURLToPath(import.meta.url)
47+
48+
const root = join(dirname(path), 'client')
49+
const plugins = [
50+
unocss({ extractors: [extractorSvelte] }),
51+
viteSvelte({
52+
compilerOptions: {
53+
hydratable: true,
54+
}
55+
}),
56+
viteSvelteFastifyDX(),
57+
]
58+
59+
export default { root, plugins }
60+
```
61+
62+
Note that you only need to use Fastify DX's Vite plugin, which includes all functionality from [fastify-vite](https://github.com/fastify/fastify-vite)'s Vite plugin.
63+
64+
</td>
65+
</tr>
66+
</table>
67+
68+
### Route exports
69+
70+
Fastify DX picks up exports from route modules to determine route behavior and functionality, as per the [URMA specification](https://github.com/fastify/fastify-dx/blob/main/URMA.md).
71+
72+
To add those exports, you must use `<script context="module">` (Svelte-specific syntax) which determines the script that runs in the general module namespace for a Svelte component. So in Fastify DX Svelte applications, it's commonplace to have two code blocks, a regular one and another with `context` set to `module`:
73+
74+
```html
75+
<script context="module">
76+
export function getData () {
77+
return { message: 'Hello from getData!' }
78+
}
79+
<script>
80+
81+
<script>
82+
import { useRouteContext } = '/dx:core.js'
83+
const { data } = useRouteContext()
84+
</script>
85+
86+
<p>{data.message}</p>
87+
```

docs/svelte/data-prefetching.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<sub>**Go back to the [index](https://github.com/fastify/fastify-dx/blob/main/packages/fastify-dx-svelte/README.md).**</sub>
2+
3+
<br>
4+
5+
## Isomorphic data prefetching
6+
7+
Fastify DX for Svelte implements the `getData()` hook from the [URMA specification](https://github.com/fastify/fastify-dx/blob/main/URMA.md) to solve this problem.
8+
9+
### `getData(ctx)`
10+
11+
This hook is set up in a way that it runs server-side before any SSR takes place, so any data fetched is made available to the route component before it starts rendering. During first render, any data retrieved on the server is automatically sent to be hydrated on the client so no new requests are made. Then, during client-side navigation (post first-render), a JSON request is fired to an endpoint automatically registered for running the `getData()` function for that route on the server.
12+
13+
The objet returned by `getData()` gets automatically assigned as `data` in the [universal route context](https://github.com/fastify/fastify-dx/blob/main/docs/svelte/route-context.md) object and is accessible from `getMeta()` and `onEnter()` hooks and also via the `useRouteContext()` hook.
14+
15+
```html
16+
<script context="module">
17+
export function getData (ctx) {
18+
return {
19+
message: 'Hello from getData!',
20+
}
21+
}
22+
</script>
23+
24+
<script>
25+
import { useRouteContext } from '/dx:core.js'
26+
const { data } = useRouteContext()
27+
</script>
28+
29+
<p>{data.message}</p>
30+
```

docs/svelte/index.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# fastify-dx-svelte [![NPM version](https://img.shields.io/npm/v/fastify-dx-svelte.svg?style=flat)](https://www.npmjs.com/package/fastify-dx-svelte) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/)
2+
3+
- [**Introduction**](https://github.com/fastify/fastify-dx/blob/main/packages/fastify-dx-svelte/README.md#introduction)
4+
- [**Quick Start**](https://github.com/fastify/fastify-dx/blob/main/packages/fastify-dx-svelte/README.md#quick-start)
5+
- [**Package Scripts**](https://github.com/fastify/fastify-dx/blob/main/packages/fastify-dx-svelte/README.md#package-scripts)
6+
- [**Basic Setup**](https://github.com/fastify/fastify-dx/blob/main/docs/svelte/basic-setup.md)
7+
- [**Project Structure**](https://github.com/fastify/fastify-dx/blob/main/docs/svelte/project-structure.md)
8+
- [**Rendering Modes**](https://github.com/fastify/fastify-dx/blob/main/docs/svelte/rendering-modes.md)
9+
- [**Routing Configuration**](https://github.com/fastify/fastify-dx/blob/main/docs/svelte/routing-config.md)
10+
- [**Data Prefetching**](https://github.com/fastify/fastify-dx/blob/main/docs/svelte/data-prefetching.md)
11+
- [**Route Layouts**](https://github.com/fastify/fastify-dx/blob/main/docs/svelte/route-layouts.md)
12+
- [**Route Context**](https://github.com/fastify/fastify-dx/blob/main/docs/svelte/route-context.md)
13+
- [**Route Enter Event**](https://github.com/fastify/fastify-dx/blob/main/docs/svelte/route-enter.md)
14+
- [**Virtual Modules**](https://github.com/fastify/fastify-dx/blob/main/docs/svelte/virtual-modules.md)
15+
16+
## Introduction
17+
18+
**Fastify DX for Svelte** is a renderer adapter for [**fastify-vite**](https://github.com/fastify/fastify-vite).
19+
20+
It lets you run and SSR (server-side render) **Svelte applications built with Vite** on [Fastify](https://fastify.io/), with a minimal and transparent **server-first approach** — everything starts with `server.js`, your actual Fastify server).
21+
22+
It also provides a set of built-in utilities for ease of development and managing a universal JavaScript context (SSR to CSR), very much like **Nuxt.js**, **Next.js** and **Remix**. All **Fastify DX** framework adapters implement the [URMA specification](https://github.com/fastify/fastify-dx/blob/main/URMA.md) and have almost the same API, with only minimal differences due to specific framework APIs or idioms.
23+
24+
It is a **fast**, **lightweight** alternative to Nuxt.js packed with **Developer Experience** features.
25+
26+
It has an extremely small core (~1k LOC total) and is built on top of [Fastify](https://github.com/fastify/fastify), [Vite](https://vitejs.dev/), [Valtio](https://github.com/pmndrs/valtio) and [Svelte Routing](https://github.com/EmilTholin/svelte-routing).
27+
28+
[**See the release notes for the 0.0.1 alpha release**](https://github.com/fastify/fastify-dx/releases/tag/svelte-v0.0.1).
29+
30+
> At this stage this project is mostly a [**one-man show**](https://github.com/sponsors/galvez), who's devoting all his free time to its completion. Contributions are extremely welcome, as well as bug reports for any issues you may find.
31+
32+
In this first alpha release it's still missing a test suite. The same is true for [**fastify-vite**](https://github.com/fastify/fastify-vite).
33+
34+
It'll move into **beta** status when test suites are added to both packages.
35+
36+
## Quick Start
37+
38+
Ensure you have **Node v16+**.
39+
40+
Make a copy of [**starters/svelte**](https://github.com/fastify/fastify-dx/tree/dev/starters/svelte). If you have [`degit`](https://github.com/Rich-Harris/degit), run the following from a new directory:
41+
42+
```bash
43+
degit fastify/fastify-dx/starters/svelte
44+
```
45+
46+
> **If you're starting a project from scratch**, you'll need these packages installed.
47+
>
48+
> ```bash
49+
> npm i fastify fastify-vite fastify-dx-svelte -P
50+
> npm i @sveltejs/vite-plugin-svelte -D
51+
> ```
52+
53+
54+
Run `npm install`.
55+
56+
Run `npm run dev`.
57+
58+
Visit `http://localhost:3000/`.
59+
60+
## What's Included
61+
62+
That will get you a **starter template** with:
63+
64+
- A minimal [Fastify](https://github.com/fastify/fastify) server.
65+
- Some dummy API routes.
66+
- A `pages/` folder with some [demo routes](https://github.com/fastify/fastify-dx/tree/dev/starters/svelte/client/pages).
67+
- All configuration files.
68+
69+
It also includes some _**opinionated**_ essentials:
70+
71+
- [**PostCSS Preset Env**](https://www.npmjs.com/package/postcss-preset-env) by [**Jonathan Neal**](https://github.com/jonathantneal), which enables [several modern CSS features](https://preset-env.cssdb.org/), such as [**CSS Nesting**](https://www.w3.org/TR/css-nesting-1/).
72+
73+
- [**UnoCSS**](https://github.com/unocss/unocss) by [**Anthony Fu**](https://antfu.me/), which supports all [Tailwind utilities](https://uno.antfu.me/) and many other goodies through its [default preset](https://github.com/unocss/unocss/tree/main/packages/preset-uno).
74+
75+
- [**Valtio**](https://github.com/pmndrs/valtio) by [**Daishi Kato**](https://blog.axlight.com/), with a global and SSR-ready store which you can use anywhere. <br>Svelte support is provided via [Sveltio](https://github.com/wobsoriano/sveltio) by [Robert Soriano](https://robsoriano.com/).
76+
77+
78+
## Package Scripts
79+
80+
`npm run dev` boots the development server.
81+
82+
`npm run build` creates the production bundle.
83+
84+
`npm run serve` serves the production bundle.
85+
86+
## Meta
87+
88+
Created by [Jonas Galvez](https://github.com/sponsors/galvez), **Engineering Manager** and **Open Sourcerer** at [NearForm](https://nearform.com).
89+
90+
## Sponsors
91+
92+
<a href="https://nearform.com"><img width="200px" src="https://user-images.githubusercontent.com/12291/172310344-594669fd-da4c-466b-a250-a898569dfea3.svg"></a>
93+
94+
Also [**Duc-Thien Bui**](https://github.com/aecea) and [**Tom Preston-Werner**](https://github.com/mojombo) [via GitHub Sponsors](https://github.com/sponsors/galvez). _Thank you!_

docs/svelte/meta-tags.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<sub>**Go back to the [index](https://github.com/fastify/fastify-dx/blob/main/packages/fastify-dx-svelte/README.md).**</sub>
2+
3+
<br>
4+
5+
## Meta Tags
6+
7+
Following the [URMA specification](https://github.com/fastify/fastify-dx/blob/main/URMA.md), Fastify DX renders `<head>` elements independently from the SSR phase. This allows you to fetch data for populating the first `<meta>` tags and stream them right away to the client, and only then perform SSR.
8+
9+
> Additional `<link>` preload tags can be produced from the SSR phase. This is **not currently implemented** in this **alpha release** but is a planned feature. If you can't wait for it, you can roll out your own (and perhaps contribute your solution) by providing your own [`createHtmlFunction()`](https://github.com/fastify/fastify-dx/blob/main/packages/fastify-dx-svelte/index.js#L57) to [fastify-vite](https://github.com/fastify/fastify-vite).
10+
11+
### `getMeta()`
12+
13+
To populate `<title>`, `<meta>` and `<link>` elements, export a `getMeta()` function that returns an object matching the format expected by [unihead](https://github.com/galvez/unihead), the underlying library used by Fastify DX.
14+
15+
It receives the [route context](https://github.com/fastify/fastify-dx/blob/main/packages/fastify-dx-svelte/README.md#route-context) as first parameter and runs after `getData()`, allowing you to access any `data` populated by these other functions to generate your tags.
16+
17+
```html
18+
<script context="module">
19+
export function getMeta (ctx) {
20+
return {
21+
title: 'Route Title',
22+
meta: [
23+
{ name: 'twitter:title', value: 'Route Title' },
24+
]
25+
}
26+
}
27+
</script>
28+
29+
<p>Route with meta tags.</p>
30+
```

docs/svelte/project-structure.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<sub>**Go back to the [index](https://github.com/fastify/fastify-dx/blob/main/packages/fastify-dx-svelte/README.md).**</sub>
2+
3+
<br>
4+
5+
## Project Structure
6+
7+
The [starter template](https://github.com/fastify/fastify-dx/tree/dev/starters/svelte) looks like this:
8+
9+
```
10+
├── server.js
11+
├── client/
12+
│ ├── index.js
13+
│ ├── context.js
14+
│ ├── root.svelte
15+
│ ├── index.html
16+
│ ├── layouts/
17+
│ │ ├── default.svelte
18+
│ │ └── auth.svelte
19+
│ └── pages/
20+
│ ├── index.svelte
21+
│ ├── client-only.svelte
22+
│ ├── server-only.svelte
23+
│ ├── using-data.svelte
24+
│ └── using-store.svelte
25+
├── vite.config.js
26+
└── package.json
27+
```
28+
29+
Several internal files are provided as virtual modules by Fastify DX. They are located inside the `fastify-dx-svelte` package in `node_modules`, and dynamically loaded so you don't have to worry about them unless you want them overriden.
30+
31+
In this case, placing a file with the same name as the registered virtual module in your Vite project root will override it. Find the detailed rundown of all virtual modules [here][virtual-modules].
32+
33+
[virtual-modules]: https://github.com/fastify/fastify-dx/blob/main/docs/svelte/virtual-modules.md
34+
35+
The `server.js` file is your application entry point. It's the file that runs everything. It boots a Fastify server configured with [**fastify-vite**](https://github.com/fastify/fastify-vite) and **Fastify DX for Svelte** as a renderer adapter to **fastify-vite**.
36+
37+
The `client/index.js` file is your Vite server entry point, it's the file that provides your client bundle (which runs in the Vite-enriched environment) to the Node.js environment where Fastify runs.
38+
39+
> Right now, it's mostly a **boilerplate file** because it must exist but it will also probably never need to be changed.
40+
41+
It exports your application's factory function (must be named `create`), the application routes (must be named `routes`) and the universal route context [initialization module](https://github.com/fastify/fastify-dx/blob/main/docs/svelte/route-context.md#initialization-module) (must be named `context` and have a dynamic module import so Fastify DX can pick up `default` and named exports).
42+
43+
The `client/index.html` file is the [root HTML template of the application](https://vitejs.dev/guide/#index-html-and-project-root), which Vite uses as the client bundling entry point.
44+
45+
> You can expand this file with additional `<meta>` and `<link>` tags if you wish, provided you don't remove any of the placeholders.
46+
47+
This files links to `/dx:mount.js`, which is a virtual module provided by Fastify DX.
48+
49+
Virtual modules are covered [here][virtual-modules].
50+
51+
The `client/pages/` directory contains your route modules, whose paths are dynamically inferred from the directory structure itself. You can change this behavior easily. More on this [here][routing-config].
52+
53+
[routing-config]: https://github.com/fastify/fastify-dx/blob/main/docs/svelte/routing-config.md
54+
55+
The `client/layouts/` directory contains your route layout modules, which can be associated to any route. By default, `layouts/default.svelte` is used, but if you don't need to do any modifications on that file, you can safely removed as it's provided by Fastify DX in that case. The starter template also comes with `layouts/auth.svelte`, to demonstrate a more advanced use of layouts.
56+
57+
[routing-config]: https://github.com/fastify/fastify-dx/blob/main/docs/svelte/routing-config.md
58+
59+
The `client/context.js` file is the universal [route context][route-context] initialization module. Any named exports from this file are attached to the `RouteContext` class prototype on the server, preventing them from being reassigned on every request. The `default` export from this file, however, runs for every request so you can attach any request-specific data to it.
60+
61+
[route-context]: https://github.com/fastify/fastify-dx/blob/main/docs/svelte/route-context.md

docs/svelte/rendering-modes.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<sub>**Go back to the [index](https://github.com/fastify/fastify-dx/blob/main/packages/fastify-dx-svelte/README.md).**</sub>
2+
3+
<br>
4+
5+
# Rendering modes
6+
7+
Following the [URMA specification](https://github.com/fastify/fastify-dx/blob/main/URMA.md), Fastify DX's route modules can be set for universal rendering (SSR + CSR hydration, the default behavior), SSR in streaming mode, SSR only (client gets no JavaScript) or CSR only (SSR fully disabled). Fastify DX for Svelte supports all of these modes minus streaming, which is currently not yet supported by Svelte itself.
8+
9+
## `serverOnly`
10+
11+
If a route module exports `serverOnly` set to `true`, only SSR will take place. The client gets the server-side rendered markup without any accompanying JavaScript or data hydration.
12+
13+
You should use this setting to deliver lighter pages when there's no need to run any code on them, such as statically generated content sites.
14+
15+
```html
16+
<script context="module">
17+
export const serverOnly = true
18+
</script>
19+
20+
<p>This route is rendered on the server only!</p>
21+
```
22+
23+
[This example](https://github.com/fastify/fastify-dx/blob/main/starters/svelte/client/pages/server-only.svelte) is part of the [starter template](https://github.com/fastify/fastify-dx/tree/dev/starters/svelte).
24+
25+
## `clientOnly`
26+
27+
If a route module exports `clientOnly` set to `true`, no SSR will take place, only data fetching and data hydration. The client gets the empty container element (the one that wraps `<!-- element -->` in `index.html`) and all rendering takes place on the client only.
28+
29+
You can use this setting to save server resources on internal pages where SSR makes no significant diference for search engines or UX in general, such as a password-protected admin section.
30+
31+
```html
32+
<script context="module">
33+
export const clientOnly = true
34+
</script>
35+
36+
<p>This route is rendered on the client only!</p>
37+
```
38+
39+
[This example](https://github.com/fastify/fastify-dx/blob/main/starters/svelte/client/pages/client-only.svelte) is part of the [starter template](https://github.com/fastify/fastify-dx/tree/dev/starters/svelte).

0 commit comments

Comments
 (0)