From 767a00b14730c0adf0dee8967d8b91a3137e4d22 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 14 Mar 2021 12:57:26 -0400 Subject: [PATCH 01/14] update docs --- documentation/docs/01-routing.md | 136 +++++++++++++++++ documentation/docs/01-structure.md | 82 ---------- .../docs/{05-layouts.md => 02-layouts.md} | 37 ++--- documentation/docs/02-routing.md | 141 ------------------ documentation/docs/03-loading.md | 123 +++++++++++++++ .../{03-client-api.md => 04-client-api.md} | 0 documentation/docs/04-loading.md | 132 ---------------- 7 files changed, 274 insertions(+), 377 deletions(-) create mode 100644 documentation/docs/01-routing.md delete mode 100644 documentation/docs/01-structure.md rename documentation/docs/{05-layouts.md => 02-layouts.md} (78%) delete mode 100644 documentation/docs/02-routing.md create mode 100644 documentation/docs/03-loading.md rename documentation/docs/{03-client-api.md => 04-client-api.md} (100%) delete mode 100644 documentation/docs/04-loading.md diff --git a/documentation/docs/01-routing.md b/documentation/docs/01-routing.md new file mode 100644 index 000000000000..5b27e4266dd9 --- /dev/null +++ b/documentation/docs/01-routing.md @@ -0,0 +1,136 @@ +--- +title: Routing +--- + +At the heart of SvelteKit is a *filesystem-based router*. This means that the structure of your application is defined by the structure of your codebase — specifically, the contents of `src/routes`. + +> You can change this to a different directory by editing the [project config](#Project-configuration). + +There are two types of route — **pages** and **endpoints**. + +### Pages + +Pages are Svelte components written in `.svelte` files (or any file with an extension listed in [`config.extensions`](#Project-configuration)). When a user first visits the application, they will be served a server-rendered version of the page in question, plus some JavaScript that 'hydrates' the page and initialises a client-side router. From that point forward, navigating to other pages is handled entirely on the client for a fast, app-like feel. + +The filename determines the route. For example, `src/routes/index.svelte` is the root of your site: + +```html + + + Welcome + + +

Hello and welcome to my site!

+``` + +A file called either `src/routes/about.svelte` or `src/routes/about/index.svelte` would correspond to the `/about` route: + +```html + + + About + + +

About this site

+

TODO...

+``` + +Dynamic parameters are encoded using `[brackets]`. For example, a blog post might be defined by `src/routes/blog/[slug].svelte`. Soon, we'll see how to access that parameter in a [load function](#Loading) or the [page store](#TODO). + +### Endpoints + +Endpoints are modules written in `.js` (or `.ts`) files that export functions corresponding to HTTP methods. Each function receives HTTP `request` and `context` objects as arguments. This is useful for creating a JSON API. For example our hypothetical blog page, `/blog/cool-article`, might request data from `/blog/cool-article.json`, which could be represented by a `src/routes/blog/[slug].json.js` endpoint: + +```js +import db from '$lib/database'; + +/** + * @param {{ + * host: string; + * method: 'GET'; + * headers: Record; + * path: string; + * body: any; + * query: URLSearchParams; + * }} request + * @param {any} context + * @returns {{ + * status?: number; + * headers?: Record; + * body: any; + * }} + */ +export async function get(request, context) { + // the `slug` parameter is available because this file + // is called [slug].json.js + const { slug } = request.params; + + const article = await db.get(slug); + + if (article !== null) { + return { + body: { + article + } + }; + } else { + return { + status: 404, + body: { + error: 'Not found' + } + }; + } +} +``` + +Because this module only runs on the server (or when you build your site, if [prerendering](#Prerendering)), you can freely access things like databases. (Don't worry about `$lib`, we'll get to that [later](#$lib).) + +The second argument, `context`, is something you define during [setup](#Setup), if necessary. + +The job of this function is to return a `{status, headers, body}` object representing the response. If the returned `body` is an object, and no `content-type` header is returned, it will automatically be turned into a JSON response. + +> We don't interact with the `req`/`res` objects you might be familiar with from Node's `http` module or frameworks like Express, because they're only available on certain platforms. Instead, SvelteKit translates the returned object into whatever's required by the platform you're deploying your app to. + +For endpoints that handle other HTTP methods, like POST, export the corresponding function: + +```js +export function post(request, context) {...} +``` + +Since `delete` is a reserved word in JavaScript, DELETE requests are handled with a `del` function. + + +### Private modules + +A filename that has a segment with a leading underscore, such as `src/routes/foo/_Private.svelte` or `src/routes/bar/_utils/cool-util.js`, is hidden from the router, but can be imported by files that are not. + + +### Advanced + +A route can have multiple dynamic parameters, for example `src/routes/[category]/[item].svelte` or even `src/routes/[category]-[item].svelte`. If the number of route segments is unknown, you can use rest syntax — for example you might implement GitHub's file viewer like so... + +```bash +/[org]/[repo]/tree/[branch]/[...file] +``` + +...in which case a request for `/sveltejs/kit/tree/master/documentation/docs/01-routing.md` would result in the following parameters being available to the page: + +```js +{ + org: 'sveltejs', + repo: 'kit', + branch: 'master', + file: ['documentation', 'docs', '01-routing.md'] +} +``` + +Finally, you can use a subset of regular expression syntax to control whether routes match or not: + +```bash +# matches /2021/04/25 but not /a/b/c or /1/2/3 +src/routes/[year(\d{4})]/[month(\d{2})]/[day(\d{2})].svelte +``` + +Because of technical limitations, the following characters cannot be used: `/`, `\`, `?`, `:`, `(` and `)`. + diff --git a/documentation/docs/01-structure.md b/documentation/docs/01-structure.md deleted file mode 100644 index 55b019bfabba..000000000000 --- a/documentation/docs/01-structure.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -title: SvelteKit app structure ---- - -If you take a look inside a new SvelteKit project, you'll see some files that SvelteKit expects to find: - -```bash -├ package.json -├ src -│ ├ routes -│ │ └ index.svelte -│ ├ components -│ │ └ Counter.svelte -│ ├ service-worker.js -│ └ app.html -├ static -│ ├ # your files here -├ svelte.config.cjs -└ vite.config.js -``` - -### package.json - -Your package.json contains your app's dependencies and defines a number of scripts: - -- `npm run dev` — start the app in development mode, and watch source files for changes -- `npm run build` — build the app in production mode -- `npm start` — start the app in production mode after you've built it - -### src - -This contains the _home page_ for your app — `src/index.svelte` and (optionally) `src/service-worker.js` — along with a `src/app.html` file. - -#### src/routes/index.svelte - -This is the home page for your application and is just like any other Svelte component. - -#### src/service-worker.js - -_Currently not implemented._ - -Service workers act as proxy servers that give you fine-grained control over how to respond to network requests. For example, when the browser requests `/goats.jpg`, the service worker can respond with a file it previously cached, or it can pass the request on to the server, or it could even respond with something completely different, such as a picture of llamas. - -Among other things, this makes it possible to build applications that work offline. - -Because every app needs a slightly different service worker (sometimes it's appropriate to always serve from the cache, sometimes that should only be a last resort in case of no connectivity), Sapper doesn't attempt to control the service worker. Instead, you write the logic in `service-worker.js`. You can import any of the following from `@sapper/service-worker`: - -- `files` — an array of files found in the `static` directory -- `shell` — the client-side JavaScript generated by the bundler (Rollup or webpack) -- `routes` — an array of `{ pattern: RegExp }` objects you can use to determine whether a Sapper-controlled page is being requested -- `timestamp` — the time the service worker was generated (useful for generating unique cache names) - -#### src/app.html - -This file is a template for responses from the server. Sapper will inject content that replaces the following tags: - -- `%svelte.base%` — a `` element (see [base URLs](docs#Base_URLs)) -- `%svelte.styles%` — critical CSS for the page being requested -- `%svelte.head%` — HTML representing page-specific `` contents, like `` -- `%svelte.html%` — HTML representing the body of the page being rendered -- `%svelte.scripts%` — script tags for the client-side app -- `%svelte.cspnonce%` — CSP nonce taken from `res.locals.nonce` (see [Content Security Policy (CSP)](docs#Content_Security_Policy_CSP)) - -### src/routes - -This is the meat of your app — the pages and server routes. See the section on [routing](docs#Routing) for the juicy details. - -### static - -This is a place to put any files that your app uses — fonts, images and so on. For example `static/favicon.png` will be served as `/favicon.png`. - -Sapper doesn't serve these files — you'd typically use [sirv](https://github.com/lukeed/sirv) or [serve-static](https://github.com/expressjs/serve-static) for that — but it will read the contents of the `static` folder so that you can easily generate a cache manifest for offline support (see [service-worker.js](docs#src_service-worker_js)). - -> Note that the default behaviour of the service worker is to cache all assets from the static directory, so if you have more than 50mb of files here, you will start to exceed the cache limit for service-workers in some browsers, which can cause the service worker to stop loading. In this instance, it is advisable to customise what files are cached by editing the service-worker yourself. - -### svelte.config.cjs - -This file contains SvelteKit options as well as options for `svelte-preprocess`. - -### vite.config.js - -This is the [Vite configuration file](https://vitejs.dev/config/) for your project. diff --git a/documentation/docs/05-layouts.md b/documentation/docs/02-layouts.md similarity index 78% rename from documentation/docs/05-layouts.md rename to documentation/docs/02-layouts.md index d7840b42e7b0..36a06a7bd0e3 100644 --- a/documentation/docs/05-layouts.md +++ b/documentation/docs/02-layouts.md @@ -44,7 +44,7 @@ If we create pages for `/`, `/about` and `/settings`... ...the nav will always be visible, and clicking between the three pages will only result in the `<h1>` being replaced. -### Nested routes +### Nested layouts Suppose we don't just have a single `/settings` page, but instead have nested pages like `/settings/profile` and `/settings/notifications` with a shared submenu (for a real-life example, see [github.com/settings](https://github.com/settings)). @@ -62,24 +62,17 @@ We can create a layout that only applies to pages below `/settings` (while inher <slot></slot> ``` -The `page` store from `$app/stores` can be useful for styling: - -```diff -+<script> -+ import { page } from '$app/stores'; -+</script> -+ - <div class="submenu"> -- <a href="/settings/profile">Profile</a> -- <a href="/settings/notifications">Notifications</a> -+ <a -+ class:selected={$page.path === "/settings/profile"} -+ href="/settings/profile" -+ >Profile</a> -+ -+ <a -+ class:selected={$page.path === "/settings/notifications"} -+ href="/settings/notifications" -+ >Notifications</a> - </div> -``` + +### Error pages + +If your page fails to load (see [Loading](#loading)), SvelteKit will render an error page. You can customise this page by creating a file called `src/routes/$error.svelte`, which is a component that receives an `error` prop alongside a `status` code: + +```html +<script> + export let status; + export let error; +</script> + +<h1>{status}</h1> +<p>{error.message}</p> +``` \ No newline at end of file diff --git a/documentation/docs/02-routing.md b/documentation/docs/02-routing.md deleted file mode 100644 index 1f61957b1b7f..000000000000 --- a/documentation/docs/02-routing.md +++ /dev/null @@ -1,141 +0,0 @@ ---- -title: Routing ---- - -As we've seen, there are two types of route in SvelteKit — pages and API endpoints. - -### Pages - -Pages are Svelte components written in `.svelte` files. When a user first visits the application, they will be served a server-rendered version of the route in question, plus some JavaScript that 'hydrates' the page and initialises a client-side router. From that point forward, navigating to other pages is handled entirely on the client for a fast, app-like feel. - -The filename determines the route. For example, `src/routes/index.svelte` is the root of your site: - -```html -<!-- src/routes/index.svelte --> -<svelte:head> - <title>Welcome - - -

Hello and welcome to my site!

-``` - -A file called either `src/routes/about.svelte` or `src/routes/about/index.svelte` would correspond to the `/about` route: - -```html - - - About - - -

About this site

-

TODO...

-``` - -Dynamic parameters are encoded using `[brackets]`. For example, here's how you could create a page that renders a blog post: - -```html - - - - - - - {article.title} - - -

{article.title}

- -
{@html article.html}
-``` - -If you want to capture more params, you can create nested folders using the same naming convention: `[slug]/[language]`. - -If you don't want to create several folders to capture more than one parameter like `[year]/[month]/...`, or if the number of parameters is dynamic, you can use a spread route parameter. For example, instead of individually capturing `/blog/[slug]/[year]/[month]/[day]`, you can create a file for `/blog/[...slug].svelte` and extract the params like so: - -```html - - -``` - -> See the section on [loading](docs#Loading) for more info about `load` and `fetch` - -### Server routes - -Server routes are modules written in `.js` or `.ts` files that export functions corresponding to HTTP methods. Each function receives HTTP `request` and `context` objects as arguments. This is useful for creating a JSON API. For example, here's how you could create an endpoint that served the blog page above: - -```js -// routes/blog/[slug].json.js -import db from './_database.js'; // the underscore tells SvelteKit this isn't a route - -export async function get(req, context) { - // the `slug` parameter is available because this file - // is called [slug].json.js - const { slug } = req.params; - - const article = await db.get(slug); - - if (article !== null) { - return { - body: { - article - } - }; - } else { - return { - status: 404, - body: { - error: 'Not found' - } - }; - } -} -``` - -> `delete` is a reserved word in JavaScript. To handle DELETE requests, export a function called `del` instead. - -### File naming rules - -There are three simple rules for naming the files that define your routes: - -- A file called `src/routes/about.svelte` corresponds to the `/about` route. A file called `src/routes/blog/[slug].svelte` corresponds to the `/blog/:slug` route, in which case `params.slug` is available to `load` -- The file `src/routes/index.svelte` corresponds to the root of your app. `src/routes/about/index.svelte` is treated the same as `src/routes/about.svelte`. -- Files and directories with a leading underscore do _not_ create routes. This allows you to colocate helper modules and components with the routes that depend on them — for example you could have a file called `src/routes/_helpers/datetime.js` and it would _not_ create a `/_helpers/datetime` route - -### Error page - -In addition to regular pages, there is a 'special' page that SvelteKit expects to find — `src/routes/$error.svelte`. This will be shown when an error occurs while rendering a page. - -The `error` object is made available to the template along with the HTTP `status` code. `error` is also available in the [`page` store](docs#Stores). - -### Regexes in routes - -You can use a subset of regular expressions to qualify route parameters, by placing them in parentheses after the parameter name. - -For example, `src/routes/items/[id([0-9]+)].svelte` would only match numeric IDs — `/items/123` would match and make the value `123` available in `page.params.id`, but `/items/xyz` would not match. - -Because of technical limitations, the following characters cannot be used: `/`, `\`, `?`, `:`, `(` and `)`. diff --git a/documentation/docs/03-loading.md b/documentation/docs/03-loading.md new file mode 100644 index 000000000000..ad8bc4a4eabc --- /dev/null +++ b/documentation/docs/03-loading.md @@ -0,0 +1,123 @@ +--- +title: Loading +--- + +A component that defines a page can export a `load` function that runs before the component is created. This function runs both during server-side rendering and in the client, and allows you to get data for a page without (for example) showing a loading spinner and fetching data in `onMount`. + +Our example blog page might contain a `load` function like this: + +```html + +``` + +`load` is the SvelteKit equivalent of `getStaticProps` or `getServerSideProps` in Next.js or `asyncData` in Nuxt.js. + +Note the `context="module"` — this is necessary because `load` runs before the component is rendered. + +> `load` only applies to components that define pages, not the components that they import. + +### Input + +The `load` function receives an object containing four fields — `page`, `fetch`, `session` and `context`. + +#### input.page + +`page` is a `{ host, path, params, query }` object where `host` is the URL's host, `path` is its pathname, `params` is derived from `path` and the route filename, and `query` is an instance of `URLSearchParams`. + +So if the example above was `src/routes/blog/[slug].svelte` and the URL was `/blog/some-post?foo=bar&baz`, the following would be true: + +- `page.path === '/blog/some-post'` +- `page.params.slug === 'some-post'` +- `page.query.get('foo') === 'bar'` +- `page.query.has('baz')` + +#### input.fetch + +`fetch` is equivalent to the native `fetch` web API, and can make credentialled requests. It can be used across both client and server contexts. + +> When `fetch` runs on the server, the resulting response will be serialized and inlined into the rendered HTML. This allows the subsequent client-side `load` to access identical data immediately without an additional network request. + +#### input.session + +`session` can be used to pass data from the server related to the current request, e.g. the current user. By default it is `undefined`. [Seeding session data](#Seeding_session_data) describes how to add data to it. + +#### input.context + +`context` is passed from layout components to child layouts and page components. For the root `$layout.svelte` component, it is equal to `{}`, but if that component's `load` function returns an object with a `context` property, it will be available to subsequent `load` functions. + +> It is important to note that `load` may run on either the server or in the client browser. Code called inside `load` blocks: +> +> - should run on the same domain as any upstream API servers requiring credentials +> - should not reference `window`, `document` or any browser-specific objects +> - should not reference any API keys or secrets, which will be exposed to the client + +### Output + +If you return a Promise from `load`, the SvelteKit will delay rendering until the promise resolves. The return value has several properties, all optional: + +#### output.status + +The HTTP status code for the page. If returning an `error` this must be a `4xx` or `5xx` response; if returning a `redirect` it must be a `3xx` response. The default is `200`. + +#### output.error + +If something goes wrong during `load`, return an `Error` object or a `string` describing the error alongside a `4xx` or `5xx` status code. + +#### output.redirect + +If the page should redirect (because the page is deprecated, or the user needs to be logged in, or whatever else) return a `string` containing the location to which they should be redirected alongside a `3xx` status code. + +#### output.maxage + +To cause pages to be cached, return a `number` describing the page's max age in seconds. The resulting cache header will include `private` if user data was involved in rendering the page (either via `session`, or because a credentialled `fetch` was made in a `load` function), but otherwise will include `public` so that it can be cached by CDNs. + +This only applies to page components, _not_ layout components. + +#### output.props + +If the `load` function returns a `props` object, the props will be passed to the component when it is rendered. + +#### output.context + +This will be merged with any existing `context` and passed to the `load` functions of subsequent layout and page components. + +This only applies to layout components, _not_ page components. \ No newline at end of file diff --git a/documentation/docs/03-client-api.md b/documentation/docs/04-client-api.md similarity index 100% rename from documentation/docs/03-client-api.md rename to documentation/docs/04-client-api.md diff --git a/documentation/docs/04-loading.md b/documentation/docs/04-loading.md deleted file mode 100644 index e623f15b4a9e..000000000000 --- a/documentation/docs/04-loading.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: Loading ---- - -Page components can define a `load` function that runs before the component is created. The values it returns are passed as props to the page. - -`load` functions are called when a page is loaded and are typically used to load data that the page depends on - hence its name. This avoids the user seeing the page update as it loads, as is typically the case with client-side loading. - -`load` is the SvelteKit equivalent to `getInitialProps` in Next.js or `asyncData` in Nuxt.js. - -Note that `load` will run both on the server side and on the client side. It therefore should not reference any APIs only present in the browser. - -The following code shows how to load a blog post and pass it to the page in the `article` prop: - -```html - - - - -

{article.title}

-``` - -The [routing section](docs#Routing) describes how the dynamic parameter `slug` works. - -It should be defined in a `context="module"` script since it is not part of the component instance itself – it runs before the component has been created. See the [tutorial](https://svelte.dev/tutorial/module-exports) for more on the module context. - -### Arguments - -The `load` function receives an object containing four fields — `fetch`, `page`, `context`, and `session`. - -`fetch` is equivalent to the native `fetch` web API, and can make credentialled requests. It can be used across both client and server contexts. - -`page` is a `{ host, path, params, query }` object where `host` is the URL's host, `path` is its pathname, `params` is derived from `path` and the route filename, and `query` is an instance of `URLSearchParams`. - -So if the example above was `src/routes/blog/[slug].svelte` and the URL was `/blog/some-post?foo=bar&baz`, the following would be true: - -- `page.path === '/blog/some-post'` -- `page.params.slug === 'some-post'` -- `page.query.get('foo') === 'bar'` -- `page.query.has('baz')` - -`context` is passed from layout components to child layouts and page components. For the root `$layout.svelte` component, it is equal to `{}`, but if that component's `load` function returns an object with a `context` property, it will be available to subsequent `load` functions. - -`session` can be used to pass data from the server related to the current request, e.g. the current user. By default it is `undefined`. [Seeding session data](docs#Seeding_session_data) describes how to add data to it. - -#### api - -In browsers, you can use `fetch` to make AJAX requests, for getting data from your server routes (among other things). On the server it's a little trickier — you can make HTTP requests, but you must specify an origin, and you don't have access to cookies. This means that it's impossible to request data based on the user's session, such as data that requires you to be logged in. - -To fix this, SvelteKit provides a `fetch` method to the `load` function, which work on the server as well as in the client: - -```html - -``` - -It is important to note that `load` may run on either the server or in the client browser. Code called inside `load` blocks: - -- should run on the same domain as any upstream API servers requiring credentials -- should not reference `window`, `document` or any browser-specific objects -- should not reference any API keys or secrets, which will be exposed to the client - -### Return values - -If you return a Promise from `load`, the page will delay rendering until the promise resolves. You can also return a plain object. In both cases, the values in the object will be passed into the components as props. - -When SvelteKit renders a page on the server, it will attempt to serialize the resolved value (using [devalue](https://github.com/Rich-Harris/devalue)) and include it on the page, so that the client doesn't also need to call `preload` upon initialization. Serialization will fail if the value includes functions or custom classes (cyclical and repeated references are fine, as are built-ins like `Date`, `Map`, `Set` and `RegExp`). - -#### error - -If the user navigated to `/blog/some-invalid-slug`, we would want to render a 404 Not Found page. We can do that by returning a status code and an error instance: - -```html - -``` - -The same applies to other error codes you might encounter. - -#### redirect - -You can abort rendering and redirect to a different location by returning a 3xx status code and a `redirect` path: - -```html - -``` From 7694a920a7f82443c026492741ca7e6624f47495 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 14 Mar 2021 13:42:40 -0400 Subject: [PATCH 02/14] more docs --- documentation/docs/04-setup.md | 104 ++++++++++++++++++ .../docs/06-server-side-rendering.md | 42 ------- documentation/docs/14-debugging.md | 19 ---- documentation/docs/99-troubleshooting.md | 34 ++++++ 4 files changed, 138 insertions(+), 61 deletions(-) create mode 100644 documentation/docs/04-setup.md delete mode 100644 documentation/docs/06-server-side-rendering.md delete mode 100644 documentation/docs/14-debugging.md create mode 100644 documentation/docs/99-troubleshooting.md diff --git a/documentation/docs/04-setup.md b/documentation/docs/04-setup.md new file mode 100644 index 000000000000..d6d8fd354ce1 --- /dev/null +++ b/documentation/docs/04-setup.md @@ -0,0 +1,104 @@ +--- +title: Setup +--- + +An optional `src/setup.js` (or `src/setup.ts`, or `src/setup/index.js`) file exports two functions that run on the server — **prepare** and **getSession**. + +Both functions, if provided, run for every page or endpoint request SvelteKit receives. + +> The location of this file can be [configured](#configuration) as `config.kit.files.setup` + +### prepare + +This function receives the incoming headers and can return `context` and outgoing `headers`: + +```js +/** + * @param {{ + * headers: Record + * }} incoming + * @returns {Promise<{ + * headers?: Record + * context?: any + * }>} + */ +export async function prepare({ headers }) { + return { + headers: {...}, + context: {...} + }; +} +``` + +The outgoing `headers` will be added to the response alongside any headers returned from individual endpoints. This is useful for setting cookies, for example: + +```js +import * as cookie from 'cookie'; +import { v4 as uuid } from '@lukeed/uuid'; + +export async function prepare(incoming) { + const cookies = cookie.parse(incoming.headers.cookie || ''); + + const headers = {}; + if (!cookies.session_id) { + headers['set-cookie'] = `session_id=${uuid()}; HttpOnly`; + } + + return { + headers + }; +} +``` + +The `context` is passed to endpoints, and is used by `getSession` to derive a session object which is available in the browser. It's a good place to store information about the current user, for example. + +```diff +import * as cookie from 'cookie'; +import { v4 as uuid } from '@lukeed/uuid'; ++import db from '$lib/db'; + +export async function prepare(incoming) { + const cookies = cookie.parse(incoming.headers.cookie || ''); + + const headers = {}; + if (!cookies.session_id) { + headers['set-cookie'] = `session_id=${uuid()}; HttpOnly`; + } + + return { +- headers ++ headers, ++ context: { ++ user: await db.get_user(cookies.session_id) ++ } + }; +} +``` + + +### getSession + +This function takes the `context` returned from `prepare` and returns a `session` object that is safe to expose to the browser. + +```js +/** + * @param {{ + * context: any + * }} options + * @returns {any} + */ +export function getSession({ context }) { + return { + user: { + // only include properties needed client-side — + // exclude anything else attached to the user + // like access tokens etc + name: context.user?.name, + email: context.user?.email, + avatar: context.user?.avatar + } + }; +} +``` + +> `session` must be serializable, which means it must not contain things like functions or custom classes, just built-in JavaScript data types \ No newline at end of file diff --git a/documentation/docs/06-server-side-rendering.md b/documentation/docs/06-server-side-rendering.md deleted file mode 100644 index 2c65fccd4d38..000000000000 --- a/documentation/docs/06-server-side-rendering.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Server-side rendering ---- - -SvelteKit will render any component first on the server side and send it to the client as HTML. It will then run the component again on the client side to allow it to update based on dynamic data. This means you need to ensure that components can run both on the client and server side. - -If, for example, your components try to access the global variables `document` or `window`, this will result in an error when the page is pre-rendered on the server side. - -If you need access to these variables, you can run code exclusively on the client side by wrapping it in - -```js -if (typeof window !== 'undefined') { - // client-only code here -} -``` - -Alternatively, you can run it `onMount` (see below). - -### Third-party libraries that depend on `window` - -SvelteKit works well with most third-party libraries you are likely to come across. However, sometimes libraries have implicit dependencies on `window`. - -A third-party library might come bundled in a way which allows it to work with multiple different module loaders. This code might check for the existence of `window.global` and therefore depend on `window`. - -Since SvelteKit will try to execute your component on the server side – where there is no `window` – importing such a module will cause the component to fail. You will get an error message saying `Server-side code is attempting to access the global variable "window"`. - -To solve this, you can load the library by importing it in the `onMount` function, which is only called on the client. Since this is a dynamic import you need to use `await import`. - -```html - - - -``` diff --git a/documentation/docs/14-debugging.md b/documentation/docs/14-debugging.md deleted file mode 100644 index 3e883ed7364f..000000000000 --- a/documentation/docs/14-debugging.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: Debugging ---- - -Debugging your server code is particularly easy with [ndb](https://github.com/GoogleChromeLabs/ndb). Install it globally... - -```bash -npm install -g ndb -``` - -...then run SvelteKit: - -```bash -ndb npm run dev -``` - -> This assumes that `npm run dev` runs `sapper dev`. You can also run SvelteKit via [npx](https://blog.npmjs.org/post/162869356040/introducing-npx-an-npm-package-runner), as in `ndb npx sapper dev`. - -Note that you may not see any terminal output for a few seconds while ndb starts up. diff --git a/documentation/docs/99-troubleshooting.md b/documentation/docs/99-troubleshooting.md new file mode 100644 index 000000000000..3f1a7f38a4ae --- /dev/null +++ b/documentation/docs/99-troubleshooting.md @@ -0,0 +1,34 @@ +--- +title: Troubleshooting +--- + +### Server-side rendering + +SvelteKit will render any component first on the server side and send it to the client as HTML. It will then run the component again on the client side to allow it to update based on dynamic data. This means you need to ensure that components can run both on the client and server side. + +If, for example, your components try to access the global variables `document` or `window`, this will result in an error when the page is pre-rendered on the server side. + +If you need access to these variables, you can run code exclusively on the client side by wrapping it in + +```js +import { browser } from '$app/env'; + +if (browser) { + // client-only code here +} +``` + +Alternatively, you can run it `onMount`, since this only runs in the browser. This is also a good way to load libraries that depend on `window`: + +```html + +``` From 85cfaa51b72db7c7e8c9812424c381d4e87d118b Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 14 Mar 2021 14:47:31 -0400 Subject: [PATCH 03/14] document modules --- documentation/docs/04-client-api.md | 45 --------------- documentation/docs/05-imports.md | 69 +++++++++++++++++++++++ documentation/docs/07-state-management.md | 53 ----------------- 3 files changed, 69 insertions(+), 98 deletions(-) delete mode 100644 documentation/docs/04-client-api.md create mode 100644 documentation/docs/05-imports.md delete mode 100644 documentation/docs/07-state-management.md diff --git a/documentation/docs/04-client-api.md b/documentation/docs/04-client-api.md deleted file mode 100644 index b6ae06cfd090..000000000000 --- a/documentation/docs/04-client-api.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Client API ---- - -The `$app/navigation` and `$app/stores` modules contain functions for controlling SvelteKit programmatically and responding to events. - -### goto(href, options?) - -- `href` — the page to go to -- `options` — not required - - `replaceState` (`boolean`, default `false`) — determines whether to use `history.pushState` (the default) or `history.replaceState`. - - `noscroll` (`boolean`, default `false`) — prevent scroll to top after navigation. - -Programmatically navigates to the given `href`. If the destination is a SvelteKit route, SvelteKit will handle the navigation, otherwise the page will be reloaded with the new `href`. In other words, the behaviour is as though the user clicked on a link with this `href`. - -Returns a `Promise` that resolves when the navigation is complete. This can be used to perform actions once the navigation has completed, such as updating a database, store, etc. - -```js -import { goto } from '$app/navigation'; - -const navigateAndSave = async () => { - await goto('/'); - saveItem(); -}; - -const saveItem = () => { - // do something with the database -}; -``` - -### prefetch(href) - -- `href` — the page to prefetch - -Programmatically prefetches the given page, which means a) ensuring that the code for the page is loaded, and b) calling the page's `preload` method with the appropriate options. This is the same behaviour that SvelteKit triggers when the user taps or mouses over an `` element with [sveltekit:prefetch](docs#sveltekit_prefetch). - -Returns a `Promise` that resolves when the prefetch is complete. - -### prefetchRoutes(routes?) - -- `routes` — an optional array of strings representing routes to prefetch - -Programmatically prefetches the code for routes that haven't yet been fetched. Typically, you might call this to speed up subsequent navigation (this is the 'L' of the [PRPL pattern](https://developers.google.com/web/fundamentals/performance/prpl-pattern/)). Omitting arguments will cause all routes to be fetched, or you can specify routes by any matching pathname such as `/about` (to match `src/routes/about.svelte`) or `/blog/*` (to match `src/routes/blog/[slug].svelte`). Unlike `prefetch`, this won't call `preload` for individual pages. - -Returns a `Promise` that resolves when the routes have been prefetched. diff --git a/documentation/docs/05-imports.md b/documentation/docs/05-imports.md new file mode 100644 index 000000000000..1617d5c0d0e4 --- /dev/null +++ b/documentation/docs/05-imports.md @@ -0,0 +1,69 @@ +--- +title: Modules +--- + +SvelteKit makes a number of modules available to your application. + +### $app/env + +```js +import { amp, browser, dev } from '$app/env'; +``` + +* `amp` is `true` or `false` depending on the corresponding value in your [project configuration](#configuration) +* `browser` is `true` or `false` depending on whether the app is running in the browser or on the server +* `dev` is `true` in development mode, `false` in production + +### $app/navigation + +```js +import { goto, prefetch, prefetchRoutes } from '$app/navigation'; +``` + +* `goto(href, { replaceState, noscroll })` returns a `Promise` that resolves when SvelteKit navigates (or fails to navigate, in which case the promise rejects) to the specified `href`. The second argument is optional. If `replaceState` is true, a new history entry won't be created. If `noscroll` is true, the browser won't scroll to the top of the page after navigation. +* `prefetch(href)` programmatically prefetches the given page, which means a) ensuring that the code for the page is loaded, and b) calling the page's `load` function with the appropriate options. This is the same behaviour that SvelteKit triggers when the user taps or mouses over an `` element with [sveltekit:prefetch](docs#sveltekit_prefetch). If the next navigation is to `href`, the values returned from `load` will be used, making navigation instantaneous. Returns a `Promise` that resolves when the prefetch is complete. +* `prefetchRoutes(routes)` — programmatically prefetches the code for routes that haven't yet been fetched. Typically, you might call this to speed up subsequent navigation. If no argument is given, all routes will be fetched, otherwise you can specify routes by any matching pathname such as `/about` (to match `src/routes/about.svelte`) or `/blog/*` (to match `src/routes/blog/[slug].svelte`). Unlike `prefetch`, this won't call `preload` for individual pages. Returns a `Promise` that resolves when the routes have been prefetched. + +### $app/paths + +```js +import { base, assets } from '$app/paths'; +``` + +* `base` — a root-relative (i.e. begins with a `/`) string that matches `config.kit.files.base` in your [project configuration](#configuration) +* `assets` — a root-relative or absolute path that matches `config.kit.files.assets` (after it has been resolved against `base`) + +### $app/stores + +```js +import { getStores, navigating, page, session } from '$app/stores'; +``` + +Stores are _contextual_ — they are added to the [context](https://svelte.dev/tutorial/context-api) or your root component. This means that `session` and `page` are unique to each request on the server, rather than shared between multiple requests handled by the same server simultaneously, which is what makes it safe to include user-specific data in `session`. + +Because of that, the stores are not free-floating objects: they must be accessed during component initialisation, like anything else that would be accessed with `getContext`. + +* `getStores` is a convenience function around `getContext` that returns `{ navigating, page, session }`. Most of the time, you won't need to use it. + +The stores themselves attach to the correct context at the point of subscription, which means you can import and use them directly in components without boilerplate. + +* `navigating` is a [readable store](https://svelte.dev/tutorial/readable-stores) with a value that is `true` once client-side navigation starts, and `false` once it finishes +* `page` is a readable store whose value reflects the object passed to `load` functions — it contains `host`, `path`, `params` and `query` +* `session` is a [writable store](https://svelte.dev/tutorial/writable-stores) whose initial value is whatever was returned from [`getSession`](#getsession). It can be written to, but this will _not_ cause changes to persist on the server — this is something you must implement yourself. + + +### $lib + +This is a simple alias to `src/lib`, or whatever directory is specified as [`config.kit.files.lib`]. It allows you to access common components and utility modules from arbitrary files in `src/routes` without `../../../../` nonsense. + +### $service-worker + +This module is only available to [service workers](#service-workers). + +```js +import { build, files, timestamp } from '$service-worker'; +``` + +* `build` is an array of URL strings representing the files generated by Vite, suitable for caching with `cache.addAll(build)` +* `files` is an array of URL strings representing the files in your `static` directory, or whatever directory is specified by [`config.kit.files.assets`](#configuration) +* `timestamp` is the result of calling `Date.now()` at build time. It's useful for generating unique cache names inside your service worker, so that a later deployment of your app can invalidate old caches \ No newline at end of file diff --git a/documentation/docs/07-state-management.md b/documentation/docs/07-state-management.md deleted file mode 100644 index 11ab676082b8..000000000000 --- a/documentation/docs/07-state-management.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Stores ---- - -The `page` and `session` values passed to `preload` functions are available to components as [stores](https://svelte.dev/tutorial/writable-stores), along with `navigating`. - -A component can retrieve the stores by importing them: - -```html - -``` - -- `navigating` contains a read-only boolean value, indicating whether or not a navigation is pending -- `page` contains read-only information about the current route. See [preloading](docs#Arguments) for details. -- `session` can be used to pass data from the server related to the current request. It is a [writable store](https://svelte.dev/tutorial/writable-stores), meaning you can update it with new data. If, for example, you populate the session with the current user on the server, you can update the store when the user logs in. Your components will refresh to reflect the new state - -### Seeding session data - -`session` is `undefined` by default. To populate it with data, implement a function that returns session data given an HTTP request. This function will be located in `src/setup/index.js` (or `src/setup/index.ts`). - -As an example, let's look at how to populate the session with the current user. - -```js -// src/setup/index.js -import cookie from 'cookie'; -import jwt from 'jsonwebtoken'; - -export async function prepare({ headers }) { - const { token } = cookie.parse(headers.cookie); - const user = token ? jwt.decode(token) : false; - - return { - context: { - authenticated: !!user, - user - } - }; -} - -export async function getSession(context) { - return context; -} -``` - -The `prepare` function receives request headers from the current request. You can optionally return response headers and a context object passed to server routes (for example, `src/routes/api.js`). - -The `getSession` function may return a `Promise` (or, equivalently, be `async`). It receives the `context` from the `prepare` function, and you can seed the `session` data by returning it. - -The context and session data must be serializable. This means it must not contain functions or custom classes, just built-in JavaScript data types. - -> Note that if `session` returns a `Promise` (or is `async`), it will be re-awaited for on **every** server-rendered page route. From ee3de0488c2aa537ee0bd01038beb82098bd3761 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 14 Mar 2021 14:54:04 -0400 Subject: [PATCH 04/14] update link options --- .../{08-link-options.md => 06-a-options.md} | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) rename documentation/docs/{08-link-options.md => 06-a-options.md} (84%) diff --git a/documentation/docs/08-link-options.md b/documentation/docs/06-a-options.md similarity index 84% rename from documentation/docs/08-link-options.md rename to documentation/docs/06-a-options.md index f0e702cccc7c..f4d9c3326d84 100644 --- a/documentation/docs/08-link-options.md +++ b/documentation/docs/06-a-options.md @@ -1,5 +1,5 @@ --- -title: Link options +title: Anchor options --- ### sveltekit:prefetch @@ -16,30 +16,28 @@ We can mitigate that by _prefetching_ the data. Adding a `sveltekit:prefetch` at ...will cause SvelteKit to run the page's `load` function as soon as the user hovers over the link (on a desktop) or touches it (on mobile), rather than waiting for the `click` event to trigger navigation. Typically, this buys us an extra couple of hundred milliseconds, which is the difference between a user interface that feels laggy, and one that feels snappy. -> `sveltekit:prefetch` is a SvelteKit idiom, not a standard attribute for `` elements - You can also programmatically invoke `prefetch` from `$app/navigation`. -### rel=external +### sveltekit:noscroll -By default, the SvelteKit runtime intercepts clicks on `` elements and bypasses the normal browser navigation for relative (same-origin) URLs that match one of your page routes. We sometimes need to tell SvelteKit that certain links need to be be handled by normal browser navigation. +When navigating to internal links, SvelteKit mirrors the browser's default navigation behaviour: it will change the scroll position to 0,0 so that the user is at the very top left of the page (unless the link includes a `#hash`, in which case it will scroll to the element with a matching ID). -Adding a `rel=external` attribute to a link... +In certain cases, you may wish to disable this behaviour. Adding a `sveltekit:noscroll` attribute to a link... ```html -Path +Path ``` -...will trigger a browser navigation when the link is clicked. +...will prevent scrolling after the link is clicked. -### sveltekit:noscroll +### rel=external -When navigating to internal links, SvelteKit will change the scroll position to 0,0 so that the user is at the very top left of the page. When a hash is defined, it will scroll to the element with a matching ID. +By default, the SvelteKit runtime intercepts clicks on `` elements and bypasses the normal browser navigation for relative (same-origin) URLs that match one of your page routes. We sometimes need to tell SvelteKit that certain links need to be be handled by normal browser navigation. -In certain cases, you may wish to disable this behaviour. Adding a `sveltekit:noscroll` attribute to a link... +Adding a `rel=external` attribute to a link... ```html -Path +Path ``` -...will prevent scrolling after the link is clicked. +...will trigger a browser navigation when the link is clicked. From 7f7f403e8d43ac4e8141bc480936052d723b1b0d Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 14 Mar 2021 18:24:05 -0400 Subject: [PATCH 05/14] document config options --- documentation/docs/98-configuration.md | 115 +++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 documentation/docs/98-configuration.md diff --git a/documentation/docs/98-configuration.md b/documentation/docs/98-configuration.md new file mode 100644 index 000000000000..245bd9209bf6 --- /dev/null +++ b/documentation/docs/98-configuration.md @@ -0,0 +1,115 @@ +--- +title: Configuration +--- + +Your project's configuration lives in a `svelte.config.cjs` file. All values are optional. The complete list of options, with defaults, is shown here: + +```js +/** @type {import('@sveltejs/kit').Config} */ +module.exports = { + // options passed to svelte.compile (https://svelte.dev/docs#svelte_compile) + compilerOptions: null, + + // an array of file extensions that should be treated as Svelte components + extensions: ['.svelte'], + + kit: { + adapter: null, + amp: false, + appDir: '_app', + files: { + assets: 'static', + lib: 'src/lib', + routes: 'src/routes', + serviceWorker: 'src/service-worker', + setup: 'src/setup', + template: 'src/app.html' + }, + host: null, + hostHeader: null, + paths: { + assets: '', + base: '' + }, + prerender: { + crawl: true, + enabled: true, + force: false, + pages: ['*'] + }, + startGlobal: null, + target: null + }, + + // options passed to svelte.preprocess (https://svelte.dev/docs#svelte_preprocess) + preprocess: null +}; +``` + +#### adapter + +Determines how the output of `svelte-kit build` is converted for different platforms. Can be specified as a `string` or a `[string, object]` tuple if you need to pass options. + +#### amp + +Enable [AMP](#amp) mode. + +#### appDir + +The directory relative to `paths.assets` where the built JS and CSS (and imported assets) are served from. (The filenames therein contain content-based hashes, meaning they can be cached indefinitely). + +#### files + +An object containing zero or more of the following `string` values: + +* `assets` — a place to put static files that should have stable URLs and undergo no processing, such as `favicon.ico` or `manifest.json` +* `lib` — your app's internal library, accessible throughout the codebase as `$lib` +* `routes` — the files that define the structure of your app (see [Routing](#routing)) +* `serviceWorker` — the location of your service worker's entry point (see [Service workers](#service-workers)) +* `setup` — the location of your setup file (see [Setup](#setup)) +* `template` — the location of the template for HTML responses + +#### host + +A value that overrides the `Host` header when populating `page.host` + +#### hostHeader + +If your app is behind a reverse proxy (think load balancers and CDNs) then the `Host` header will be incorrect. In most cases, the underlying host is exposed via the [`X-Forwarded-Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) header and you should specify this in your config if you need to access `page.host`: + +```js +// svelte.config.cjs +module.exports = { + kit: { + hostHeader: 'X-Forwarded-Host' + } +}; +``` + +**You should only do this if you trust the reverse proxy**, which is why it isn't the default. + +#### paths + +An object containing zero or more of the following `string` values: + +* `assets` — an absolute path, or a path relative to `base`, where your app's files are served from. This is useful if your files are served from a storage bucket of some kind +* `base` — a root-relative (i.e. starts with `/`) path that specifies where your app is served from. This allows the app to live on a non-root path + +#### prerender + +See [Prerendering](#prerendering). An object containing zero or more of the following: + +* `crawl` — determines whether SvelteKit should find pages to prerender by following links from the seed page(s) +* `enabled` — set to `false` to disable prerendering altogether +* `force` — if `true`, a page that fails to render will _not_ cause the entire build to fail +* `pages` — an array of pages to prerender, or start crawling from (if `crawl: true`). The `*` string includes all non-dynamic routes (i.e. pages with no `[parameters]` ) + +#### startGlobal + +You probably don't need this, it's mainly useful for SvelteKit's integration tests. + +If specified, the client-side app will not start automatically. Instead, a global function will be created with the specified name. Calling it will start the app and return a promise that resolves (or rejects) once everything has initialised. + +#### target + +Specifies an element to mount the app to. It must be a DOM selector that identifies an element that exists in your template file. If unspecified, the app will be mounted to `document.body`. \ No newline at end of file From 172740262e7ff91f82ca4e724a004e2dee62a73f Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 14 Mar 2021 19:28:52 -0400 Subject: [PATCH 06/14] finish scaffolding docs --- documentation/docs/03-loading.md | 20 +++++++++---------- documentation/docs/06-service-workers.md | 13 ++++++++++++ .../docs/{06-a-options.md => 07-a-options.md} | 0 documentation/docs/08-amp.md | 9 +++++++++ documentation/docs/09-adapters.md | 9 +++++++++ documentation/docs/10-prerendering.md | 9 +++++++++ documentation/docs/11-cli.md | 9 +++++++++ .../docs/{09-building.md => xx-building.md} | 0 .../docs/{11-deploying.md => xx-deploying.md} | 0 .../docs/{10-exporting.md => xx-exporting.md} | 0 .../docs/{12-security.md => xx-security.md} | 0 11 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 documentation/docs/06-service-workers.md rename documentation/docs/{06-a-options.md => 07-a-options.md} (100%) create mode 100644 documentation/docs/08-amp.md create mode 100644 documentation/docs/09-adapters.md create mode 100644 documentation/docs/10-prerendering.md create mode 100644 documentation/docs/11-cli.md rename documentation/docs/{09-building.md => xx-building.md} (100%) rename documentation/docs/{11-deploying.md => xx-deploying.md} (100%) rename documentation/docs/{10-exporting.md => xx-exporting.md} (100%) rename documentation/docs/{12-security.md => xx-security.md} (100%) diff --git a/documentation/docs/03-loading.md b/documentation/docs/03-loading.md index ad8bc4a4eabc..5f6f400c31fe 100644 --- a/documentation/docs/03-loading.md +++ b/documentation/docs/03-loading.md @@ -59,7 +59,7 @@ Note the `context="module"` — this is necessary because `load` runs before the The `load` function receives an object containing four fields — `page`, `fetch`, `session` and `context`. -#### input.page +#### page `page` is a `{ host, path, params, query }` object where `host` is the URL's host, `path` is its pathname, `params` is derived from `path` and the route filename, and `query` is an instance of `URLSearchParams`. @@ -70,17 +70,17 @@ So if the example above was `src/routes/blog/[slug].svelte` and the URL was `/bl - `page.query.get('foo') === 'bar'` - `page.query.has('baz')` -#### input.fetch +#### fetch `fetch` is equivalent to the native `fetch` web API, and can make credentialled requests. It can be used across both client and server contexts. > When `fetch` runs on the server, the resulting response will be serialized and inlined into the rendered HTML. This allows the subsequent client-side `load` to access identical data immediately without an additional network request. -#### input.session +#### session `session` can be used to pass data from the server related to the current request, e.g. the current user. By default it is `undefined`. [Seeding session data](#Seeding_session_data) describes how to add data to it. -#### input.context +#### context `context` is passed from layout components to child layouts and page components. For the root `$layout.svelte` component, it is equal to `{}`, but if that component's `load` function returns an object with a `context` property, it will be available to subsequent `load` functions. @@ -94,29 +94,29 @@ So if the example above was `src/routes/blog/[slug].svelte` and the URL was `/bl If you return a Promise from `load`, the SvelteKit will delay rendering until the promise resolves. The return value has several properties, all optional: -#### output.status +#### status The HTTP status code for the page. If returning an `error` this must be a `4xx` or `5xx` response; if returning a `redirect` it must be a `3xx` response. The default is `200`. -#### output.error +#### error If something goes wrong during `load`, return an `Error` object or a `string` describing the error alongside a `4xx` or `5xx` status code. -#### output.redirect +#### redirect If the page should redirect (because the page is deprecated, or the user needs to be logged in, or whatever else) return a `string` containing the location to which they should be redirected alongside a `3xx` status code. -#### output.maxage +#### maxage To cause pages to be cached, return a `number` describing the page's max age in seconds. The resulting cache header will include `private` if user data was involved in rendering the page (either via `session`, or because a credentialled `fetch` was made in a `load` function), but otherwise will include `public` so that it can be cached by CDNs. This only applies to page components, _not_ layout components. -#### output.props +#### props If the `load` function returns a `props` object, the props will be passed to the component when it is rendered. -#### output.context +#### context This will be merged with any existing `context` and passed to the `load` functions of subsequent layout and page components. diff --git a/documentation/docs/06-service-workers.md b/documentation/docs/06-service-workers.md new file mode 100644 index 000000000000..8a12d3f0a1ff --- /dev/null +++ b/documentation/docs/06-service-workers.md @@ -0,0 +1,13 @@ +--- +title: Service workers +--- + +Service workers act as proxy servers that handle network requests inside your app. This makes it possible to make your app work offline, but even if you don't need offline support (or can't realistically implement it because of the type of app you're building), it's often worth using service workers to speed up navigation by precaching your built JS and CSS. + +In SvelteKit, if you have a `src/service-worker.js` file (or `src/service-worker.ts`, or `src/service-worker/index.js`, etc) it will be built with Vite and automatically registered. + +> You can change the location of your service worker in your [project configuration](#configuration). + +Inside the service worker you have access to the [`$service-worker` module](#$service-worker). + +Because it needs to be bundled (since browsers don't yet support `import` in this context), and depends on the client-side app's build manifest, **service workers only work in production, not in development**. \ No newline at end of file diff --git a/documentation/docs/06-a-options.md b/documentation/docs/07-a-options.md similarity index 100% rename from documentation/docs/06-a-options.md rename to documentation/docs/07-a-options.md diff --git a/documentation/docs/08-amp.md b/documentation/docs/08-amp.md new file mode 100644 index 000000000000..4c85d4f22bda --- /dev/null +++ b/documentation/docs/08-amp.md @@ -0,0 +1,9 @@ +--- +title: AMP +--- + +An unfortunate reality of modern web development is that it is sometimes necessary to create an [AMP](https://amp.dev/) version of your site. In SvelteKit this can be done by setting the [`amp`](#configuration-amp) config option, which has the following effects: + +* Client-side JavaScript, including the router, is disabled +* Styles are concatenated into `