diff --git a/.changeset/poor-gifts-cross.md b/.changeset/poor-gifts-cross.md new file mode 100644 index 000000000000..275626734c3c --- /dev/null +++ b/.changeset/poor-gifts-cross.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +[breaking] `ssr/hydrate/router/prerender.default` are now configurable in `+page(.server).js` and `+layout(.server).js` diff --git a/documentation/docs/03-routing.md b/documentation/docs/03-routing.md index 03468fa3308b..462ff74754d3 100644 --- a/documentation/docs/03-routing.md +++ b/documentation/docs/03-routing.md @@ -69,9 +69,12 @@ This function runs alongside `+page.svelte`, which means it runs on the server d As well as `load`, `page.js` can export values that configure the page's behaviour: -- `export const prerender = true` or `false` overrides [`config.kit.prerender.default`](/docs/configuration#prerender) -- `export const hydrate = true` or `false` overrides [`config.kit.browser.hydrate`](/docs/configuration#browser) -- `export const router = true` or `false` overrides [`config.kit.browser.router`](/docs/configuration#browser) +- `export const prerender = true` or `false` or `'auto'` +- `export const hydrate = true` or `false` +- `export const router = true` or `false` +- `export const ssr = true` or `false` + +You can find more information about these in [page options](/docs/page-options). #### +page.server.js @@ -108,6 +111,8 @@ export async function load({ params }) { During client-side navigation, SvelteKit will load this data from the server, which means that the returned value must be serializable using [devalue](https://github.com/rich-harris/devalue). +Like `+page.js`, `+page.server.js` can export [page options](/docs/page-options) — `prerender`, `hydrate`, `router` and `ssr`. + #### Actions `+page.server.js` can also declare _actions_, which correspond to the `POST`, `PATCH`, `PUT` and `DELETE` HTTP methods. A request made to the page with one of these methods will invoke the corresponding action before rendering the page. @@ -277,7 +282,7 @@ export function load() { } ``` -Unlike `+page.js`, `+layout.js` cannot export `prerender`, `hydrate` and `router`, as these are page-level options. +If a `+layout.js` exports [page options](/docs/page-options) — `prerender`, `hydrate` `router` and `ssr` — they will be used as defaults for child pages. Data returned from a layout's `load` function is also available to all its child pages: @@ -297,6 +302,8 @@ Data returned from a layout's `load` function is also available to all its child To run your layout's `load` function on the server, move it to `+layout.server.js`, and change the `LayoutLoad` type to `LayoutServerLoad`. +Like `+layout.js`, `+layout.server.js` can export [page options](/docs/page-options) — `prerender`, `hydrate` `router` and `ssr`. + ### +server As well as pages, you can define routes with a `+server.js` file (sometimes referred to as an 'API route' or an 'endpoint'), which gives you full control over the response. Your `+server.js` file (or `+server.ts`) exports functions corresponding to HTTP verbs like `GET`, `POST`, `PATCH`, `PUT` and `DELETE` that take a `RequestEvent` argument and return a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object. diff --git a/documentation/docs/06-hooks.md b/documentation/docs/06-hooks.md index ded925961642..7bf25b938010 100644 --- a/documentation/docs/06-hooks.md +++ b/documentation/docs/06-hooks.md @@ -63,7 +63,6 @@ You can add call multiple `handle` functions with [the `sequence` helper functio `resolve` also supports a second, optional parameter that gives you more control over how the response will be rendered. That parameter is an object that can have the following fields: -- `ssr: boolean` (default `true`) — if `false`, renders an empty 'shell' page instead of server-side rendering - `transformPageChunk(opts: { html: string, done: boolean }): MaybePromise` — applies custom transforms to HTML. If `done` is true, it's the final chunk. Chunks are not guaranteed to be well-formed HTML (they could include an element's opening tag but not its closing tag, for example) but they will always be split at sensible boundaries such as `%sveltekit.head%` or layout/page components. ```js @@ -71,7 +70,6 @@ You can add call multiple `handle` functions with [the `sequence` helper functio /** @type {import('@sveltejs/kit').Handle} */ export async function handle({ event, resolve }) { const response = await resolve(event, { - ssr: !event.url.pathname.startsWith('/admin'), transformPageChunk: ({ html }) => html.replace('old', 'new') }); @@ -79,8 +77,6 @@ export async function handle({ event, resolve }) { } ``` -> Disabling [server-side rendering](/docs/appendix#ssr) effectively turns your SvelteKit app into a [**single-page app** or SPA](/docs/appendix#csr-and-spa). In most situations this is not recommended ([see appendix](/docs/appendix#ssr)). Consider whether it's truly appropriate to disable it, and do so selectively rather than for all requests. - ### handleError If an error is thrown during loading or rendering, this function will be called with the `error` and the `event` that caused it. This allows you to send data to an error tracking service, or to customise the formatting before printing the error to the console. diff --git a/documentation/docs/12-page-options.md b/documentation/docs/12-page-options.md index e0ed3ef0cdb6..e8e44dd0af60 100644 --- a/documentation/docs/12-page-options.md +++ b/documentation/docs/12-page-options.md @@ -2,53 +2,27 @@ title: Page options --- -By default, SvelteKit will render any component first on the server and send it to the client as HTML. It will then render the component again in the browser to make it interactive in a process called **hydration**. For this reason, you need to ensure that components can run in both places. SvelteKit will then initialise a [**router**](/docs/routing) that takes over subsequent navigations. +By default, SvelteKit will render (or [prerender](/docs/appendix#prerendering)) any component first on the server and send it to the client as HTML. It will then render the component again in the browser to make it interactive in a process called **hydration**. For this reason, you need to ensure that components can run in both places. SvelteKit will then initialise a [**router**](/docs/routing) that takes over subsequent navigations. -You can control each of these on a per-app (via `svelte.config.js`) or per-page (via `+page.js` or `+page.server.js`) basis. If both are specified, per-page settings override per-app settings in case of conflicts. - -### router - -SvelteKit includes a [client-side router](/docs/appendix#routing) that intercepts navigations (from the user clicking on links, or interacting with the back/forward buttons) and updates the page contents, rather than letting the browser handle the navigation by reloading. - -In certain circumstances you might need to disable [client-side routing](/docs/appendix#routing) with the app-wide [`browser.router` config option](/docs/configuration#browser) or the page-level `router` export: - -```js -/// file: +page.js/+page.server.js -export const router = false; -``` - -Note that this will disable client-side routing for any navigation from this page, regardless of whether the router is already active. - -### hydrate - -Ordinarily, SvelteKit [hydrates](/docs/appendix#hydration) your server-rendered HTML into an interactive page. Some pages don't require JavaScript at all — many blog posts and 'about' pages fall into this category. In these cases you can skip hydration when the app boots up with the app-wide [`browser.hydrate` config option](/docs/configuration#browser) or the page-level `hydrate` export: - -```js -/// file: +page.js/+page.server.js -export const hydrate = false; -``` - -> If `hydrate` and `router` are both `false`, SvelteKit will not add any JavaScript to the page at all. If [server-side rendering](/docs/hooks#handle) is disabled in `handle`, `hydrate` must be `true` or no content will be rendered. +You can control each of these on a page-by-page basis by exporting options from [`+page.js`](/docs/routing#page-page-js) or [`+page.server.js`](/docs/routing#page-page-server-js), or for groups of pages using a shared [`+layout.js`](/docs/routing#layout-layout-js) or [`+layout.server.js`](/docs/routing#layout-layout-server-js). To define an option for the whole app, export it from the root layout. Child layouts and pages override values set in parent layouts, so — for example — you can enable prerendering for your entire app then disable it for pages that need to be dynamically rendered. ### prerender It's likely that at least some routes of your app can be represented as a simple HTML file generated at build time. These routes can be [_prerendered_](/docs/appendix#prerendering). -Prerendering happens automatically for any `+page` or `+server` file with the `prerender` annotation: - ```js /// file: +page.js/+page.server.js/+server.js export const prerender = true; ``` -Alternatively, you can set [`config.kit.prerender.default`](/docs/configuration#prerender) to `true` and prerender everything except pages that are explicitly marked as _not_ prerenderable: +Alternatively, you can set `export const prerender = true` in your root `+layout` and prerender everything except pages that are explicitly marked as _not_ prerenderable: ```js /// file: +page.js/+page.server.js/+server.js export const prerender = false; ``` -Routes with `prerender = true` will be excluded from manifests used for dynamic SSR, making your server (or serverless/edge functions) smaller. In some cases you might want to prerender a route but also include it in the manifest (for example, you want to prerender your most recent/popular content but server-render the long tail) — for these cases, there's a third option, 'auto': +Routes with `prerender = true` will be excluded from manifests used for dynamic SSR, making your server (or serverless/edge functions) smaller. In some cases you might want to prerender a route but also include it in the manifest (for example, with a route like `/blog/[slug]` where you want to prerender your most recent/popular content but server-render the long tail) — for these cases, there's a third option, 'auto': ```js /// file: +page.js/+page.server.js/+server.js @@ -57,7 +31,24 @@ export const prerender = 'auto'; > If your entire app is suitable for prerendering, you can use [`adapter-static`](https://github.com/sveltejs/kit/tree/master/packages/adapter-static), which will output files suitable for use with any static webserver. -The prerenderer will start at the root of your app and generate HTML for any prerenderable pages it finds. Each page is scanned for `` elements that point to other pages that are candidates for prerendering — because of this, you generally don't need to specify which pages should be accessed. If you _do_ need to specify which pages should be accessed by the prerenderer, you can do so with the `entries` option in the [prerender configuration](/docs/configuration#prerender). +The prerenderer will start at the root of your app and generate files for any prerenderable pages or `+server.js` routes it finds. Each page is scanned for `` elements that point to other pages that are candidates for prerendering — because of this, you generally don't need to specify which pages should be accessed. If you _do_ need to specify which pages should be accessed by the prerenderer, you can do so with the `entries` option in the [prerender configuration](/docs/configuration#prerender). + +#### Prerendering server routes + +Unlike the other page options, `prerender` also applies to `+server.js` files. These files are _not_ affected from layouts, but will inherit default values from the pages that fetch data from them, if any. For example if a `+page.js` contains this `load` function... + +```js +/// file: +page.js +export const prerender = true; + +/** @type {import('./$types').PageLoad} */ +export async function load({ fetch }) { + const res = await fetch('/my-server-route.json'); + return await res.json(); +} +``` + +...then `src/routes/my-server-route.json/+server.js` will be treated as prerenderable if it doesn't contain its own `export const prerender = false`. #### When not to prerender @@ -76,3 +67,36 @@ Because prerendering writes to the filesystem, it isn't possible to have two end For that reason among others, it's recommended that you always include a file extension — `src/routes/foo.json/+server.js` and `src/routes/foo/bar.json/+server.js` would result in `foo.json` and `foo/bar.json` files living harmoniously side-by-side. For _pages_, we skirt around this problem by writing `foo/index.html` instead of `foo`. + +### hydrate + +Ordinarily, SvelteKit [hydrates](/docs/appendix#hydration) your server-rendered HTML into an interactive page. Some pages don't require JavaScript at all — many blog posts and 'about' pages fall into this category. In these cases you can skip hydration through the `hydrate` export: + +```js +/// file: +page.js +export const hydrate = false; +``` + +> If `hydrate` and `router` are both `false`, SvelteKit will not add any JavaScript to the page at all. If [server-side rendering](/docs/hooks#handle) is disabled in `handle`, `hydrate` must be `true` or no content will be rendered. + +### router + +SvelteKit includes a [client-side router](/docs/appendix#routing) that intercepts navigations (from the user clicking on links, or interacting with the back/forward buttons) and updates the page contents, rather than letting the browser handle the navigation by reloading. + +In certain circumstances you might need to disable [client-side routing](/docs/appendix#routing) through the `router` export: + +```js +/// file: +page.js +export const router = false; +``` + +Note that this will disable client-side routing for any navigation from this page, regardless of whether the router is already active. + +### ssr + +Normally, SvelteKit renders your page on the server first and sends that HTML to the client where it's hydrated. If you set `ssr` to `false`, it renders an empty 'shell' page instead. This is useful if your page accesses browser-only methods or objects, but in most situations it's not recommended ([see appendix](/docs/appendix#ssr)). + +```js +/// file: +page.js +export const ssr = false; +``` diff --git a/documentation/docs/15-configuration.md b/documentation/docs/15-configuration.md index 81f858280a11..1893883bbbd0 100644 --- a/documentation/docs/15-configuration.md +++ b/documentation/docs/15-configuration.md @@ -18,10 +18,6 @@ const config = { adapter: undefined, alias: {}, appDir: '_app', - browser: { - hydrate: true, - router: true - }, csp: { mode: 'auto', directives: { @@ -128,13 +124,6 @@ const config = { 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). Must not start or end with `/`. -### browser - -An object containing zero or more of the following `boolean` values: - -- `hydrate` — whether to [hydrate](/docs/page-options#hydrate) the server-rendered HTML with a client-side app. (It's rare that you would set this to `false` on an app-wide basis.) -- `router` — enables or disables the client-side [router](/docs/page-options#router) app-wide. - ### csp An object containing zero or more of the following values: diff --git a/documentation/docs/17-seo.md b/documentation/docs/17-seo.md index 64208d7c4440..2e1d882dc117 100644 --- a/documentation/docs/17-seo.md +++ b/documentation/docs/17-seo.md @@ -83,20 +83,13 @@ export async function GET() { #### AMP -An unfortunate reality of modern web development is that it is sometimes necessary to create an [Accelerated Mobile Pages (AMP)](https://amp.dev/) version of your site. In SvelteKit this can be done by enforcing the following [configuration](/docs/configuration) options... +An unfortunate reality of modern web development is that it is sometimes necessary to create an [Accelerated Mobile Pages (AMP)](https://amp.dev/) version of your site. In SvelteKit this can be done by setting the [`inlineStyleThreshold`](/docs/configuration#inlinestylethreshold) option... ```js /// file: svelte.config.js /** @type {import('@sveltejs/kit').Config} */ const config = { kit: { - // the combination of these options - // disables JavaScript - browser: { - hydrate: false, - router: false - }, - // since isn't // allowed, inline all styles inlineStyleThreshold: Infinity @@ -106,6 +99,16 @@ const config = { export default config; ``` +...disabling `hydrate` and `router` in your root `+layout.js`/`+layout.server.js`... + +```js +/// file: src/routes/+layout.server.js +// the combination of these options +// disables JavaScript +export const hydrate = false; +export const router = false; +``` + ...and transforming the HTML using `transformPageChunk` along with `transform` imported from `@sveltejs/amp`: ```js diff --git a/packages/adapter-static/README.md b/packages/adapter-static/README.md index 391891857c20..a692e1bdfaeb 100644 --- a/packages/adapter-static/README.md +++ b/packages/adapter-static/README.md @@ -4,7 +4,7 @@ ## Usage -Install with `npm i -D @sveltejs/adapter-static`, then add the adapter to your `svelte.config.js`: +Install with `npm i -D @sveltejs/adapter-static`, then add the adapter to your `svelte.config.js`... ```js // svelte.config.js @@ -19,16 +19,20 @@ export default { assets: 'build', fallback: null, precompress: false - }), - - prerender: { - // This can be false if you're using a fallback (i.e. SPA mode) - default: true - } + }) } }; ``` +...and add the [`prerender`](https://kit.svelte.dev/docs/page-options#prerender) option to your root layout: + +```js +// src/routes/+layout.js + +// This can be false if you're using a fallback (i.e. SPA mode) +export const prerender = true; +``` + > ⚠️ You must ensure SvelteKit's [`trailingSlash`](https://kit.svelte.dev/docs/configuration#trailingslash) option is set appropriately for your environment. If your host does not render `/a.html` upon receiving a request for `/a` then you will need to set `trailingSlash: 'always'` to create `/a/index.html` instead. ## Zero-config support @@ -44,9 +48,6 @@ export default { kit: { - adapter: adapter({...}), + adapter: adapter(), - - prerender: { - default: true } } }; @@ -91,11 +92,32 @@ export default { }; ``` -When operating in SPA mode, you can omit `config.kit.prerender.default` (or set it to `false`, its default value), and only pages that have the [`prerender`](https://kit.svelte.dev/docs/page-options#prerender) option set will be prerendered at build time. +When operating in SPA mode, you can omit the [`prerender`](https://kit.svelte.dev/docs/page-options#prerender) option from your root layout (or set it to `false`, its default value), and only pages that have the `prerender` option set will be prerendered at build time. + +SvelteKit will still crawl your app's entry points looking for prerenderable pages. If `svelte-kit build` fails because of pages that can't be loaded outside the browser, you can set `config.kit.prerender.entries` to `[]` to prevent this from happening. (Setting `config.kit.prerender.enabled` to `false` also has this effect, but would prevent the fallback page from being generated.) -SvelteKit will still crawl your app's entry points looking for prerenderable pages. If `svelte-kit build` fails because of pages that can't be loaded outside the browser, you can set `config.kit.prerender.entries` to `[]` to prevent this from happening. (Setting `config.kit.prerender.enabled` also has this effect, but would prevent the fallback page from being generated.) +During development, SvelteKit will still attempt to server-side render your routes. This means accessing things that are only available in the browser (such as the `window` object) will result in errors, even though this would be valid in the output app. To align the behavior of SvelteKit's dev mode with your SPA, you can [add `export const ssr = false` to your root `+layout`](https://kit.svelte.dev/docs/page-options#ssr). -> ⚠️ During development, SvelteKit will still attempt to server-side render your routes. This means accessing things that are only available in the browser (such as the `window` object) will result in errors, even though this would be valid in the output app. To align the behavior of SvelteKit's dev mode with your SPA, you can [call `resolve()` with a parameter of `{ssr: false}` inside the `handle()` hook](https://kit.svelte.dev/docs/hooks#handle). +If you want to create a simple SPA with no prerendered routes, the necessary config therefore looks like this: + +```js +// svelte.config.js +import adapter from '@sveltejs/adapter-static'; + +export default { + kit: { + adapter: adapter({ + fallback: '200.html' + }), + prerender: { entries: [] } + } +}; +``` + +```js +// src/routes/+layout.js +export const ssr = false; +``` ## GitHub Pages diff --git a/packages/adapter-static/test/apps/prerendered/src/routes/+layout.js b/packages/adapter-static/test/apps/prerendered/src/routes/+layout.js new file mode 100644 index 000000000000..189f71e2e1b3 --- /dev/null +++ b/packages/adapter-static/test/apps/prerendered/src/routes/+layout.js @@ -0,0 +1 @@ +export const prerender = true; diff --git a/packages/adapter-static/test/apps/prerendered/src/routes/+layout.svelte b/packages/adapter-static/test/apps/prerendered/src/routes/+layout.svelte new file mode 100644 index 000000000000..4fa864ce7aa9 --- /dev/null +++ b/packages/adapter-static/test/apps/prerendered/src/routes/+layout.svelte @@ -0,0 +1 @@ + diff --git a/packages/adapter-static/test/apps/prerendered/svelte.config.js b/packages/adapter-static/test/apps/prerendered/svelte.config.js index b2c66c3eeb9e..20cd2b3ff5b8 100644 --- a/packages/adapter-static/test/apps/prerendered/svelte.config.js +++ b/packages/adapter-static/test/apps/prerendered/svelte.config.js @@ -3,11 +3,7 @@ import adapter from '../../../index.js'; /** @type {import('@sveltejs/kit').Config} */ const config = { kit: { - adapter: adapter(), - - prerender: { - default: true - } + adapter: adapter() } }; diff --git a/packages/kit/src/core/config/index.spec.js b/packages/kit/src/core/config/index.spec.js index da3274f2d384..c324dd347b18 100644 --- a/packages/kit/src/core/config/index.spec.js +++ b/packages/kit/src/core/config/index.spec.js @@ -64,8 +64,8 @@ const get_defaults = (prefix = '') => ({ amp: undefined, appDir: '_app', browser: { - hydrate: true, - router: true + hydrate: undefined, + router: undefined }, csp: { mode: 'auto', @@ -109,7 +109,7 @@ const get_defaults = (prefix = '') => ({ concurrency: 1, crawl: true, createIndexFiles: undefined, - default: false, + default: undefined, enabled: true, entries: ['*'], force: undefined, @@ -249,19 +249,6 @@ test('fails if kit.appDir ends with slash', () => { }, /^config\.kit\.appDir cannot start or end with '\/'. See https:\/\/kit\.svelte\.dev\/docs\/configuration$/); }); -test('fails if browser.hydrate is false and browser.router is true', () => { - assert.throws(() => { - validate_config({ - kit: { - browser: { - hydrate: false, - router: true - } - } - }); - }, /^config\.kit\.browser\.router cannot be true if config\.kit\.browser\.hydrate is false$/); -}); - test('fails if paths.base is not root-relative', () => { assert.throws(() => { validate_config({ diff --git a/packages/kit/src/core/config/options.js b/packages/kit/src/core/config/options.js index 4a619faca6b6..9b4eefd5cf86 100644 --- a/packages/kit/src/core/config/options.js +++ b/packages/kit/src/core/config/options.js @@ -107,14 +107,16 @@ const options = object( return input; }), - browser: validate({ hydrate: true, router: true }, (input, keypath) => { - const value = object({ hydrate: boolean(true), router: boolean(true) })(input, keypath); - if (!value.hydrate && value.router) { - throw new Error( - 'config.kit.browser.router cannot be true if config.kit.browser.hydrate is false' - ); - } - return value; + // TODO: remove this for the 1.0 release + browser: object({ + hydrate: error( + (keypath) => + `${keypath} has been removed. You can set it inside the top level +layout.js instead. See the PR for more information: https://github.com/sveltejs/kit/pull/6197` + ), + router: error( + (keypath) => + `${keypath} has been removed. You can set it inside the top level +layout.js instead. See the PR for more information: https://github.com/sveltejs/kit/pull/6197` + ) }), csp: object({ @@ -226,7 +228,10 @@ const options = object( (keypath) => `${keypath} has been removed — it is now controlled by the trailingSlash option. See https://kit.svelte.dev/docs/configuration#trailingslash` ), - default: boolean(false), + default: error( + (keypath) => + `${keypath} has been removed. You can set it inside the top level +layout.js instead. See the PR for more information: https://github.com/sveltejs/kit/pull/6197` + ), enabled: boolean(true), entries: validate(['*'], (input, keypath) => { if (!Array.isArray(input) || !input.every((page) => typeof page === 'string')) { diff --git a/packages/kit/src/core/prerender/prerender.js b/packages/kit/src/core/prerender/prerender.js index 2cdf7b89d164..52bd4d7bdc32 100644 --- a/packages/kit/src/core/prerender/prerender.js +++ b/packages/kit/src/core/prerender/prerender.js @@ -10,6 +10,7 @@ import { escape_html_attr } from '../../utils/escape.js'; import { logger } from '../utils.js'; import { load_config } from '../config/index.js'; import { affects_path } from '../../utils/routing.js'; +import { get_option } from '../../runtime/server/utils.js'; /** * @typedef {import('types').PrerenderErrorHandler} PrerenderErrorHandler @@ -371,21 +372,12 @@ export async function prerender() { } if (route.page) { - // TODO use setting from layouts, in https://github.com/sveltejs/kit/pull/6197 - // const nodes = await Promise.all( - // [...route.page.layouts, route.page.leaf].map((n) => { - // if (n !== undefined) return manifest._.nodes[n](); - // }) - // ); - - // let prerender = config.prerender.default; - // for (const node of nodes) { - // prerender = node?.shared?.prerender ?? node?.server?.prerender ?? prerender; - // } - - const leaf = await manifest._.nodes[route.page.leaf](); - let prerender = - leaf.shared?.prerender ?? leaf.server?.prerender ?? config.prerender.default; + const nodes = await Promise.all( + [...route.page.layouts, route.page.leaf].map((n) => { + if (n !== undefined) return manifest._.nodes[n](); + }) + ); + const prerender = get_option(nodes, 'prerender') ?? false; prerender_map.set(route.id, prerender); } diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js index 7518965e43c7..231243312c7c 100644 --- a/packages/kit/src/exports/vite/build/build_server.js +++ b/packages/kit/src/exports/vite/build/build_server.js @@ -70,19 +70,13 @@ export class Server { error.stack = this.options.get_stack(error); }, hooks: null, - hydrate: ${s(config.kit.browser.hydrate)}, manifest, method_override: ${s(config.kit.methodOverride)}, paths: { base, assets }, - prerender: { - default: ${config.kit.prerender.default}, - enabled: ${config.kit.prerender.enabled} - }, public_env: {}, read, root, service_worker: ${has_service_worker ? "base + '/service-worker.js'" : 'null'}, - router: ${s(config.kit.browser.router)}, app_template, app_template_contains_nonce: ${template.includes('%sveltekit.nonce%')}, error_template, diff --git a/packages/kit/src/exports/vite/dev/index.js b/packages/kit/src/exports/vite/dev/index.js index cbefff2fb7cc..cc6b0bd23eb1 100644 --- a/packages/kit/src/exports/vite/dev/index.js +++ b/packages/kit/src/exports/vite/dev/index.js @@ -402,21 +402,15 @@ export async function dev(vite, vite_config, svelte_config, illegal_imports) { }); }, hooks, - hydrate: svelte_config.kit.browser.hydrate, manifest, method_override: svelte_config.kit.methodOverride, paths: { base: svelte_config.kit.paths.base, assets }, - prerender: { - default: svelte_config.kit.prerender.default, - enabled: svelte_config.kit.prerender.enabled - }, public_env: env.public, read: (file) => fs.readFileSync(path.join(svelte_config.kit.files.assets, file)), root, - router: svelte_config.kit.browser.router, app_template: ({ head, body, assets, nonce }) => { return ( template diff --git a/packages/kit/src/runtime/server/index.js b/packages/kit/src/runtime/server/index.js index 063ef1975ab8..eaaddfefe48f 100644 --- a/packages/kit/src/runtime/server/index.js +++ b/packages/kit/src/runtime/server/index.js @@ -187,7 +187,6 @@ export async function respond(request, options, state) { /** @type {import('types').RequiredResolveOptions} */ let resolve_opts = { - ssr: true, transformPageChunk: default_transform }; @@ -205,9 +204,14 @@ export async function respond(request, options, state) { 'transformPage has been replaced by transformPageChunk — see https://github.com/sveltejs/kit/pull/5657 for more information' ); } + // @ts-expect-error + if (opts.ssr) { + throw new Error( + 'ssr has been removed, set it in the appropriate +layout.js instead. See the PR for more information: https://github.com/sveltejs/kit/pull/6197' + ); + } resolve_opts = { - ssr: opts.ssr !== false, transformPageChunk: opts.transformPageChunk || default_transform }; } @@ -217,17 +221,14 @@ export async function respond(request, options, state) { event, options, state, - page_config: { router: true, hydrate: true }, + page_config: { router: true, hydrate: true, ssr: false }, status: 200, error: null, branch: [], fetched: [], validation_errors: undefined, cookies: [], - resolve_opts: { - ...resolve_opts, - ssr: false - } + resolve_opts }); } diff --git a/packages/kit/src/runtime/server/page/index.js b/packages/kit/src/runtime/server/page/index.js index 06daf62d85db..2691c0f8e354 100644 --- a/packages/kit/src/runtime/server/page/index.js +++ b/packages/kit/src/runtime/server/page/index.js @@ -2,7 +2,13 @@ import { devalue } from 'devalue'; import { negotiate } from '../../../utils/http.js'; import { render_response } from './render.js'; import { respond_with_error } from './respond_with_error.js'; -import { method_not_allowed, error_to_pojo, allowed_methods, static_error_page } from '../utils.js'; +import { + method_not_allowed, + error_to_pojo, + allowed_methods, + get_option, + static_error_page +} from '../utils.js'; import { create_fetch } from './fetch.js'; import { HttpError, Redirect } from '../../control.js'; import { error, json } from '../../../exports/index.js'; @@ -107,18 +113,14 @@ export async function render_page(event, route, page, options, state, resolve_op // it's crucial that we do this before returning the non-SSR response, otherwise // SvelteKit will erroneously believe that the path has been prerendered, // causing functions to be omitted from the manifesst generated later - // TODO incorporate layout options in https://github.com/sveltejs/kit/pull/6197 - const should_prerender = - leaf_node.shared?.prerender ?? leaf_node.server?.prerender ?? options.prerender.default; + const should_prerender = get_option(nodes, 'prerender') ?? false; if (should_prerender) { const mod = leaf_node.server; if (mod && (mod.POST || mod.PUT || mod.DELETE || mod.PATCH)) { throw new Error('Cannot prerender pages that have mutative methods'); } } else if (state.prerendering) { - // if the page isn't marked as prerenderable (or is explicitly - // marked NOT prerenderable, if `prerender.default` is `true`), - // then bail out at this point + // if the page isn't marked as prerenderable, then bail out at this point return new Response(undefined, { status: 204 }); @@ -132,7 +134,7 @@ export async function render_page(event, route, page, options, state, resolve_op prerender_default: should_prerender }); - if (!resolve_opts.ssr) { + if (get_option(nodes, 'ssr') === false) { return await render_response({ branch: [], validation_errors: undefined, @@ -140,7 +142,8 @@ export async function render_page(event, route, page, options, state, resolve_op cookies, page_config: { hydrate: true, - router: true + router: true, + ssr: false }, status, error: null, @@ -270,7 +273,7 @@ export async function render_page(event, route, page, options, state, resolve_op options, state, resolve_opts, - page_config: { router: true, hydrate: true }, + page_config: { router: true, hydrate: true, ssr: true }, status, error, branch: compact(branch.slice(0, j + 1)).concat({ @@ -319,7 +322,11 @@ export async function render_page(event, route, page, options, state, resolve_op options, state, resolve_opts, - page_config: get_page_config(leaf_node, options), + page_config: { + router: get_option(nodes, 'router') ?? true, + hydrate: get_option(nodes, 'hydrate') ?? true, + ssr: true + }, status, error: null, branch: compact(branch), @@ -343,24 +350,6 @@ export async function render_page(event, route, page, options, state, resolve_op } } -/** - * @param {import('types').SSRNode} leaf - * @param {SSROptions} options - */ -function get_page_config(leaf, options) { - // TODO we can reinstate this now that it's in the module - if (leaf.shared && 'ssr' in leaf.shared) { - throw new Error( - '`export const ssr` has been removed — use the handle hook instead: https://kit.svelte.dev/docs/hooks#handle' - ); - } - - return { - router: leaf.shared?.router ?? options.router, - hydrate: leaf.shared?.hydrate ?? options.hydrate - }; -} - /** * @param {import('types').RequestEvent} event * @param {import('types').SSROptions} options diff --git a/packages/kit/src/runtime/server/page/render.js b/packages/kit/src/runtime/server/page/render.js index 3ee285636ef7..a966268bf0a7 100644 --- a/packages/kit/src/runtime/server/page/render.js +++ b/packages/kit/src/runtime/server/page/render.js @@ -23,7 +23,7 @@ const updated = { * cookies: import('set-cookie-parser').Cookie[]; * options: import('types').SSROptions; * state: import('types').SSRState; - * page_config: { hydrate: boolean, router: boolean }; + * page_config: { hydrate: boolean, router: boolean; ssr: boolean }; * status: number; * error: HttpError | Error | null; * event: import('types').RequestEvent; @@ -74,7 +74,7 @@ export async function render_response({ error.stack = options.get_stack(error); } - if (resolve_opts.ssr) { + if (page_config.ssr) { /** @type {Record} */ const props = { stores: { @@ -209,9 +209,9 @@ export async function render_response({ target: document.querySelector('[data-sveltekit-hydrate="${target}"]').parentNode, paths: ${s(options.paths)}, route: ${!!page_config.router}, - spa: ${!resolve_opts.ssr}, + spa: ${!page_config.ssr}, trailing_slash: ${s(options.trailing_slash)}, - hydrate: ${resolve_opts.ssr && page_config.hydrate ? `{ + hydrate: ${page_config.ssr && page_config.hydrate ? `{ status: ${status}, error: ${error && serialize_error(error, e => e.stack)}, node_ids: [${branch.map(({ node }) => node.index).join(', ')}], @@ -286,7 +286,7 @@ export async function render_response({ body += `\n\t\t`; } - if (resolve_opts.ssr && page_config.hydrate) { + if (page_config.ssr && page_config.hydrate) { /** @type {string[]} */ const serialized_data = []; diff --git a/packages/kit/src/runtime/server/page/respond_with_error.js b/packages/kit/src/runtime/server/page/respond_with_error.js index 50e53ed439c5..658814175172 100644 --- a/packages/kit/src/runtime/server/page/respond_with_error.js +++ b/packages/kit/src/runtime/server/page/respond_with_error.js @@ -1,7 +1,7 @@ import { render_response } from './render.js'; import { load_data, load_server_data } from './load_data.js'; import { coalesce_to_error } from '../../../utils/error.js'; -import { GENERIC_ERROR, static_error_page } from '../utils.js'; +import { GENERIC_ERROR, get_option, static_error_page } from '../utils.js'; import { create_fetch } from './fetch.js'; /** @@ -30,10 +30,10 @@ export async function respond_with_error({ event, options, state, status, error, try { const branch = []; + const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout + const ssr = get_option([default_layout], 'ssr') ?? true; - if (resolve_opts.ssr) { - const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout - + if (ssr) { const server_data_promise = load_server_data({ event, state, @@ -70,8 +70,9 @@ export async function respond_with_error({ event, options, state, status, error, options, state, page_config: { - hydrate: options.hydrate, - router: options.router + hydrate: get_option([default_layout], 'hydrate') ?? true, + router: get_option([default_layout], 'router') ?? true, + ssr }, status, error, diff --git a/packages/kit/src/runtime/server/utils.js b/packages/kit/src/runtime/server/utils.js index 16baabee3edb..d44235e9c704 100644 --- a/packages/kit/src/runtime/server/utils.js +++ b/packages/kit/src/runtime/server/utils.js @@ -136,6 +136,25 @@ export function data_response(data) { } } +/** + * @template {'hydrate' | 'prerender' | 'router' | 'ssr'} Option + * @template {Option extends 'prerender' ? import('types').PrerenderOption : boolean} Value + * + * @param {Array} nodes + * @param {Option} option + * + * @returns {Value | undefined} + */ +export function get_option(nodes, option) { + return nodes.reduce( + (value, node) => + /** @type {any} TypeScript's too dumb to understand this */ ( + node?.shared?.[option] ?? node?.server?.[option] ?? value + ), + /** @type {Value | undefined} */ (undefined) + ); +} + /** * Return as a response that renders the error.html * diff --git a/packages/kit/test/apps/amp/src/routes/+layout.js b/packages/kit/test/apps/amp/src/routes/+layout.js new file mode 100644 index 000000000000..9ed282a3fa1d --- /dev/null +++ b/packages/kit/test/apps/amp/src/routes/+layout.js @@ -0,0 +1,2 @@ +export const hydrate = false; +export const router = false; diff --git a/packages/kit/test/apps/amp/svelte.config.js b/packages/kit/test/apps/amp/svelte.config.js index df407b68f274..18aec126f11f 100644 --- a/packages/kit/test/apps/amp/svelte.config.js +++ b/packages/kit/test/apps/amp/svelte.config.js @@ -1,11 +1,6 @@ /** @type {import('@sveltejs/kit').Config} */ const config = { kit: { - browser: { - router: false, - hydrate: false - }, - inlineStyleThreshold: Infinity } }; diff --git a/packages/kit/test/apps/basics/src/hooks.js b/packages/kit/test/apps/basics/src/hooks.js index fe4b94752d81..b1131b608e07 100644 --- a/packages/kit/test/apps/basics/src/hooks.js +++ b/packages/kit/test/apps/basics/src/hooks.js @@ -33,7 +33,6 @@ export const handle = sequence( } const response = await resolve(event, { - ssr: !event.url.pathname.startsWith('/no-ssr'), transformPageChunk: event.url.pathname.startsWith('/transform-page-chunk') ? ({ html }) => html.replace('__REPLACEME__', 'Worked!') : undefined diff --git a/packages/kit/test/apps/basics/src/routes/no-ssr/+layout.js b/packages/kit/test/apps/basics/src/routes/no-ssr/+layout.js new file mode 100644 index 000000000000..a3d15781a772 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/no-ssr/+layout.js @@ -0,0 +1 @@ +export const ssr = false; diff --git a/packages/kit/test/apps/basics/src/routes/no-ssr/+layout.svelte b/packages/kit/test/apps/basics/src/routes/no-ssr/+layout.svelte new file mode 100644 index 000000000000..0edcae4bf71e --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/no-ssr/+layout.svelte @@ -0,0 +1 @@ +; diff --git a/packages/kit/test/apps/basics/src/routes/no-ssr/browser-only-global/+page.svelte b/packages/kit/test/apps/basics/src/routes/no-ssr/browser-only-global/+page.svelte index 2e48a4f8ebd7..560f8bab641b 100644 --- a/packages/kit/test/apps/basics/src/routes/no-ssr/browser-only-global/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/no-ssr/browser-only-global/+page.svelte @@ -2,4 +2,6 @@ document; +{document} +

Works

diff --git a/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/+page.js b/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/+page.js new file mode 100644 index 000000000000..a3d15781a772 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/+page.js @@ -0,0 +1 @@ +export const ssr = false; diff --git a/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/+page.svelte b/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/+page.svelte new file mode 100644 index 000000000000..560f8bab641b --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/+page.svelte @@ -0,0 +1,7 @@ + + +{document} + +

Works

diff --git a/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/+layout.js b/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/+layout.js new file mode 100644 index 000000000000..a3d15781a772 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/+layout.js @@ -0,0 +1 @@ +export const ssr = false; diff --git a/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/+layout.svelte b/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/+layout.svelte new file mode 100644 index 000000000000..0385342cef1b --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/+layout.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/inherit/+page.svelte b/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/inherit/+page.svelte new file mode 100644 index 000000000000..560f8bab641b --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/inherit/+page.svelte @@ -0,0 +1,7 @@ + + +{document} + +

Works

diff --git a/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/overwrite/+page.js b/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/overwrite/+page.js new file mode 100644 index 000000000000..77ab0a02eb8e --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/overwrite/+page.js @@ -0,0 +1 @@ +export const ssr = true; diff --git a/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/overwrite/+page.svelte b/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/overwrite/+page.svelte new file mode 100644 index 000000000000..b5e77a2d9967 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/no-ssr/ssr-page-config/layout/overwrite/+page.svelte @@ -0,0 +1,7 @@ + + +{document} + +

You shouldn't see this

diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js index 6bd08d9c428c..1762d0c172e2 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -601,10 +601,42 @@ test.describe('Shadow DOM', () => { }); }); -test('Can use browser-only global on client-only page', async ({ page, read_errors }) => { - await page.goto('/no-ssr/browser-only-global'); - await expect(page.locator('p')).toHaveText('Works'); - expect(read_errors('/no-ssr/browser-only-global')).toBe(undefined); +test.describe('SPA mode / no SSR', () => { + test('Can use browser-only global on client-only page through ssr config in handle', async ({ + page, + read_errors + }) => { + await page.goto('/no-ssr/browser-only-global'); + await expect(page.locator('p')).toHaveText('Works'); + expect(read_errors('/no-ssr/browser-only-global')).toBe(undefined); + }); + + test('Can use browser-only global on client-only page through ssr config in layout.js', async ({ + page, + read_errors + }) => { + await page.goto('/no-ssr/ssr-page-config'); + await expect(page.locator('p')).toHaveText('Works'); + expect(read_errors('/no-ssr/ssr-page-config')).toBe(undefined); + }); + + test('Can use browser-only global on client-only page through ssr config in page.js', async ({ + page, + read_errors + }) => { + await page.goto('/no-ssr/ssr-page-config/layout/inherit'); + await expect(page.locator('p')).toHaveText('Works'); + expect(read_errors('/no-ssr/ssr-page-config/layout/inherit')).toBe(undefined); + }); + + test('Cannot use browser-only global on page because of ssr config in page.js', async ({ + page + }) => { + await page.goto('/no-ssr/ssr-page-config/layout/overwrite'); + await expect(page.locator('p')).toHaveText( + 'This is your custom error page saying: "document is not defined"' + ); + }); }); test.describe('$app/stores', () => { diff --git a/packages/kit/test/prerendering/basics/src/routes/+layout.js b/packages/kit/test/prerendering/basics/src/routes/+layout.js new file mode 100644 index 000000000000..189f71e2e1b3 --- /dev/null +++ b/packages/kit/test/prerendering/basics/src/routes/+layout.js @@ -0,0 +1 @@ +export const prerender = true; diff --git a/packages/kit/test/prerendering/basics/src/routes/+layout.svelte b/packages/kit/test/prerendering/basics/src/routes/+layout.svelte new file mode 100644 index 000000000000..4fa864ce7aa9 --- /dev/null +++ b/packages/kit/test/prerendering/basics/src/routes/+layout.svelte @@ -0,0 +1 @@ + diff --git a/packages/kit/test/prerendering/basics/svelte.config.js b/packages/kit/test/prerendering/basics/svelte.config.js index 9f209ad74c6e..d8b65b258145 100644 --- a/packages/kit/test/prerendering/basics/svelte.config.js +++ b/packages/kit/test/prerendering/basics/svelte.config.js @@ -6,7 +6,6 @@ const config = { adapter: adapter(), prerender: { - default: true, onError: 'continue', origin: 'http://example.com' } diff --git a/packages/kit/test/prerendering/options/src/routes/+layout.js b/packages/kit/test/prerendering/options/src/routes/+layout.js new file mode 100644 index 000000000000..189f71e2e1b3 --- /dev/null +++ b/packages/kit/test/prerendering/options/src/routes/+layout.js @@ -0,0 +1 @@ +export const prerender = true; diff --git a/packages/kit/test/prerendering/options/src/routes/+layout.svelte b/packages/kit/test/prerendering/options/src/routes/+layout.svelte new file mode 100644 index 000000000000..4fa864ce7aa9 --- /dev/null +++ b/packages/kit/test/prerendering/options/src/routes/+layout.svelte @@ -0,0 +1 @@ + diff --git a/packages/kit/test/prerendering/options/svelte.config.js b/packages/kit/test/prerendering/options/svelte.config.js index 5a2efdd38fba..2fea28fb6f60 100644 --- a/packages/kit/test/prerendering/options/svelte.config.js +++ b/packages/kit/test/prerendering/options/svelte.config.js @@ -22,10 +22,6 @@ const config = { assets: 'https://cdn.example.com/stuff' }, - prerender: { - default: true - }, - trailingSlash: 'always' } }; diff --git a/packages/kit/test/prerendering/paths-base/src/routes/+layout.js b/packages/kit/test/prerendering/paths-base/src/routes/+layout.js new file mode 100644 index 000000000000..189f71e2e1b3 --- /dev/null +++ b/packages/kit/test/prerendering/paths-base/src/routes/+layout.js @@ -0,0 +1 @@ +export const prerender = true; diff --git a/packages/kit/test/prerendering/paths-base/src/routes/+layout.svelte b/packages/kit/test/prerendering/paths-base/src/routes/+layout.svelte new file mode 100644 index 000000000000..4fa864ce7aa9 --- /dev/null +++ b/packages/kit/test/prerendering/paths-base/src/routes/+layout.svelte @@ -0,0 +1 @@ + diff --git a/packages/kit/test/prerendering/paths-base/svelte.config.js b/packages/kit/test/prerendering/paths-base/svelte.config.js index 98ed3c7c32f3..083606280209 100644 --- a/packages/kit/test/prerendering/paths-base/svelte.config.js +++ b/packages/kit/test/prerendering/paths-base/svelte.config.js @@ -7,10 +7,6 @@ const config = { paths: { base: '/path-base' - }, - - prerender: { - default: true } } }; diff --git a/packages/kit/test/prerendering/trailing-slash/src/routes/+layout.js b/packages/kit/test/prerendering/trailing-slash/src/routes/+layout.js new file mode 100644 index 000000000000..189f71e2e1b3 --- /dev/null +++ b/packages/kit/test/prerendering/trailing-slash/src/routes/+layout.js @@ -0,0 +1 @@ +export const prerender = true; diff --git a/packages/kit/test/prerendering/trailing-slash/src/routes/+layout.svelte b/packages/kit/test/prerendering/trailing-slash/src/routes/+layout.svelte new file mode 100644 index 000000000000..4fa864ce7aa9 --- /dev/null +++ b/packages/kit/test/prerendering/trailing-slash/src/routes/+layout.svelte @@ -0,0 +1 @@ + diff --git a/packages/kit/test/prerendering/trailing-slash/svelte.config.js b/packages/kit/test/prerendering/trailing-slash/svelte.config.js index 41249f6dd2f1..a05f200dfaa4 100644 --- a/packages/kit/test/prerendering/trailing-slash/svelte.config.js +++ b/packages/kit/test/prerendering/trailing-slash/svelte.config.js @@ -9,10 +9,6 @@ const config = { fallback: '200.html' }), - prerender: { - default: true - }, - trailingSlash: 'always' } }; diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index fbfc78033457..ffe84ca00789 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -123,10 +123,6 @@ export interface KitConfig { adapter?: Adapter; alias?: Record; appDir?: string; - browser?: { - hydrate?: boolean; - router?: boolean; - }; csp?: { mode?: 'hash' | 'nonce' | 'auto'; directives?: CspDirectives; @@ -263,7 +259,6 @@ export interface RequestHandler< } export interface ResolveOptions { - ssr?: boolean; transformPageChunk?: (input: { html: string; done: boolean }) => MaybePromise; } diff --git a/packages/kit/types/internal.d.ts b/packages/kit/types/internal.d.ts index 7c229d62e9de..a2897e6cc7bb 100644 --- a/packages/kit/types/internal.d.ts +++ b/packages/kit/types/internal.d.ts @@ -275,11 +275,15 @@ export interface SSRNode { hydrate?: boolean; prerender?: PrerenderOption; router?: boolean; + ssr?: boolean; }; server: { load?: ServerLoad; + hydrate?: boolean; prerender?: PrerenderOption; + router?: boolean; + ssr?: boolean; POST?: Action; PATCH?: Action; PUT?: Action; @@ -298,21 +302,15 @@ export interface SSROptions { get_stack: (error: Error) => string | undefined; handle_error(error: Error & { frame?: string }, event: RequestEvent): void; hooks: Hooks; - hydrate: boolean; manifest: SSRManifest; method_override: MethodOverride; paths: { base: string; assets: string; }; - prerender: { - default: boolean; - enabled: boolean; - }; public_env: Record; read(file: string): Buffer; root: SSRComponent['default']; - router: boolean; service_worker?: string; app_template({ head, diff --git a/sites/kit.svelte.dev/src/routes/+layout.js b/sites/kit.svelte.dev/src/routes/+layout.js new file mode 100644 index 000000000000..189f71e2e1b3 --- /dev/null +++ b/sites/kit.svelte.dev/src/routes/+layout.js @@ -0,0 +1 @@ +export const prerender = true; diff --git a/sites/kit.svelte.dev/svelte.config.js b/sites/kit.svelte.dev/svelte.config.js index e46f95df7b58..301e785eb88c 100644 --- a/sites/kit.svelte.dev/svelte.config.js +++ b/sites/kit.svelte.dev/svelte.config.js @@ -3,11 +3,7 @@ import adapter from '@sveltejs/adapter-auto'; /** @type {import('@sveltejs/kit').Config} */ const config = { kit: { - adapter: adapter(), - - prerender: { - default: true - } + adapter: adapter() } };