Skip to content

Commit 7f958dd

Browse files
authored
Prerender during build (#4192)
* add config.kit.prerender.default * prerender during build * lint * warn if no fallback and default is false * use prerendered pages in svelte-kit preview * make prerendered paths available to service worker * adapters * docs * changesets * lint
1 parent fa66862 commit 7f958dd

Some content is hidden

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

50 files changed

+401
-243
lines changed

.changeset/gorgeous-beans-glow.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] expose entire config to adapters, rather than just appDir and trailingSlash

.changeset/khaki-dolls-cough.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 builder.prerender() with builder.writePrerendered() and builder.prerendered

.changeset/large-berries-exercise.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] prerender pages during build, regardless of adapter

.changeset/modern-toys-appear.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+
Add config.kit.prerender.default option

.changeset/nine-walls-shake.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+
Use prerendered pages in svelte-kit preview

.changeset/shaggy-days-cheat.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+
Make prerendered paths available to service workers

.prettierrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
{
1414
"files": [
1515
"packages/kit/src/packaging/test/fixtures/**/expected/**/*",
16-
"packages/kit/src/core/adapt/prerender/fixtures/**/*"
16+
"packages/kit/src/core/build/prerender/fixtures/**/*"
1717
],
1818
"options": {
1919
"requirePragma": true

documentation/docs/09-adapters.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ The types for `Adapter` and its parameters are available in [types/config.d.ts](
9999
Within the `adapt` method, there are a number of things that an adapter should do:
100100

101101
- Clear out the build directory
102-
- Call `builder.prerender({ dest })` to prerender pages
102+
- Write SvelteKit output with `builder.writeClient`, `builder.writePrerendered`, `builder.writeServer`, and `builder.writeStatic`
103103
- Output code that:
104104
- Imports `App` from `${builder.getServerDirectory()}/app.js`
105105
- Instantiates the app with a manifest generated with `builder.generateManifest({ relativePath })`

documentation/docs/10-page-options.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,24 @@ Ordinarily, SvelteKit [hydrates](/docs/appendix#hydration) your server-rendered
3838

3939
It's likely that at least some pages of your app can be represented as a simple HTML file generated at build time. These pages can be [_prerendered_](/docs/appendix#prerendering) by your [adapter](/docs/adapters).
4040

41-
If your entire app is suitable for prerendering, you could use [`adapter-static`](https://github.com/sveltejs/kit/tree/master/packages/adapter-static), which will generate HTML files for every page, plus additional files that are requested by `load` functions in those pages.
42-
43-
In many cases, you'll only want to prerender specific pages in your app. You'll need to annotate these pages:
41+
Prerendering happens automatically for any page with the `prerender` annotation:
4442

4543
```html
4644
<script context="module">
4745
export const prerender = true;
4846
</script>
4947
```
5048

49+
Alternatively, you can set [`confit.kit.prerender.default`](/docs/configuration#prerender) to `true` and prerender everything except pages that are explicitly marked as _not_ prerenderable:
50+
51+
```html
52+
<script context="module">
53+
export const prerender = false;
54+
</script>
55+
```
56+
57+
> 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.
58+
5159
The prerenderer will start at the root of your app and generate HTML for any prerenderable pages it finds. Each page is scanned for `<a>` 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).
5260

5361
#### When not to prerender

documentation/docs/13-configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ See [Prerendering](/docs/page-options#prerender). An object containing zero or m
229229

230230
- `concurrency` — how many pages can be prerendered simultaneously. JS is single-threaded, but in cases where prerendering performance is network-bound (for example loading content from a remote CMS) this can speed things up by processing other tasks while waiting on the network response
231231
- `crawl` — determines whether SvelteKit should find pages to prerender by following links from the seed page(s)
232+
- `default` — set to `true` to prerender every page without `export const prerender = false`
232233
- `enabled` — set to `false` to disable prerendering altogether
233234
- `entries` — 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]` )
234235
- `onError`

packages/adapter-cloudflare-workers/index.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ export default function () {
2525
builder.rimraf(bucket);
2626
builder.rimraf(entrypoint);
2727

28-
builder.log.info('Prerendering static pages...');
29-
const prerendered = await builder.prerender({ dest: bucket });
30-
3128
builder.log.info('Installing worker dependencies...');
3229
builder.copy(`${files}/_package.json`, `${tmp}/package.json`);
3330

@@ -49,7 +46,7 @@ export default function () {
4946
`${tmp}/manifest.js`,
5047
`export const manifest = ${builder.generateManifest({
5148
relativePath
52-
})};\n\nexport const prerendered = new Set(${JSON.stringify(prerendered.paths)});\n`
49+
})};\n\nexport const prerendered = new Set(${JSON.stringify(builder.prerendered.paths)});\n`
5350
);
5451

5552
await esbuild.build({
@@ -65,6 +62,7 @@ export default function () {
6562
builder.log.minor('Copying assets...');
6663
builder.writeClient(bucket);
6764
builder.writeStatic(bucket);
65+
builder.writePrerendered(bucket);
6866
}
6967
};
7068
}

packages/adapter-cloudflare/index.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,15 @@ export default function (options = {}) {
1818

1919
builder.writeStatic(dest);
2020
builder.writeClient(dest);
21-
22-
const prerendered = await builder.prerender({ dest });
21+
builder.writePrerendered(dest);
2322

2423
const relativePath = posix.relative(tmp, builder.getServerDirectory());
2524

2625
writeFileSync(
2726
`${tmp}/manifest.js`,
2827
`export const manifest = ${builder.generateManifest({
2928
relativePath
30-
})};\n\nexport const prerendered = new Set(${JSON.stringify(prerendered.paths)});\n`
29+
})};\n\nexport const prerendered = new Set(${JSON.stringify(builder.prerendered.paths)});\n`
3130
);
3231

3332
builder.copy(`${files}/worker.js`, `${tmp}/_worker.js`, {

packages/adapter-netlify/index.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,6 @@ export default function ({ split = false } = {}) {
3636

3737
builder.log.minor(`Publishing to "${publish}"`);
3838

39-
builder.log.minor('Prerendering static pages...');
40-
await builder.prerender({
41-
dest: publish
42-
});
43-
4439
builder.writeServer('.netlify/server');
4540

4641
// for esbuild, use ESM
@@ -127,6 +122,7 @@ export default function ({ split = false } = {}) {
127122
builder.log.minor('Copying assets...');
128123
builder.writeStatic(publish);
129124
builder.writeClient(publish);
125+
builder.writePrerendered(publish);
130126

131127
builder.log.minor('Writing redirects...');
132128
const redirect_file = join(publish, '_redirects');
@@ -138,7 +134,7 @@ export default function ({ split = false } = {}) {
138134
builder.copy('_headers', headers_file);
139135
appendFileSync(
140136
headers_file,
141-
`\n\n/${builder.appDir}/*\n cache-control: public\n cache-control: immutable\n cache-control: max-age=31536000\n`
137+
`\n\n/${builder.config.kit.appDir}/*\n cache-control: public\n cache-control: immutable\n cache-control: max-age=31536000\n`
142138
);
143139
}
144140
};

packages/adapter-node/index.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,7 @@ export default function ({
3434
builder.writeClient(`${out}/client`);
3535
builder.writeServer(`${out}/server`);
3636
builder.writeStatic(`${out}/static`);
37-
38-
builder.log.minor('Prerendering static pages');
39-
await builder.prerender({
40-
dest: `${out}/prerendered`
41-
});
37+
builder.writePrerendered(`${out}/prerendered`);
4238

4339
writeFileSync(
4440
`${out}/manifest.js`,

packages/adapter-static/index.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,18 @@ export default function ({ pages = 'build', assets = pages, fallback, precompres
1212
name: '@sveltejs/adapter-static',
1313

1414
async adapt(builder) {
15+
if (!fallback && !builder.config.kit.prerender.default) {
16+
builder.log.warn(
17+
'You should set `config.kit.prerender.default` to `true` if no fallback is specified'
18+
);
19+
}
20+
1521
builder.rimraf(assets);
1622
builder.rimraf(pages);
1723

1824
builder.writeStatic(assets);
1925
builder.writeClient(assets);
20-
21-
await builder.prerender({
22-
fallback,
23-
all: !fallback,
24-
dest: pages
25-
});
26+
builder.writePrerendered(pages, { fallback });
2627

2728
if (precompress) {
2829
if (pages === assets) {

packages/adapter-static/test/apps/prerendered/svelte.config.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ import adapter from '../../../index.js';
33
/** @type {import('@sveltejs/kit').Config} */
44
const config = {
55
kit: {
6-
adapter: adapter()
6+
adapter: adapter(),
7+
8+
prerender: {
9+
default: true
10+
}
711
}
812
};
913

packages/adapter-vercel/index.js

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,6 @@ export default function ({ external = [] } = {}) {
100100
lambda: `${dir}/functions/node/render`
101101
};
102102

103-
builder.log.minor('Prerendering static pages...');
104-
105-
const prerendered = await builder.prerender({
106-
dest: `${dir}/static`
107-
});
108-
109103
builder.log.minor('Generating serverless function...');
110104

111105
const relativePath = posix.relative(tmp, builder.getServerDirectory());
@@ -139,32 +133,36 @@ export default function ({ external = [] } = {}) {
139133

140134
builder.writeStatic(dirs.static);
141135
builder.writeClient(dirs.static);
136+
builder.writePrerendered(dirs.static);
142137

143138
builder.log.minor('Writing routes...');
144139

145140
builder.mkdirp(`${dir}/config`);
146141

147-
const prerendered_pages = Array.from(prerendered.pages, ([src, page]) => ({
142+
const prerendered_pages = Array.from(builder.prerendered.pages, ([src, page]) => ({
148143
src,
149144
dest: page.file
150145
}));
151146

152-
const prerendered_redirects = Array.from(prerendered.redirects, ([src, redirect]) => ({
153-
src,
154-
headers: {
155-
Location: redirect.location
156-
},
157-
status: redirect.status
158-
}));
147+
const prerendered_redirects = Array.from(
148+
builder.prerendered.redirects,
149+
([src, redirect]) => ({
150+
src,
151+
headers: {
152+
Location: redirect.location
153+
},
154+
status: redirect.status
155+
})
156+
);
159157

160158
writeFileSync(
161159
`${dir}/config/routes.json`,
162160
JSON.stringify([
163-
...redirects[builder.trailingSlash],
161+
...redirects[builder.config.kit.trailingSlash],
164162
...prerendered_pages,
165163
...prerendered_redirects,
166164
{
167-
src: `/${builder.appDir}/.+`,
165+
src: `/${builder.config.kit.appDir}/.+`,
168166
headers: {
169167
'cache-control': 'public, immutable, max-age=31536000'
170168
}

packages/kit/src/cli.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as ports from 'port-authority';
55
import { load_config } from './core/config/index.js';
66
import { networkInterfaces, release } from 'os';
77
import { coalesce_to_error } from './utils/error.js';
8+
import { logger } from './core/utils.js';
89

910
/** @param {unknown} e */
1011
function handle_error(e) {
@@ -91,16 +92,18 @@ prog
9192
process.env.NODE_ENV = process.env.NODE_ENV || 'production';
9293
const config = await load_config();
9394

95+
const log = logger({ verbose });
96+
9497
const { build } = await import('./core/build/index.js');
95-
const build_data = await build(config);
98+
const { build_data, prerendered } = await build(config, { log });
9699

97100
console.log(
98101
`\nRun ${colors.bold().cyan('npm run preview')} to preview your production build locally.`
99102
);
100103

101104
if (config.kit.adapter) {
102105
const { adapt } = await import('./core/adapt/index.js');
103-
await adapt(config, build_data, { verbose });
106+
await adapt(config, build_data, prerendered, { log });
104107

105108
// this is necessary to close any open db connections, etc
106109
process.exit(0);

0 commit comments

Comments
 (0)