Skip to content

Commit 4843de3

Browse files
[feat] more info about prerendering errors and new strict option (#7264)
* [fix] more info about prerendering errors Helps with #7183 and #7244 * Apply suggestions from code review * swap ternary around, remove dead code * small tweak * another minor tweak * drive-by-fix * tweak when prerender.entries suggestion appears * tweak * add strict option * Apply suggestions from code review Co-authored-by: Rich Harris <[email protected]> Co-authored-by: Rich Harris <[email protected]>
1 parent e33f77e commit 4843de3

File tree

10 files changed

+50
-14
lines changed

10 files changed

+50
-14
lines changed

.changeset/tame-bats-tell.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@sveltejs/adapter-static': patch
3+
'@sveltejs/kit': patch
4+
---
5+
6+
[feat] more info about prerendering errors, add strict option to adapter-static

documentation/docs/13-page-options.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,11 @@ Note that this will disable client-side routing for any navigation from this pag
7474

7575
#### Troubleshooting
7676

77-
If you encounter an error like 'The following routes were marked as prerenderable, but were not prerendered' it's because the route in question (or a parent layout, if it's a page) has `export const prerender = true` but the page wasn't actually prerendered.
77+
If you encounter an error like 'The following routes were marked as prerenderable, but were not prerendered' it's because the route in question (or a parent layout, if it's a page) has `export const prerender = true` but the page wasn't actually prerendered, because it wasn't reached by the prerendering crawler.
7878

7979
Since these routes cannot be dynamically server-rendered, this will cause errors when people try to access the route in question. There are two ways to fix it:
8080

81-
* Ensure that SvelteKit can find the route by following links from [`config.kit.prerender.entries`](/docs/configuration#prerender). The pages containing the links (e.g. your `/` page) must _themselves_ be prerenderable, or they will be ignored
81+
* Ensure that SvelteKit can find the route by following links from [`config.kit.prerender.entries`](/docs/configuration#prerender). Add links to dynamic routes (i.e. pages with `[parameters]` ) to this option if they are not found through crawling the other entry points, else they are not prerendered because SvelteKit doesn't know what value the parameters should have. Pages not marked as prerenderable will be ignored and their links to other pages will not be crawled, even if some of them would be prerenderable.
8282
* Change `export const prerender = true` to `export const prerender = 'auto'`. Routes with `'auto'` can be dynamically server rendered
8383

8484
### ssr

documentation/docs/16-configuration.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ See [Prerendering](/docs/page-options#prerender). An object containing zero or m
252252
- `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
253253
- `crawl` — determines whether SvelteKit should find pages to prerender by following links from the seed page(s)
254254
- `enabled` — set to `false` to disable prerendering altogether
255-
- `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]` )
255+
- `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]`, because SvelteKit doesn't know what value the parameters should have)
256256
- `onError`
257257

258258
- `'fail'` — (default) fails the build when a routing error is encountered when following a link

packages/adapter-static/README.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ export default {
1818
pages: 'build',
1919
assets: 'build',
2020
fallback: null,
21-
precompress: false
21+
precompress: false,
22+
strict: true
2223
})
2324
}
2425
};
@@ -71,6 +72,10 @@ Specify a fallback page for SPA mode, e.g. `index.html` or `200.html` or `404.ht
7172

7273
If `true`, precompresses files with brotli and gzip. This will generate `.br` and `.gz` files.
7374

75+
### strict
76+
77+
By default, `adapter-static` checks that either all pages and endpoints (if any) of your app were prerendered, or you have the `fallback` option set. This check exists to prevent you from accidentally publishing an app where some parts of it are not accessible, because they are not contained in the final output. If you know this is ok (for example when a certain page only exists conditionally), you can set `strict` to `false` to turn off this check.
78+
7479
## SPA mode
7580

7681
You can use `adapter-static` to create a single-page app or SPA by specifying a **fallback page**.

packages/adapter-static/index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export interface AdapterOptions {
55
assets?: string;
66
fallback?: string;
77
precompress?: boolean;
8+
strict?: boolean;
89
}
910

1011
export default function plugin(options?: AdapterOptions): Adapter;

packages/adapter-static/index.js

+23-5
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,31 @@ export default function (options) {
2424
};
2525
});
2626

27-
if (dynamic_routes.length > 0) {
27+
if (dynamic_routes.length > 0 && options.strict) {
2828
const prefix = path.relative('.', builder.config.kit.files.routes);
29+
const has_param_routes = dynamic_routes.some((route) => route.includes('['));
30+
const config_option =
31+
has_param_routes || JSON.stringify(builder.config.kit.prerender.entries) !== '["*"]'
32+
? ` - adjust the \`prerender.entries\` config option ${
33+
has_param_routes
34+
? '(routes with parameters are not part of entry points by default)'
35+
: ''
36+
} — see https://kit.svelte.dev/docs/configuration#prerender for more info.`
37+
: '';
38+
2939
builder.log.error(
30-
`@sveltejs/adapter-static: all routes must be fully prerenderable (unless using the 'fallback' option — see https://github.com/sveltejs/kit/tree/master/packages/adapter-static#spa-mode). Try adding \`export const prerender = true\` to your root +layout.js/.ts file — see https://kit.svelte.dev/docs/page-options#prerender for more details`
31-
);
32-
builder.log.error(
33-
dynamic_routes.map((id) => ` - ${path.posix.join(prefix, id)}`).join('\n')
40+
`@sveltejs/adapter-static: all routes must be fully prerenderable, but found the following routes that are dynamic:
41+
${dynamic_routes.map((id) => ` - ${path.posix.join(prefix, id)}`).join('\n')}
42+
43+
You have the following options:
44+
- set the \`fallback\` option — see https://github.com/sveltejs/kit/tree/master/packages/adapter-static#spa-mode for more info.
45+
- add \`export const prerender = true\` to your root \`+layout.js/.ts\` or \`+layout.server.js/.ts\` file. This will try to prerender all pages.
46+
- add \`export const prerender = true\` to any \`+server.js/ts\` files that are not fetched by page \`load\` functions.
47+
${config_option}
48+
- pass \`strict: false\` to \`adapter-static\` to ignore this error. Only do this if you are sure you don't need the routes in question in your final app, as they will be unavailable. See https://github.com/sveltejs/kit/tree/master/packages/adapter-static#strict for more info.
49+
50+
If this doesn't help, you may need to use a different adapter. @sveltejs/adapter-static can only be used for sites that don't need a server for dynamic rendering, and can run on just a static file server.
51+
See https://kit.svelte.dev/docs/page-options#prerender for more details`
3452
);
3553
throw new Error('Encountered dynamic routes');
3654
}

packages/kit/src/core/adapt/builder.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@ export function create_builder({ config, build_data, routes, prerendered, log })
3333
async createEntries(fn) {
3434
/** @type {import('types').RouteDefinition[]} */
3535
const facades = routes.map((route) => {
36+
/** @type {Set<import('types').HttpMethod>} */
3637
const methods = new Set();
3738

3839
if (route.page) {
39-
methods.add('SET');
40+
methods.add('GET');
4041
}
4142

4243
if (route.endpoint) {

packages/kit/src/core/prerender/prerender.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -431,9 +431,9 @@ export async function prerender() {
431431

432432
if (not_prerendered.length > 0) {
433433
throw new Error(
434-
`The following routes were marked as prerenderable, but were not prerendered:\n${not_prerendered.map(
434+
`The following routes were marked as prerenderable, but were not prerendered because they were not found while crawling your app:\n${not_prerendered.map(
435435
(id) => ` - ${id}`
436-
)}\n\nSee https://kit.svelte.dev/docs/page-options#prerender-troubleshooting for more info`
436+
)}\n\nSee https://kit.svelte.dev/docs/page-options#prerender-troubleshooting for info on how to solve this`
437437
);
438438
}
439439

packages/kit/src/utils/filesystem.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ export function mkdirp(dir) {
66
try {
77
fs.mkdirSync(dir, { recursive: true });
88
} catch (/** @type {any} */ e) {
9-
if (e.code === 'EEXIST') return;
9+
if (e.code === 'EEXIST') {
10+
if (!fs.statSync(dir).isDirectory()) {
11+
throw new Error(`Cannot create directory ${dir}, a file already exists at this position`);
12+
}
13+
return;
14+
}
1015
throw e;
1116
}
1217
}

packages/kit/test/build-errors/prerender.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ test('prerenderable routes must be prerendered', () => {
1111
stdio: 'pipe',
1212
timeout: 15000
1313
}),
14-
/The following routes were marked as prerenderable, but were not prerendered:\r?\n - \[x\]/gs
14+
/The following routes were marked as prerenderable, but were not prerendered because they were not found while crawling your app:\r?\n - \[x\]/gs
1515
);
1616
});
1717

0 commit comments

Comments
 (0)