Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ A form is composed of a set of _fields_, which are defined by the schema. In the

These attributes allow SvelteKit to set the correct input type, set a `name` that is used to construct the `data` passed to the handler, populate the `value` of the form (for example following a failed submission, to save the user having to re-enter everything), and set the [`aria-invalid`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-invalid) state.

Passing a second argument to `.as(...)` is useful when rendering a form from existing data, such as an edit form or multiple instances created with [`for(...)`](#form-Multiple-instances-of-a-form). As well as setting the value of the element when it is rendered, it controls the value of the element when the form is reset. `radio`, `submit` and `hidden` inputs always need this value, and `checkbox` inputs need it when they represent one option in an array field. `file` inputs cannot be populated this way.
Passing a second argument to `.as(...)` is useful when rendering a form from existing data, such as an edit form or multiple instances created with [`for(...)`](#form-Multiple-instances-of-a-form). As well as setting the value of the element when it is rendered, it controls the value of the element when the form is reset. `radio`, `submit` and `hidden` inputs always need this value, and `checkbox` inputs need it when they represent one option in an array field. For these `radio` and `checkbox` inputs the second argument identifies the option, so whether it is currently checked goes in a third argument, e.g. `.as('radio', option, settings.visibility === option)` or `.as('checkbox', tag, settings.tags.includes(tag))`. `file` inputs cannot be populated this way.

> [!NOTE] The generated `name` attribute uses JS object notation (e.g. `nested.array[0].value`). String keys that require quotes such as `object['nested-array'][0].value` are not supported. Under the hood, boolean checkbox and number field names are prefixed with `b:` and `n:`, respectively, to signal SvelteKit to coerce the values from strings prior to validation.

Expand Down Expand Up @@ -1106,7 +1106,27 @@ export const createPost = form(
);
```

`requested` gives you access to the queries the client requested to refresh. Each entry is an `{ arg, query }` object: `arg` is the value the query's implementation function received — i.e. the argument *after* the schema has validated and (where applicable) transformed it — and `query` is a `RemoteQuery` already bound to the client's original cache key, so calling `query.refresh()` / `query.set(...)` updates the correct client instance. If parsing an argument fails, that query will error, but the entire command will not fail. `requested`'s second parameter, `limit`, is the maximum number of items it will return. Any refresh requests beyond this limit will fail.
`requested` gives you access to the queries the client requested to refresh. Each entry is an `{ arg, query, ignore }` object: `arg` is the value the query's implementation function received — i.e. the argument *after* the schema has validated and (where applicable) transformed it — and `query` is a `RemoteQuery` already bound to the client's original cache key, so calling `query.refresh()` / `query.set(...)` updates the correct client instance. Call `ignore()` if you intentionally do not want to update a particular instance:

```js
import { requested, query } from '$app/server';

export const getPosts = query('unchecked', ({ filter }) => {
return ['foo', 'bar'];
});
---cut---
for (const { arg, query, ignore } of requested(getPosts, 10)) {
if (arg.filter === 'author:santa') {
void query.refresh();
} else {
ignore();
}
}
```

Every requested update must be refreshed, set, reconnected (for a live query), or explicitly ignored. Otherwise, the corresponding query will enter an error state on the client. If parsing or validating an argument fails, that query will also error, but the entire command will not fail.

`requested`'s second parameter, `limit`, is the maximum number of items it will return. Any refresh requests beyond this limit will fail on the client.

> [!NOTE] `limit` is required because the list of refresh requests is controlled by the client — each entry causes the server to validate an argument and usually re-fetch data, so an unbounded list is a denial-of-service risk. Choose a limit that reflects the worst case you're willing to handle per request. You _can_ pass `Infinity` if you have explicitly decided to accept any number of refreshes, but it is not recommended.

Expand All @@ -1121,6 +1141,17 @@ declare const getPosts: RemoteQueryFunction<any, any>;
await requested(getPosts, 1).refreshAll();
```

If you want to intentionally ignore every selected update, use `ignoreAll`:

```js
import { requested } from '$app/server';

---cut---
await requested(getPosts, 10).ignoreAll();
```

`ignoreAll` only ignores entries within the specified `limit`. Any excess entries still fail on the client.

> [!NOTE] Why does the command have to name every query it's willing to refresh? Two reasons:
>
> - **Bundle size.** If a command could implicitly refresh *any* query in your app, SvelteKit would have to include every query's code in the command's server bundle, because it can't know ahead of time which ones will be called.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ When you create a new SvelteKit project with `npx sv create`, it installs [`adap
- [`svelte-adapter-azure-swa`](https://github.com/geoffrich/svelte-adapter-azure-swa) for [Azure Static Web Apps](https://docs.microsoft.com/en-us/azure/static-web-apps/)
- [`svelte-kit-sst`](https://github.com/sst/v2/tree/master/packages/svelte-kit-sst) for [AWS via SST](https://sst.dev/docs/start/aws/svelte)
- [`@sveltejs/adapter-node`](adapter-node) for [Google Cloud Run](https://cloud.google.com/run)
- [`@sveltejs/adapter-node`](adapter-node) for [Render](https://render.com)

It's recommended to install the appropriate adapter to your `devDependencies` once you've settled on a target environment, since this will add the adapter to your lockfile and slightly improve install times on CI.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ title: Cloudflare

To deploy to [Cloudflare Workers](https://workers.cloudflare.com/) or [Cloudflare Pages](https://pages.cloudflare.com/), use [`adapter-cloudflare`](https://github.com/sveltejs/kit/tree/main/packages/adapter-cloudflare).

This adapter will be installed by default when you use [`adapter-auto`](adapter-auto). If you plan on staying with Cloudflare, you can switch from [`adapter-auto`](adapter-auto) to using this adapter directly so that `event.platform` is emulated during local development, type declarations are automatically applied, and the ability to set Cloudflare-specific options is provided.
This adapter will be installed by default when you use [`adapter-auto`](adapter-auto). If you plan on staying with Cloudflare, you can switch from [`adapter-auto`](adapter-auto) to using this adapter directly so that `cloudflare:workers` is emulated during local development, type declarations are automatically applied, and the ability to set Cloudflare-specific options is provided.

## Comparisons

Expand Down Expand Up @@ -54,7 +54,7 @@ Path to your [Wrangler configuration file](https://developers.cloudflare.com/wor

### platformProxy

Preferences for the emulated `platform.env` local bindings. See the [getPlatformProxy](https://developers.cloudflare.com/workers/wrangler/api/#parameters-1) Wrangler API documentation for a full list of options.
Preferences for the emulated `env` local bindings. See the [getPlatformProxy](https://developers.cloudflare.com/workers/wrangler/api/#parameters-1) Wrangler API documentation for a full list of options.

### fallback

Expand Down Expand Up @@ -131,62 +131,34 @@ Functions contained in the [`/functions` directory](https://developers.cloudflar

## Runtime APIs

The [`env`](https://developers.cloudflare.com/workers/runtime-apis/fetch-event#parameters) object contains your project's [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/), which consist of KV/DO namespaces, etc. It is passed to SvelteKit via the `platform` property, along with [`ctx`](https://developers.cloudflare.com/workers/runtime-apis/context/), [`caches`](https://developers.cloudflare.com/workers/runtime-apis/cache/), and [`cf`](https://developers.cloudflare.com/workers/runtime-apis/request/#incomingrequestcfproperties), meaning that you can access it in hooks and endpoints:
The [`env`](https://developers.cloudflare.com/workers/runtime-apis/fetch-event#parameters) object contains your project's [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/), which consist of KV/DO namespaces, etc. It is available on the [`cloudflare:workers`](https://developers.cloudflare.com/workers/runtime-apis/bindings/#importing-env-as-a-global) module.

```js
/// file: +server.js
// @filename: ambient.d.ts
import { DurableObjectNamespace } from '@cloudflare/workers-types';

declare global {
namespace App {
interface Platform {
env: {
YOUR_DURABLE_OBJECT_NAMESPACE: DurableObjectNamespace;
};
}
}
declare module 'cloudflare:workers' {
export const env: {
YOUR_DURABLE_OBJECT_NAMESPACE: import('@cloudflare/workers-types').DurableObjectNamespace;
};
}
// @filename: +server.js
// ---cut---
// @errors: 2355 2322
/// file: +server.js
import { env } from 'cloudflare:workers';

/** @type {import('./$types').RequestHandler} */
export async function POST({ request, platform }) {
const x = platform?.env.YOUR_DURABLE_OBJECT_NAMESPACE.idFromName('x');
export async function POST() {
const x = env.YOUR_DURABLE_OBJECT_NAMESPACE.idFromName('x');
}
```

> [!NOTE] SvelteKit's built-in [`$app/env/*` modules](environment-variables) should be preferred for environment variables.

To make these types available to your app, install [`wrangler`](https://www.npmjs.com/package/wrangler), run [`wrangler types`](https://developers.cloudflare.com/workers/languages/typescript/), and reference them in your `src/app.d.ts`:

```ts
// @filename: ambient.d.ts
import { KVNamespace, DurableObjectNamespace } from '@cloudflare/workers-types';

namespace Cloudflare {
export interface Env {
YOUR_KV_NAMESPACE: KVNamespace;
YOUR_DURABLE_OBJECT_NAMESPACE: DurableObjectNamespace;
}
}
/// file: src/app.d.ts
// ---cut---

declare global {
namespace App {
interface Platform {
+++ env: Cloudflare.Env;+++
}
}
}

export {};
```
To make these types available to your app, install [`wrangler`](https://www.npmjs.com/package/wrangler) and run [`wrangler types`](https://developers.cloudflare.com/workers/languages/typescript/).

### Testing locally

Cloudflare specific values in the `platform` property are emulated during dev and preview modes. Local [bindings](https://developers.cloudflare.com/workers/wrangler/configuration/#bindings) are created based on your [Wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/) and are used to populate `platform.env` during development and preview. Use the adapter config [`platformProxy` option](#Options-platformProxy) to change your preferences for the bindings.
Cloudflare specific values are emulated during dev and preview modes. Local [bindings](https://developers.cloudflare.com/workers/wrangler/configuration/#bindings) are created based on your [Wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/) and are used to populate `env` during development and preview. Use the adapter config [`platformProxy` option](#Options-platformProxy) to change your preferences for the bindings.

> [!NOTE] [Durable Objects](https://developers.cloudflare.com/durable-objects/) and [Workflows](https://developers.cloudflare.com/workflows/), which require custom classes to be exported from your worker, are not currently supported.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ If `true`, your app will be deployed as a [Netlify Edge Function](https://docs.n

If `true`, your app will be split into multiple functions instead of a single one for the entire app.

If `edge` is `true`, this option cannot be used.

## Netlify alternatives to SvelteKit functionality

You may build your app using functionality provided directly by SvelteKit without relying on any Netlify functionality. Using the SvelteKit versions of these features will allow them to be used in dev mode, tested with integration tests, and to work with other adapters should you ever decide to switch away from Netlify. However, in some scenarios you may find it beneficial to use the Netlify versions of these features. One example would be if you're migrating an app that's already hosted on Netlify to SvelteKit.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,12 @@ The expiration time (in seconds) before the cached asset will be re-generated by

### bypassToken

A random token that can be provided in the URL to bypass the cached version of the asset, by requesting the asset with a `__prerender_bypass=<token>` cookie.
A random token that can be used for two things:

Making a `GET` or `HEAD` request with `x-prerender-revalidate: <token>` will force the asset to be re-validated.
- Draft mode, which bypasses the cache so that you can, for example, view live content from your CMS as you edit it. Send the token in a `__prerender_bypass=<token>` cookie to render the route at request time. See [Vercel's Draft Mode documentation](https://vercel.com/docs/draft-mode?framework=sveltekit) for more details.
- Revalidation, which empties the route's ISR cache and repopulates it for future visitors. To do so, send a `GET` or `HEAD` request with a `x-prerender-revalidate: <token>` header.

The `BYPASS_TOKEN` is saved at build time; setting or changing it after the application has been built requires a new deployment.

Note that the `BYPASS_TOKEN` string must be at least 32 characters long. You could generate one using the JavaScript console like so:

Expand Down Expand Up @@ -200,6 +203,10 @@ If you have Vercel functions contained in the `api` directory at the project's r

Projects created before a certain date may default to using an older Node version than what SvelteKit currently requires. You can [change the Node version in your project settings](https://vercel.com/docs/concepts/functions/serverless-functions/runtimes/node-js#node.js-version).

### More information

You can find more information on how to use SvelteKit on Vercel [in the Vercel documentation](https://vercel.com/docs/frameworks/full-stack/sveltekit).

## Troubleshooting

### Accessing the file system
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ type AdapterSpecificOptions = any;

// @filename: index.js
// ---cut---
import { getRequest, setResponse } from '@sveltejs/kit/node';

/** @param {AdapterSpecificOptions} options */
export default function (options) {
/** @type {import('@sveltejs/kit').Adapter} */
Expand Down Expand Up @@ -42,6 +44,15 @@ export default function (options) {
}
},
vite: {
getRequest(options) {
const request = getRequest(options);
// modify the Request object here if needed
return request;
},
setResponse(res, response) {
// handle WebSockets here, for example
setResponse(res, response);
},
plugins: {
// add plugins here to integrate with Vite
pre: [],
Expand All @@ -61,8 +72,8 @@ Within the `adapt` method, there are a number of things that an adapter should d
- Clear out the build directory
- Write SvelteKit output with `builder.writeClient`, `builder.writeServer`, and `builder.writePrerendered`
- Output code that:
- Imports `Server` from `${builder.getServerDirectory()}/index.js`
- Instantiates the app with a manifest generated with `builder.generateManifest({ relativePath })`
- Imports a `server` instance generated by `${builder.generateServerInstance()}`
- Runs `await server.init({ env, read })`
- Listens for requests from the platform, converts them to a standard [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) if necessary, calls the `server.respond(request, { getClientAddress })` function to generate a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) and responds with it
- expose any platform-specific information to SvelteKit via the `platform` option passed to `server.respond`
- Bundle the output to avoid needing to install dependencies on the target platform, if necessary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ Bundling can disrupt this in two ways.

First, a bundler may place code imported by `instrumentation.server.js` and application code in the same shared chunk. Importing that chunk to initialize instrumentation can then evaluate application code before the interceptor has been installed. By the time the application is dynamically imported, the module is already in the ESM module cache and it is too late to instrument it.

There is also an unavoidable chicken-and-egg limitation: importing [`$app/env/*` modules](environment-variables) evaluates your `src/env.js` module and its dependencies. Because of this, instrumentation cannot intercept a module imported by `src/env`, because that imported module must run before `instrumentation.server.js` can start. Therefore, you should avoid importing anything from `src/env.js` that you need to instrument.

Second, a bundler may inline or transform the module you want to instrument. For example, it could replace this:

```js
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,25 @@ Video files can be very large, so extra care should be taken to ensure that they

### Fonts

SvelteKit automatically preloads critical `.js` and `.css` files when the user visits a page, but it does _not_ preload fonts by default, since this may cause unnecessary files (such as font weights that are referenced by your CSS but not actually used on the current page) to be downloaded. Having said that, preloading fonts correctly can make a big difference to how fast your site feels. In your [`handle`](hooks#handle) hook, you can call `resolve` with a `preload` filter that includes your fonts.
SvelteKit automatically preloads critical `.js` and `.css` files when the user visits a page, but it does _not_ preload fonts by default, since this may cause unnecessary files (such as font weights that are referenced by your CSS but not actually used on the current page) to be downloaded. Having said that, preloading fonts correctly can make a big difference to how fast your site feels. In your [`handle`](hooks#handle) hook, you can call `resolve` with a `preload` filter that includes your fonts:

```js
/// file: src/hooks.server.js
/** @type {import('@sveltejs/kit/hooks').Handle} */
export async function handle({ event, resolve }) {
return resolve(event, {
preload: (asset) => {
if (asset.type === 'font') {
return asset.filename === 'node_modules/@fontsource/inter/files/inter-latin-400-normal.woff2';
}

return true;
}
});
}
```

`filename` is the source filename relative to the project root, and is only available when `asset.type === 'font'` since JS and CSS assets are bundled by Vite.

You can reduce the size of font files by [subsetting](https://web.dev/learn/performance/optimize-web-fonts#subset_your_web_fonts) your fonts.

Expand Down
Loading