Skip to content

Commit f1f8d33

Browse files
authored
replace router/hydrate options with csr (#6446)
* replace router/hydrate options with csr - closes #6436 * update template * update docs * fail noisily
1 parent 60d44b6 commit f1f8d33

File tree

34 files changed

+120
-232
lines changed

34 files changed

+120
-232
lines changed

.changeset/sharp-glasses-mix.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
[breaking] replace `router`/`hydrate` page options with `csr`

documentation/docs/00-introduction.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ title: Introduction
1212

1313
SvelteKit is a framework for building extremely high-performance web apps.
1414

15-
Building an app with all the modern best practices is fiendishly complicated. Those practices include [build optimizations](https://vitejs.dev/guide/features.html#build-optimizations), so that you load only the minimal required code; [offline support](/docs/service-workers); [prefetching](/docs/a-options#sveltekit-prefetch) pages before the user initiates navigation; and [configurable rendering](/docs/page-options) that allows you to generate HTML [on the server](/docs/appendix#ssr) or [in the browser](/docs/page-options#router) at runtime or [at build-time](/docs/page-options#prerender). SvelteKit does all the boring stuff for you so that you can get on with the creative part.
15+
Building an app with all the modern best practices is fiendishly complicated. Those practices include [build optimizations](https://vitejs.dev/guide/features.html#build-optimizations), so that you load only the minimal required code; [offline support](/docs/service-workers); [prefetching](/docs/a-options#sveltekit-prefetch) pages before the user initiates navigation; and [configurable rendering](/docs/page-options) that allows you to render your app [on the server](/docs/appendix#ssr) or [in the browser](/docs/appendix#csr) at runtime or [at build-time](/docs/page-options#prerender). SvelteKit does all the boring stuff for you so that you can get on with the creative part.
1616

1717
It uses [Vite](https://vitejs.dev/) with a [Svelte plugin](https://github.com/sveltejs/vite-plugin-svelte) to provide a lightning-fast and feature-rich development experience with [Hot Module Replacement (HMR)](https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/config.md#hot), where changes to your code are reflected in the browser instantly.
1818

documentation/docs/03-routing.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,8 @@ This function runs alongside `+page.svelte`, which means it runs on the server d
7070
As well as `load`, `page.js` can export values that configure the page's behaviour:
7171

7272
- `export const prerender = true` or `false` or `'auto'`
73-
- `export const hydrate = true` or `false`
74-
- `export const router = true` or `false`
7573
- `export const ssr = true` or `false`
74+
- `export const csr = true` or `false`
7675

7776
You can find more information about these in [page options](/docs/page-options).
7877

@@ -111,7 +110,7 @@ export async function load({ params }) {
111110

112111
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).
113112

114-
Like `+page.js`, `+page.server.js` can export [page options](/docs/page-options)`prerender`, `hydrate`, `router` and `ssr`.
113+
Like `+page.js`, `+page.server.js` can export [page options](/docs/page-options)`prerender`, `ssr` and `csr`.
115114

116115
#### Actions
117116

@@ -282,7 +281,7 @@ export function load() {
282281
}
283282
```
284283
285-
If a `+layout.js` exports [page options](/docs/page-options) — `prerender`, `hydrate` `router` and `ssr` — they will be used as defaults for child pages.
284+
If a `+layout.js` exports [page options](/docs/page-options) — `prerender`, `ssr` and `csr` — they will be used as defaults for child pages.
286285
287286
Data returned from a layout's `load` function is also available to all its child pages:
288287
@@ -302,7 +301,7 @@ Data returned from a layout's `load` function is also available to all its child
302301
303302
To run your layout's `load` function on the server, move it to `+layout.server.js`, and change the `LayoutLoad` type to `LayoutServerLoad`.
304303
305-
Like `+layout.js`, `+layout.server.js` can export [page options](/docs/page-options) — `prerender`, `hydrate` `router` and `ssr`.
304+
Like `+layout.js`, `+layout.server.js` can export [page options](/docs/page-options) — `prerender`, `ssr` and `csr`.
306305
307306
### +server
308307

documentation/docs/09-a-options.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ We can mitigate that by _prefetching_ the data. Adding a `data-sveltekit-prefetc
1616

1717
...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.
1818

19-
Note that prefetching will not work if the [`router`](/docs/page-options#router) setting is `false`.
20-
2119
You can also programmatically invoke `prefetch` from `$app/navigation`.
2220

2321
### data-sveltekit-reload

documentation/docs/12-page-options.md

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -68,35 +68,24 @@ For that reason among others, it's recommended that you always include a file ex
6868

6969
For _pages_, we skirt around this problem by writing `foo/index.html` instead of `foo`.
7070

71-
### hydrate
72-
73-
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:
74-
75-
```js
76-
/// file: +page.js
77-
export const hydrate = false;
78-
```
79-
80-
> 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.
81-
82-
### router
71+
Note that this will disable client-side routing for any navigation from this page, regardless of whether the router is already active.
8372

84-
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.
73+
### ssr
8574

86-
In certain circumstances you might need to disable [client-side routing](/docs/appendix#routing) through the `router` export:
75+
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 is unable to be rendered on the server, but in most situations it's not recommended ([see appendix](/docs/appendix#ssr)).
8776

8877
```js
8978
/// file: +page.js
90-
export const router = false;
79+
export const ssr = false;
9180
```
9281

93-
Note that this will disable client-side routing for any navigation from this page, regardless of whether the router is already active.
82+
### csr
9483

95-
### ssr
96-
97-
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)).
84+
Ordinarily, SvelteKit [hydrates](/docs/appendix#hydration) your server-rendered HTML into an interactive client-side-rendered (CSR) page. Some pages don't require JavaScript at all — many blog posts and 'about' pages fall into this category. In these cases you can disable CSR:
9885

9986
```js
10087
/// file: +page.js
101-
export const ssr = false;
88+
export const csr = false;
10289
```
90+
91+
> If both `ssr` and `csr` are `false`, nothing will be rendered!

documentation/docs/17-seo.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,11 @@ const config = {
9999
export default config;
100100
```
101101

102-
...disabling `hydrate` and `router` in your root `+layout.js`/`+layout.server.js`...
102+
...disabling `csr` in your root `+layout.js`/`+layout.server.js`...
103103

104104
```js
105105
/// file: src/routes/+layout.server.js
106-
// the combination of these options
107-
// disables JavaScript
108-
export const hydrate = false;
109-
export const router = false;
106+
export const csr = false;
110107
```
111108

112109
...and transforming the HTML using `transformPageChunk` along with `transform` imported from `@sveltejs/amp`:

packages/create-svelte/templates/default/src/routes/about/+page.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1-
import { browser, dev } from '$app/environment';
1+
import { dev } from '$app/environment';
22

33
// we don't need any JS on this page, though we'll load
44
// it in dev so that we get hot module replacement...
5-
export const hydrate = dev;
6-
7-
// ...but if the client-side router is already loaded
8-
// (i.e. we came here from elsewhere in the app), use it
9-
export const router = browser;
5+
export const csr = dev;
106

117
// since there's no dynamic data here, we can prerender
128
// it so that it gets served as a static asset in prod

packages/kit/src/runtime/client/client.js

Lines changed: 16 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,6 @@ export function create_client({ target, base, trailing_slash }) {
107107
/** @type {import('svelte').SvelteComponent} */
108108
let root;
109109

110-
let router_enabled = true;
111-
112110
// keeping track of the history index in order to prevent popstate navigation events if needed
113111
let current_history_index = history.state?.[INDEX_KEY];
114112

@@ -155,22 +153,18 @@ export function create_client({ target, base, trailing_slash }) {
155153
url = new URL(url, get_base_uri(document));
156154
}
157155

158-
if (router_enabled) {
159-
return navigate({
160-
url,
161-
scroll: noscroll ? scroll_state() : null,
162-
keepfocus,
163-
redirect_chain,
164-
details: {
165-
state,
166-
replaceState
167-
},
168-
accepted: () => {},
169-
blocked: () => {}
170-
});
171-
}
172-
173-
await native_navigation(url);
156+
return navigate({
157+
url,
158+
scroll: noscroll ? scroll_state() : null,
159+
keepfocus,
160+
redirect_chain,
161+
details: {
162+
state,
163+
replaceState
164+
},
165+
accepted: () => {},
166+
blocked: () => {}
167+
});
174168
}
175169

176170
/** @param {URL} url */
@@ -241,15 +235,7 @@ export function create_client({ target, base, trailing_slash }) {
241235
routeId: null
242236
});
243237
} else {
244-
if (router_enabled) {
245-
goto(new URL(navigation_result.location, url).href, {}, [
246-
...redirect_chain,
247-
url.pathname
248-
]);
249-
} else {
250-
await native_navigation(new URL(navigation_result.location, location.href));
251-
}
252-
238+
goto(new URL(navigation_result.location, url).href, {}, [...redirect_chain, url.pathname]);
253239
return false;
254240
}
255241
} else if (navigation_result.props?.page?.status >= 400) {
@@ -354,9 +340,6 @@ export function create_client({ target, base, trailing_slash }) {
354340
page = navigation_result.props.page;
355341
}
356342

357-
const leaf_node = navigation_result.state.branch[navigation_result.state.branch.length - 1];
358-
router_enabled = leaf_node?.node.shared?.router !== false;
359-
360343
if (callback) callback();
361344

362345
updating = false;
@@ -398,10 +381,8 @@ export function create_client({ target, base, trailing_slash }) {
398381
});
399382
}
400383

401-
if (router_enabled) {
402-
const navigation = { from: null, to: new URL(location.href) };
403-
callbacks.after_navigate.forEach((fn) => fn(navigation));
404-
}
384+
const navigation = { from: null, to: new URL(location.href) };
385+
callbacks.after_navigate.forEach((fn) => fn(navigation));
405386

406387
started = true;
407388
}
@@ -1185,8 +1166,6 @@ export function create_client({ target, base, trailing_slash }) {
11851166

11861167
/** @param {MouseEvent} event */
11871168
addEventListener('click', (event) => {
1188-
if (!router_enabled) return;
1189-
11901169
// Adapted from https://github.com/visionmedia/page.js
11911170
// MIT license https://github.com/visionmedia/page.js#license
11921171
if (event.button || event.which !== 1) return;
@@ -1256,7 +1235,7 @@ export function create_client({ target, base, trailing_slash }) {
12561235
});
12571236

12581237
addEventListener('popstate', (event) => {
1259-
if (event.state && router_enabled) {
1238+
if (event.state) {
12601239
// if a popstate-driven navigation is cancelled, we need to counteract it
12611240
// with history.go, which means we end up back here, hence this check
12621241
if (event.state[INDEX_KEY] === current_history_index) return;
Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,11 @@
11
import { create_client } from './client.js';
22
import { init } from './singletons.js';
33
import { set_paths } from '../paths.js';
4-
5-
export { set_public_env } from '../env-public.js';
4+
import { set_public_env } from '../env-public.js';
65

76
/**
87
* @param {{
9-
* paths: {
10-
* assets: string;
11-
* base: string;
12-
* },
13-
* target: Element;
14-
* route: boolean;
15-
* spa: boolean;
16-
* trailing_slash: import('types').TrailingSlash;
8+
* env: Record<string, string>;
179
* hydrate: {
1810
* status: number;
1911
* error: Error | (import('../server/page/types').SerializedHttpError);
@@ -23,26 +15,33 @@ export { set_public_env } from '../env-public.js';
2315
* data: Array<import('types').ServerDataNode | null>;
2416
* errors: Record<string, any> | null;
2517
* };
18+
* paths: {
19+
* assets: string;
20+
* base: string;
21+
* },
22+
* target: Element;
23+
* trailing_slash: import('types').TrailingSlash;
2624
* }} opts
2725
*/
28-
export async function start({ paths, target, route, spa, trailing_slash, hydrate }) {
26+
export async function start({ env, hydrate, paths, target, trailing_slash }) {
27+
set_public_env(env);
28+
set_paths(paths);
29+
2930
const client = create_client({
3031
target,
3132
base: paths.base,
3233
trailing_slash
3334
});
3435

3536
init({ client });
36-
set_paths(paths);
3737

3838
if (hydrate) {
3939
await client._hydrate(hydrate);
40+
} else {
41+
client.goto(location.href, { replaceState: true });
4042
}
4143

42-
if (route) {
43-
if (spa) client.goto(location.href, { replaceState: true });
44-
client._start_router();
45-
}
44+
client._start_router();
4645

4746
dispatchEvent(new CustomEvent('sveltekit:start'));
4847
}

packages/kit/src/runtime/server/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ export async function respond(request, options, state) {
221221
event,
222222
options,
223223
state,
224-
page_config: { router: true, hydrate: true, ssr: false },
224+
page_config: { ssr: false, csr: true },
225225
status: 200,
226226
error: null,
227227
branch: [],

0 commit comments

Comments
 (0)