Skip to content

Commit

Permalink
Change config prerender.force to prerender.onError
Browse files Browse the repository at this point in the history
fixes sveltejs#1940

- Changing from `force` to `onError` gives a somewhat more descriptive
  name to the option.
- Using the strings "fail" and "continue" further clarifies what the
  option does.
- Providing your own function to deal with an error allows for
  fine-tuning which errors fail the build and which do not.

The original ticket suggested that the custom function return a boolean,
but after seeing the implementation of the error handler in svelteKit, I
thought it more fitting to just allow it the exact same API: throw if
you want the build to fail.
  • Loading branch information
happycollision committed Jul 27, 2021
1 parent 68c3906 commit b0addbf
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/tame-guests-collect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

Remove the `prerender.force` option in favor of `prerender.onError`
27 changes: 25 additions & 2 deletions documentation/docs/14-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const config = {
prerender: {
crawl: true,
enabled: true,
force: false,
onError: 'fail',
pages: ['*']
},
router: true,
Expand Down Expand Up @@ -148,7 +148,30 @@ See [Prerendering](#ssr-and-javascript-prerender). An object containing zero or

- `crawl` — determines whether SvelteKit should find pages to prerender by following links from the seed page(s)
- `enabled` — set to `false` to disable prerendering altogether
- `force` — if `true`, a page that fails to render will _not_ cause the entire build to fail
- `onError`

- `'fail'` — (default) fails the build when a routing error is encountered when following a link
- `'continue'` — allows the build to continue, despite routing errors
- `function` — custom error handler allowing you to log, `throw` and fail the build, or take other action of your choosing based on the details of the crawl

```ts
/** @type {import('@sveltejs/kit').PrerenderErrorHandler} */
const handleError = ({ status, path, referrer, referenceType }) => {
if (path.startsWith('/blog')) throw new Error('Missing a blog page!');
console.warn(`${status} ${path}${referrer ? ` (${referenceType} from ${referrer})` : ''}`);
};

export default {
kit: {
adapter: static(),
target: '#svelte',
prerender: {
onError: handleError
}
}
};
```

- `pages`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]` )

### router
Expand Down
51 changes: 38 additions & 13 deletions packages/kit/src/core/adapt/prerender.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import { mkdirp } from '../filesystem/index.js';
import { __fetch_polyfill } from '../../install-fetch.js';
import { SVELTE_KIT } from '../constants.js';

/**
* @typedef {import('types/config').PrerenderErrorHandler} PrerenderErrorHandler
* @typedef {import('types/config').ValidatedConfig['kit']['prerender']['onError']} OnErrorConfig
* @typedef {import('types/internal').Logger} Logger
*/

/** @param {string} html */
function clean_html(html) {
return html
Expand Down Expand Up @@ -45,13 +51,34 @@ function get_srcset_urls(attrs) {
return results;
}

/** @type {(errorDetails: Parameters<PrerenderErrorHandler>[0] ) => string} */
function errorDetailsToString({ status, path, referrer, referenceType }) {
return `${status} ${path}${referrer ? ` (${referenceType} from ${referrer})` : ''}`;
}

/** @type {(log: Logger, onError: OnErrorConfig) => PrerenderErrorHandler} */
function chooseErrorHandler(log, onError) {
switch (onError) {
case 'continue':
return (errorDetails) => {
log.error(errorDetailsToString(errorDetails));
};
case 'fail':
return (errorDetails) => {
throw new Error(errorDetailsToString(errorDetails));
};
default:
return onError;
}
}

const OK = 2;
const REDIRECT = 3;

/** @param {{
* cwd: string;
* out: string;
* log: import('types/internal').Logger;
* log: Logger;
* config: import('types/config').ValidatedConfig;
* build_data: import('types/internal').BuildData;
* fallback?: string;
Expand All @@ -75,14 +102,7 @@ export async function prerender({ cwd, out, log, config, build_data, fallback, a
read: (file) => readFileSync(join(config.kit.files.assets, file))
});

/** @type {(status: number, path: string, parent: string | null, verb: string) => void} */
const error = config.kit.prerender.force
? (status, path, parent, verb) => {
log.error(`${status} ${path}${parent ? ` (${verb} from ${parent})` : ''}`);
}
: (status, path, parent, verb) => {
throw new Error(`${status} ${path}${parent ? ` (${verb} from ${parent})` : ''}`);
};
const error = chooseErrorHandler(log, config.kit.prerender.onError);

const files = new Set([...build_data.static, ...build_data.client]);

Expand All @@ -107,9 +127,9 @@ export async function prerender({ cwd, out, log, config, build_data, fallback, a

/**
* @param {string} path
* @param {string?} parent
* @param {string?} referrer
*/
async function visit(path, parent) {
async function visit(path, referrer) {
path = normalize(path);

if (seen.has(path)) return;
Expand Down Expand Up @@ -162,7 +182,7 @@ export async function prerender({ cwd, out, log, config, build_data, fallback, a
log.info(`${rendered.status} ${path}`);
writeFileSync(file, rendered.body || '');
} else if (response_type !== OK) {
error(rendered.status, path, parent, 'linked');
error({ status: rendered.status, path, referrer, referenceType: 'linked' });
}

dependencies.forEach((result, dependency_path) => {
Expand All @@ -183,7 +203,12 @@ export async function prerender({ cwd, out, log, config, build_data, fallback, a
if (response_type === OK) {
log.info(`${result.status} ${dependency_path}`);
} else {
error(result.status, dependency_path, path, 'fetched');
error({
status: result.status,
path: dependency_path,
referrer: path,
referenceType: 'fetched'
});
}
});

Expand Down
4 changes: 2 additions & 2 deletions packages/kit/src/core/config/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ test('fills in defaults', () => {
prerender: {
crawl: true,
enabled: true,
force: false,
onError: 'fail',
pages: ['*']
},
router: true,
Expand Down Expand Up @@ -150,7 +150,7 @@ test('fills in partial blanks', () => {
prerender: {
crawl: true,
enabled: true,
force: false,
onError: 'fail',
pages: ['*']
},
router: true,
Expand Down
12 changes: 11 additions & 1 deletion packages/kit/src/core/config/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,17 @@ const options = {
children: {
crawl: expect_boolean(true),
enabled: expect_boolean(true),
force: expect_boolean(false),
onError: {
type: 'leaf',
default: 'fail',
validate: (option, keypath) => {
if (typeof option === 'function') return option;
if (['continue', 'fail'].includes(option)) return option;
throw new Error(
`${keypath} should be either a custom function or one of "continue" or "fail"`
);
}
},
pages: {
type: 'leaf',
default: ['*'],
Expand Down
2 changes: 1 addition & 1 deletion packages/kit/src/core/config/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ async function testLoadDefaultConfig(path) {
exclude: []
},
paths: { base: '', assets: '/.' },
prerender: { crawl: true, enabled: true, force: false, pages: ['*'] },
prerender: { crawl: true, enabled: true, onError: 'fail', pages: ['*'] },
router: true,
ssr: true,
target: null,
Expand Down
9 changes: 8 additions & 1 deletion packages/kit/types/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ export type Config = {
preprocess?: any;
};

export type PrerenderErrorHandler = (errorDetails: {
status: number;
path: string;
referrer: string | null;
referenceType: 'linked' | 'fetched';
}) => void | never;

export type ValidatedConfig = {
compilerOptions: any;
extensions: string[];
Expand Down Expand Up @@ -117,7 +124,7 @@ export type ValidatedConfig = {
prerender: {
crawl: boolean;
enabled: boolean;
force: boolean;
onError: 'fail' | 'continue' | PrerenderErrorHandler;
pages: string[];
};
router: boolean;
Expand Down
2 changes: 1 addition & 1 deletion packages/kit/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import './ambient-modules';

export { Adapter, AdapterUtils, Config, ValidatedConfig } from './config';
export { Adapter, AdapterUtils, Config, ValidatedConfig, PrerenderErrorHandler } from './config';
export { EndpointOutput, RequestHandler } from './endpoint';
export { ErrorLoad, ErrorLoadInput, Load, LoadInput, LoadOutput, Page } from './page';
export {
Expand Down

0 comments on commit b0addbf

Please sign in to comment.