From 16b29bc91fd0f4190e570b5caa0a51bb55c9ff25 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 11:31:50 -0400 Subject: [PATCH 01/16] move some logic around --- packages/kit/src/core/adapt/builder.js | 72 ++++++++------------- packages/kit/src/core/adapt/builder.spec.js | 1 + packages/kit/src/core/adapt/index.js | 20 +++++- 3 files changed, 48 insertions(+), 45 deletions(-) diff --git a/packages/kit/src/core/adapt/builder.js b/packages/kit/src/core/adapt/builder.js index e434d947fae7..b79fb68d7a93 100644 --- a/packages/kit/src/core/adapt/builder.js +++ b/packages/kit/src/core/adapt/builder.js @@ -5,57 +5,21 @@ import { pipeline } from 'stream'; import { promisify } from 'util'; import { copy, rimraf, mkdirp } from '../../utils/filesystem.js'; import { generate_manifest } from '../generate_manifest/index.js'; -import { get_path } from '../../utils/routing.js'; + +const pipe = promisify(pipeline); /** * Creates the Builder which is passed to adapters for building the application. * @param {{ * config: import('types').ValidatedConfig; * build_data: import('types').BuildData; + * routes: import('types').RouteData[]; * prerendered: import('types').Prerendered; * log: import('types').Logger; * }} opts * @returns {import('types').Builder} */ -export function create_builder({ config, build_data, prerendered, log }) { - /** @type {Set} */ - const prerendered_paths = new Set(prerendered.paths); - - /** @param {import('types').RouteData} route */ - // TODO routes should come pre-filtered - function not_prerendered(route) { - const path = route.page && get_path(route.id); - if (path) { - return !prerendered_paths.has(path) && !prerendered_paths.has(path + '/'); - } - - return true; - } - - const pipe = promisify(pipeline); - - /** - * @param {string} file - * @param {'gz' | 'br'} format - */ - async function compress_file(file, format = 'gz') { - const compress = - format == 'br' - ? zlib.createBrotliCompress({ - params: { - [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT, - [zlib.constants.BROTLI_PARAM_QUALITY]: zlib.constants.BROTLI_MAX_QUALITY, - [zlib.constants.BROTLI_PARAM_SIZE_HINT]: statSync(file).size - } - }) - : zlib.createGzip({ level: zlib.constants.Z_BEST_COMPRESSION }); - - const source = createReadStream(file); - const destination = createWriteStream(`${file}.${format}`); - - await pipe(source, compress, destination); - } - +export function create_builder({ config, build_data, routes, prerendered, log }) { return { log, rimraf, @@ -66,8 +30,6 @@ export function create_builder({ config, build_data, prerendered, log }) { prerendered, async createEntries(fn) { - const { routes } = build_data.manifest_data; - /** @type {import('types').RouteDefinition[]} */ const facades = routes.map((route) => { const methods = new Set(); @@ -113,7 +75,7 @@ export function create_builder({ config, build_data, prerendered, log }) { } } - const filtered = new Set(group.filter(not_prerendered)); + const filtered = new Set(group); // heuristic: if /foo/[bar] is included, /foo/[bar].json should // also be included, since the page likely needs the endpoint @@ -146,7 +108,7 @@ export function create_builder({ config, build_data, prerendered, log }) { return generate_manifest({ build_data, relative_path: relativePath, - routes: build_data.manifest_data.routes.filter(not_prerendered), + routes, format }); }, @@ -221,3 +183,25 @@ export function create_builder({ config, build_data, prerendered, log }) { } }; } + +/** + * @param {string} file + * @param {'gz' | 'br'} format + */ +async function compress_file(file, format = 'gz') { + const compress = + format == 'br' + ? zlib.createBrotliCompress({ + params: { + [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT, + [zlib.constants.BROTLI_PARAM_QUALITY]: zlib.constants.BROTLI_MAX_QUALITY, + [zlib.constants.BROTLI_PARAM_SIZE_HINT]: statSync(file).size + } + }) + : zlib.createGzip({ level: zlib.constants.Z_BEST_COMPRESSION }); + + const source = createReadStream(file); + const destination = createWriteStream(`${file}.${format}`); + + await pipe(source, compress, destination); +} diff --git a/packages/kit/src/core/adapt/builder.spec.js b/packages/kit/src/core/adapt/builder.spec.js index 2f2c82f4a78f..af35cc19fd51 100644 --- a/packages/kit/src/core/adapt/builder.spec.js +++ b/packages/kit/src/core/adapt/builder.spec.js @@ -29,6 +29,7 @@ test('copy files', () => { config: /** @type {import('types').ValidatedConfig} */ (mocked), // @ts-expect-error build_data: {}, + routes: [], // @ts-expect-error prerendered: { paths: [] diff --git a/packages/kit/src/core/adapt/index.js b/packages/kit/src/core/adapt/index.js index 25d02039f065..9159ba18d7d8 100644 --- a/packages/kit/src/core/adapt/index.js +++ b/packages/kit/src/core/adapt/index.js @@ -1,4 +1,5 @@ import colors from 'kleur'; +import { get_path } from '../../utils/routing.js'; import { create_builder } from './builder.js'; /** @@ -12,7 +13,24 @@ export async function adapt(config, build_data, prerendered, { log }) { console.log(colors.bold().cyan(`\n> Using ${name}`)); - const builder = create_builder({ config, build_data, prerendered, log }); + /** @type {Set} */ + const prerendered_paths = new Set(prerendered.paths); + + const builder = create_builder({ + config, + build_data, + routes: build_data.manifest_data.routes.filter((route) => { + // TODO do this analysis during prerendering — figure out which routes were `prerender = false` or `prerender = 'auto'` + const path = route.page && get_path(route.id); + if (path) { + return !prerendered_paths.has(path) && !prerendered_paths.has(path + '/'); + } + + return true; + }), + prerendered, + log + }); await adapt(builder); log.success('done'); From 9265fea2cbc151f671596e1a1692f7516a97d20d Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 11:38:11 -0400 Subject: [PATCH 02/16] simplify some stuff --- packages/kit/src/core/prerender/prerender.js | 26 +++++++++----------- packages/kit/src/exports/vite/index.js | 1 - 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/packages/kit/src/core/prerender/prerender.js b/packages/kit/src/core/prerender/prerender.js index 5c89fd3e837f..b1356109fb71 100644 --- a/packages/kit/src/core/prerender/prerender.js +++ b/packages/kit/src/core/prerender/prerender.js @@ -17,7 +17,7 @@ import { get_path } from '../../utils/routing.js'; * @typedef {import('types').Logger} Logger */ -const [, , client_out_dir, results_path, manifest_path, verbose, env] = process.argv; +const [, , client_out_dir, results_path, verbose, env] = process.argv; prerender(); @@ -340,25 +340,21 @@ export async function prerender() { } } - if (config.prerender.enabled) { - for (const entry of config.prerender.entries) { - if (entry === '*') { - /** @type {import('types').SSRManifest} */ - const manifest = (await import(pathToFileURL(manifest_path).href)).manifest; - const { routes } = manifest._; - const entries = compact(routes.map((route) => route.page && get_path(route.id))); + for (const entry of config.prerender.entries) { + if (entry === '*') { + const { routes } = manifest._; + const entries = compact(routes.map((route) => route.page && get_path(route.id))); - for (const entry of entries) { - enqueue(null, config.paths.base + entry); // TODO can we pre-normalize these? - } - } else { - enqueue(null, config.paths.base + entry); + for (const entry of entries) { + enqueue(null, config.paths.base + entry); // TODO can we pre-normalize these? } + } else { + enqueue(null, config.paths.base + entry); } - - await q.done(); } + await q.done(); + const rendered = await server.respond(new Request(config.prerender.origin + '/[fallback]'), { getClientAddress, prerendering: { diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index ecdcc7d3e887..a97a2bdfe2d3 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -412,7 +412,6 @@ function kit() { [ vite_config.build.outDir, results_path, - manifest_path, '' + verbose, JSON.stringify({ ...env.private, ...env.public }) ], From 23e00b6e4d1afb121fb3baa935851e1e8d84e947 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 13:42:37 -0400 Subject: [PATCH 03/16] determine prerenderability more accurately --- packages/kit/src/core/adapt/index.js | 21 +++--- packages/kit/src/core/prerender/prerender.js | 73 ++++++++++++++++---- packages/kit/src/exports/vite/index.js | 11 ++- packages/kit/src/utils/routing.js | 9 --- packages/kit/types/internal.d.ts | 4 +- packages/kit/types/private.d.ts | 2 + 6 files changed, 84 insertions(+), 36 deletions(-) diff --git a/packages/kit/src/core/adapt/index.js b/packages/kit/src/core/adapt/index.js index 9159ba18d7d8..9be11c22807e 100644 --- a/packages/kit/src/core/adapt/index.js +++ b/packages/kit/src/core/adapt/index.js @@ -1,32 +1,29 @@ import colors from 'kleur'; -import { get_path } from '../../utils/routing.js'; import { create_builder } from './builder.js'; /** * @param {import('types').ValidatedConfig} config * @param {import('types').BuildData} build_data * @param {import('types').Prerendered} prerendered + * @param {import('types').PrerenderMap} prerender_map * @param {{ log: import('types').Logger }} opts */ -export async function adapt(config, build_data, prerendered, { log }) { +export async function adapt(config, build_data, prerendered, prerender_map, { log }) { const { name, adapt } = config.kit.adapter; console.log(colors.bold().cyan(`\n> Using ${name}`)); - /** @type {Set} */ - const prerendered_paths = new Set(prerendered.paths); - const builder = create_builder({ config, build_data, routes: build_data.manifest_data.routes.filter((route) => { - // TODO do this analysis during prerendering — figure out which routes were `prerender = false` or `prerender = 'auto'` - const path = route.page && get_path(route.id); - if (path) { - return !prerendered_paths.has(path) && !prerendered_paths.has(path + '/'); - } - - return true; + const prerender = prerender_map.get(route.id); + return ( + prerender === false || + prerender === undefined || + prerender === 'auto' || + prerender === 'unknown' + ); }), prerendered, log diff --git a/packages/kit/src/core/prerender/prerender.js b/packages/kit/src/core/prerender/prerender.js index b1356109fb71..531a2634bbc0 100644 --- a/packages/kit/src/core/prerender/prerender.js +++ b/packages/kit/src/core/prerender/prerender.js @@ -9,8 +9,7 @@ import { crawl } from './crawl.js'; import { escape_html_attr } from '../../utils/escape.js'; import { logger } from '../utils.js'; import { load_config } from '../config/index.js'; -import { compact } from '../../utils/array.js'; -import { get_path } from '../../utils/routing.js'; +import { affects_path } from '../../utils/routing.js'; /** * @typedef {import('types').PrerenderErrorHandler} PrerenderErrorHandler @@ -58,12 +57,15 @@ const OK = 2; const REDIRECT = 3; /** - * @param {import('types').Prerendered} prerendered + * @param {{ + * prerendered: import('types').Prerendered; + * prerender_map: import('types').PrerenderMap; + * }} data */ -const output_and_exit = (prerendered) => { +const output_and_exit = (data) => { writeFileSync( results_path, - JSON.stringify(prerendered, (_key, value) => + JSON.stringify(data, (_key, value) => value instanceof Map ? Array.from(value.entries()) : value ) ); @@ -79,11 +81,13 @@ export async function prerender() { paths: [] }; + const prerender_map = new Map(); + /** @type {import('types').ValidatedKitConfig} */ const config = (await load_config()).kit; if (!config.prerender.enabled) { - output_and_exit(prerendered); + output_and_exit({ prerendered, prerender_map }); return; } @@ -340,13 +344,58 @@ export async function prerender() { } } + for (const route of manifest._.routes) { + try { + if (route.endpoint) { + const mod = await route.endpoint(); + if (mod.prerender) { + if (mod.POST || mod.PATCH || mod.PUT || mod.DELETE) { + throw new Error( + `Cannot prerender a +server file with POST, PATCH, PUT, or DELETE (${route.id})` + ); + } + + prerender_map.set(route.id, mod.prerender); + } else { + // TODO set these based on the pages that request them + prerender_map.set(route.id, 'unknown'); + } + } + + 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; + + prerender_map.set(route.id, prerender); + } + } catch (e) { + // We failed to import the module, which indicates it can't be prerendered + // TODO should we catch these? It's almost certainly a bug in the app + console.error(e); + } + } + for (const entry of config.prerender.entries) { if (entry === '*') { - const { routes } = manifest._; - const entries = compact(routes.map((route) => route.page && get_path(route.id))); - - for (const entry of entries) { - enqueue(null, config.paths.base + entry); // TODO can we pre-normalize these? + for (const [id, prerender] of prerender_map) { + if (prerender && prerender !== 'unknown') { + if (id.includes('[')) continue; + const path = `/${id.split('/').filter(affects_path).join('/')}`; + enqueue(null, config.paths.base + path); + } } } else { enqueue(null, config.paths.base + entry); @@ -367,7 +416,7 @@ export async function prerender() { mkdirp(dirname(file)); writeFileSync(file, await rendered.text()); - output_and_exit(prerendered); + output_and_exit({ prerendered, prerender_map }); } /** @return {string} */ diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index a97a2bdfe2d3..33f18438f898 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -97,6 +97,9 @@ function kit() { /** @type {import('types').Prerendered} */ let prerendered; + /** @type {import('types').PrerenderMap} */ + let prerender_map; + /** @type {import('types').BuildData} */ let build_data; @@ -424,12 +427,16 @@ function kit() { if (code) { reject(new Error(`Prerendering failed with code ${code}`)); } else { - prerendered = JSON.parse(fs.readFileSync(results_path, 'utf8'), (key, value) => { + const results = JSON.parse(fs.readFileSync(results_path, 'utf8'), (key, value) => { if (key === 'pages' || key === 'assets' || key === 'redirects') { return new Map(value); } return value; }); + + prerendered = results.prerendered; + prerender_map = new Map(results.prerender_map); + fulfil(undefined); } }); @@ -465,7 +472,7 @@ function kit() { if (svelte_config.kit.adapter) { const { adapt } = await import('../../core/adapt/index.js'); - await adapt(svelte_config, build_data, prerendered, { log }); + await adapt(svelte_config, build_data, prerendered, prerender_map, { log }); } else { console.log(colors.bold().yellow('\nNo adapter specified')); diff --git a/packages/kit/src/utils/routing.js b/packages/kit/src/utils/routing.js index 67c6e0c6a887..3ff8c92443cb 100644 --- a/packages/kit/src/utils/routing.js +++ b/packages/kit/src/utils/routing.js @@ -96,15 +96,6 @@ export function affects_path(segment) { return !/^\([^)]+\)$/.test(segment); } -/** - * Turns a route ID into a path, if possible - * @param {string} id - */ -export function get_path(id) { - if (id.includes('[')) return null; - return `/${id.split('/').filter(affects_path).join('/')}`; -} - /** * @param {RegExpMatchArray} match * @param {string[]} names diff --git a/packages/kit/types/internal.d.ts b/packages/kit/types/internal.d.ts index 2543bc14c35f..fe27a5a5ed41 100644 --- a/packages/kit/types/internal.d.ts +++ b/packages/kit/types/internal.d.ts @@ -334,7 +334,9 @@ export interface PageNodeIndexes { leaf: number; } -export type SSREndpoint = Partial>; +export type SSREndpoint = Partial> & { + prerender?: boolean | 'auto'; +}; export interface SSRRoute { id: string; diff --git a/packages/kit/types/private.d.ts b/packages/kit/types/private.d.ts index f517091c29a5..42b3ce8dd68e 100644 --- a/packages/kit/types/private.d.ts +++ b/packages/kit/types/private.d.ts @@ -184,6 +184,8 @@ export interface PrerenderErrorHandler { export type PrerenderOnErrorValue = 'fail' | 'continue' | PrerenderErrorHandler; +export type PrerenderMap = Map; + export interface RequestOptions { getClientAddress: () => string; platform?: App.Platform; From 707ad87830fae535f7fc895d06ed43c9a8c25880 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 13:44:49 -0400 Subject: [PATCH 04/16] handle explicit false --- packages/kit/src/core/prerender/prerender.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kit/src/core/prerender/prerender.js b/packages/kit/src/core/prerender/prerender.js index 531a2634bbc0..c2ce169d360c 100644 --- a/packages/kit/src/core/prerender/prerender.js +++ b/packages/kit/src/core/prerender/prerender.js @@ -348,8 +348,8 @@ export async function prerender() { try { if (route.endpoint) { const mod = await route.endpoint(); - if (mod.prerender) { - if (mod.POST || mod.PATCH || mod.PUT || mod.DELETE) { + if (mod.prerender !== undefined) { + if (mod.prerender && (mod.POST || mod.PATCH || mod.PUT || mod.DELETE)) { throw new Error( `Cannot prerender a +server file with POST, PATCH, PUT, or DELETE (${route.id})` ); From 3fb297e01890aacf6c93e03dec36968a41c2d08d Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 15:10:33 -0400 Subject: [PATCH 05/16] implement prerenderable endpoints --- packages/kit/src/core/prerender/prerender.js | 16 ++++++++++---- packages/kit/src/runtime/server/endpoint.js | 18 +++++++++++++++- packages/kit/src/runtime/server/index.js | 2 +- packages/kit/src/runtime/server/page/fetch.js | 4 +++- packages/kit/src/runtime/server/page/index.js | 21 ++++++++++++------- packages/kit/types/internal.d.ts | 19 +++++++++++++---- packages/kit/types/private.d.ts | 4 +++- 7 files changed, 64 insertions(+), 20 deletions(-) diff --git a/packages/kit/src/core/prerender/prerender.js b/packages/kit/src/core/prerender/prerender.js index c2ce169d360c..2cdf7b89d164 100644 --- a/packages/kit/src/core/prerender/prerender.js +++ b/packages/kit/src/core/prerender/prerender.js @@ -81,6 +81,7 @@ export async function prerender() { paths: [] }; + /** @type {import('types').PrerenderMap} */ const prerender_map = new Map(); /** @type {import('types').ValidatedKitConfig} */ @@ -235,6 +236,16 @@ export async function prerender() { const encoded_dependency_path = new URL(dependency_path, 'http://localhost').pathname; const decoded_dependency_path = decodeURI(encoded_dependency_path); + const prerender = result.response.headers.get('x-sveltekit-prerender'); + + if (prerender) { + const route_id = /** @type {string} */ (result.response.headers.get('x-sveltekit-routeid')); + const existing_value = prerender_map.get(route_id); + if (existing_value !== 'auto') { + prerender_map.set(route_id, prerender === 'true' ? true : 'auto'); + } + } + const body = result.body ?? new Uint8Array(await result.response.arrayBuffer()); save( 'dependencies', @@ -356,9 +367,6 @@ export async function prerender() { } prerender_map.set(route.id, mod.prerender); - } else { - // TODO set these based on the pages that request them - prerender_map.set(route.id, 'unknown'); } } @@ -391,7 +399,7 @@ export async function prerender() { for (const entry of config.prerender.entries) { if (entry === '*') { for (const [id, prerender] of prerender_map) { - if (prerender && prerender !== 'unknown') { + if (prerender) { if (id.includes('[')) continue; const path = `/${id.split('/').filter(affects_path).join('/')}`; enqueue(null, config.paths.base + path); diff --git a/packages/kit/src/runtime/server/endpoint.js b/packages/kit/src/runtime/server/endpoint.js index 2f25bf010f1c..9585e027e66b 100644 --- a/packages/kit/src/runtime/server/endpoint.js +++ b/packages/kit/src/runtime/server/endpoint.js @@ -4,9 +4,10 @@ import { check_method_names, method_not_allowed } from './utils.js'; /** * @param {import('types').RequestEvent} event * @param {import('types').SSREndpoint} mod + * @param {import('types').SSRState} state * @returns {Promise} */ -export async function render_endpoint(event, mod) { +export async function render_endpoint(event, mod, state) { const method = /** @type {import('types').HttpMethod} */ (event.request.method); // TODO: Remove for 1.0 @@ -22,6 +23,16 @@ export async function render_endpoint(event, mod) { return method_not_allowed(mod, method); } + const prerender = mod.prerender ?? state.prerender_default; + + if (prerender && (mod.POST || mod.PATCH || mod.PUT || mod.DELETE)) { + throw new Error('Cannot prerender endpoints that have mutative methods'); + } + + if (state.prerendering && !prerender) { + throw new Error(`${event.routeId} is not prerenderable`); + } + try { const response = await handler( /** @type {import('types').RequestEvent>} */ (event) @@ -34,6 +45,11 @@ export async function render_endpoint(event, mod) { ); } + if (state.prerendering) { + response.headers.set('x-sveltekit-routeid', /** @type {string} */ (event.routeId)); + response.headers.set('x-sveltekit-prerender', String(prerender)); + } + return response; } catch (error) { if (error instanceof HttpError) { diff --git a/packages/kit/src/runtime/server/index.js b/packages/kit/src/runtime/server/index.js index 5c03fb045901..7cd89d2ff8a6 100644 --- a/packages/kit/src/runtime/server/index.js +++ b/packages/kit/src/runtime/server/index.js @@ -240,7 +240,7 @@ export async function respond(request, options, state) { } else if (route.page) { response = await render_page(event, route, route.page, options, state, resolve_opts); } else if (route.endpoint) { - response = await render_endpoint(event, await route.endpoint()); + response = await render_endpoint(event, await route.endpoint(), state); } else { // a route will always have a page or an endpoint, but TypeScript // doesn't know that diff --git a/packages/kit/src/runtime/server/page/fetch.js b/packages/kit/src/runtime/server/page/fetch.js index e6ef5aae7c89..1a90eefde75c 100644 --- a/packages/kit/src/runtime/server/page/fetch.js +++ b/packages/kit/src/runtime/server/page/fetch.js @@ -10,9 +10,10 @@ import { domain_matches, path_matches } from './cookie.js'; * options: import('types').SSROptions; * state: import('types').SSRState; * route: import('types').SSRRoute | import('types').SSRErrorPage; + * prerender_default: true | false | 'auto'; * }} opts */ -export function create_fetch({ event, options, state, route }) { +export function create_fetch({ event, options, state, route, prerender_default }) { /** @type {import('./types').Fetched[]} */ const fetched = []; @@ -135,6 +136,7 @@ export function create_fetch({ event, options, state, route }) { new Request(new URL(requested, event.url).href, { ...opts }), options, { + prerender_default, ...state, initiator: route } diff --git a/packages/kit/src/runtime/server/page/index.js b/packages/kit/src/runtime/server/page/index.js index d350441a7158..7e50694a3134 100644 --- a/packages/kit/src/runtime/server/page/index.js +++ b/packages/kit/src/runtime/server/page/index.js @@ -51,8 +51,6 @@ export async function render_page(event, route, page, options, state, resolve_op } } - const { fetcher, fetched, cookies } = create_fetch({ event, options, state, route }); - try { const nodes = await Promise.all([ // we use == here rather than === because [undefined] serializes as "[null]" @@ -109,24 +107,31 @@ 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; 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 endpoints with mutative methods'); + 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 (!should_prerender) { - return new Response(undefined, { - status: 204 - }); - } + return new Response(undefined, { + status: 204 + }); } + const { fetcher, fetched, cookies } = create_fetch({ + event, + options, + state, + route, + prerender_default: should_prerender + }); + if (!resolve_opts.ssr) { return await render_response({ branch: [], diff --git a/packages/kit/types/internal.d.ts b/packages/kit/types/internal.d.ts index aaaab6a3a7fe..d94fc29adb83 100644 --- a/packages/kit/types/internal.d.ts +++ b/packages/kit/types/internal.d.ts @@ -16,7 +16,13 @@ import { ServerInitOptions, SSRManifest } from './index.js'; -import { HttpMethod, MaybePromise, RequestOptions, TrailingSlash } from './private.js'; +import { + HttpMethod, + MaybePromise, + PrerenderOption, + RequestOptions, + TrailingSlash +} from './private.js'; export interface ServerModule { Server: typeof InternalServer; @@ -267,13 +273,13 @@ export interface SSRNode { shared: { load?: Load; hydrate?: boolean; - prerender?: boolean; + prerender?: PrerenderOption; router?: boolean; }; server: { load?: ServerLoad; - prerender?: boolean; + prerender?: PrerenderOption; POST?: Action; PATCH?: Action; PUT?: Action; @@ -334,7 +340,7 @@ export interface PageNodeIndexes { } export type SSREndpoint = Partial> & { - prerender?: boolean | 'auto'; + prerender?: PrerenderOption; }; export interface SSRRoute { @@ -354,6 +360,11 @@ export interface SSRState { initiator?: SSRRoute | SSRErrorPage; platform?: any; prerendering?: PrerenderOptions; + /** + * When fetching data from a +server.js endpoint in `load`, the page's + * prerender option is inherited by the endpoint, unless overridden + */ + prerender_default?: PrerenderOption; } export type StrictBody = string | Uint8Array; diff --git a/packages/kit/types/private.d.ts b/packages/kit/types/private.d.ts index 42b3ce8dd68e..12fe1323ad2c 100644 --- a/packages/kit/types/private.d.ts +++ b/packages/kit/types/private.d.ts @@ -184,7 +184,9 @@ export interface PrerenderErrorHandler { export type PrerenderOnErrorValue = 'fail' | 'continue' | PrerenderErrorHandler; -export type PrerenderMap = Map; +export type PrerenderOption = boolean | 'auto'; + +export type PrerenderMap = Map; export interface RequestOptions { getClientAddress: () => string; From caaaaa3535ab22a62afc707725ecb0458a405ccd Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 15:18:28 -0400 Subject: [PATCH 06/16] prerender content.json --- sites/kit.svelte.dev/src/routes/content.json/+server.js | 2 ++ sites/kit.svelte.dev/svelte.config.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sites/kit.svelte.dev/src/routes/content.json/+server.js b/sites/kit.svelte.dev/src/routes/content.json/+server.js index a0333f13e88b..a757fd60764a 100644 --- a/sites/kit.svelte.dev/src/routes/content.json/+server.js +++ b/sites/kit.svelte.dev/src/routes/content.json/+server.js @@ -1,6 +1,8 @@ import { content } from '$lib/search/content.server.js'; import { json } from '@sveltejs/kit'; +export const prerender = true; + /** @type {import('./$types').RequestHandler} */ export function GET() { return json({ diff --git a/sites/kit.svelte.dev/svelte.config.js b/sites/kit.svelte.dev/svelte.config.js index f59272ed425e..bae891792d33 100644 --- a/sites/kit.svelte.dev/svelte.config.js +++ b/sites/kit.svelte.dev/svelte.config.js @@ -7,7 +7,7 @@ const config = { prerender: { default: true, - entries: ['*', '/content.json'] + entries: ['*'] } } }; From bafc4cb6dbfecda4dc6e8f6be92f0a228abae991 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 15:31:11 -0400 Subject: [PATCH 07/16] tests --- .../test/apps/prerendered/src/routes/+page.js | 5 +++++ .../test/apps/prerendered/src/routes/+page.svelte | 8 +++++++- .../src/routes/endpoint/explicit.json/+server.js | 8 ++++++++ .../src/routes/endpoint/implicit.json/+server.js | 9 +++++++++ packages/adapter-static/test/test.js | 11 ++++++++++- 5 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 packages/adapter-static/test/apps/prerendered/src/routes/+page.js create mode 100644 packages/adapter-static/test/apps/prerendered/src/routes/endpoint/explicit.json/+server.js create mode 100644 packages/adapter-static/test/apps/prerendered/src/routes/endpoint/implicit.json/+server.js diff --git a/packages/adapter-static/test/apps/prerendered/src/routes/+page.js b/packages/adapter-static/test/apps/prerendered/src/routes/+page.js new file mode 100644 index 000000000000..868703b63372 --- /dev/null +++ b/packages/adapter-static/test/apps/prerendered/src/routes/+page.js @@ -0,0 +1,5 @@ +/** @type {import('./$types').PageLoad} */ +export async function load({ fetch }) { + const res = await fetch('/endpoint/implicit.json'); + return await res.json(); +} diff --git a/packages/adapter-static/test/apps/prerendered/src/routes/+page.svelte b/packages/adapter-static/test/apps/prerendered/src/routes/+page.svelte index 404fd77511d2..d92d424b6686 100644 --- a/packages/adapter-static/test/apps/prerendered/src/routes/+page.svelte +++ b/packages/adapter-static/test/apps/prerendered/src/routes/+page.svelte @@ -1 +1,7 @@ -

This page was prerendered

\ No newline at end of file + + +

This page was prerendered

+

answer: {data.answer}

diff --git a/packages/adapter-static/test/apps/prerendered/src/routes/endpoint/explicit.json/+server.js b/packages/adapter-static/test/apps/prerendered/src/routes/endpoint/explicit.json/+server.js new file mode 100644 index 000000000000..fc4b44c582d4 --- /dev/null +++ b/packages/adapter-static/test/apps/prerendered/src/routes/endpoint/explicit.json/+server.js @@ -0,0 +1,8 @@ +import { json } from '@sveltejs/kit'; + +export const prerender = true; + +/** @type {import('./$types').RequestHandler} */ +export function GET() { + return json({ answer: 42 }); +} diff --git a/packages/adapter-static/test/apps/prerendered/src/routes/endpoint/implicit.json/+server.js b/packages/adapter-static/test/apps/prerendered/src/routes/endpoint/implicit.json/+server.js new file mode 100644 index 000000000000..b579cdd18224 --- /dev/null +++ b/packages/adapter-static/test/apps/prerendered/src/routes/endpoint/implicit.json/+server.js @@ -0,0 +1,9 @@ +import { json } from '@sveltejs/kit'; + +// no export const prerender here, it should be prerendered by virtue +// of being fetched from a prerendered page + +/** @type {import('./$types').RequestHandler} */ +export function GET() { + return json({ answer: 42 }); +} diff --git a/packages/adapter-static/test/test.js b/packages/adapter-static/test/test.js index 97bef6e5d5ce..4069190d217f 100644 --- a/packages/adapter-static/test/test.js +++ b/packages/adapter-static/test/test.js @@ -7,9 +7,18 @@ run('prerendered', (test) => { assert.ok(fs.existsSync(`${cwd}/build/index.html`)); }); - test('prerenders content', async ({ base, page }) => { + test('prerenders a page', async ({ base, page }) => { await page.goto(base); assert.equal(await page.textContent('h1'), 'This page was prerendered'); + assert.equal(await page.textContent('p'), 'answer: 42'); + }); + + test('prerenders an unreferenced endpoint with explicit `prerender` setting', async ({ cwd }) => { + assert.ok(fs.existsSync(`${cwd}/build/endpoint/explicit.json`)); + }); + + test('prerenders a referenced endpoint with implicit `prerender` setting', async ({ cwd }) => { + assert.ok(fs.existsSync(`${cwd}/build/endpoint/implicit.json`)); }); }); From 83a49e87e2b8ff99777fe455fb066d035b4c9afd Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 15:34:59 -0400 Subject: [PATCH 08/16] lint --- packages/kit/src/core/adapt/index.js | 7 +------ packages/kit/src/runtime/server/page/fetch.js | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/kit/src/core/adapt/index.js b/packages/kit/src/core/adapt/index.js index 9be11c22807e..ee020825de2c 100644 --- a/packages/kit/src/core/adapt/index.js +++ b/packages/kit/src/core/adapt/index.js @@ -18,12 +18,7 @@ export async function adapt(config, build_data, prerendered, prerender_map, { lo build_data, routes: build_data.manifest_data.routes.filter((route) => { const prerender = prerender_map.get(route.id); - return ( - prerender === false || - prerender === undefined || - prerender === 'auto' || - prerender === 'unknown' - ); + return prerender === false || prerender === undefined || prerender === 'auto'; }), prerendered, log diff --git a/packages/kit/src/runtime/server/page/fetch.js b/packages/kit/src/runtime/server/page/fetch.js index 1a90eefde75c..11f4d2f13b09 100644 --- a/packages/kit/src/runtime/server/page/fetch.js +++ b/packages/kit/src/runtime/server/page/fetch.js @@ -10,7 +10,7 @@ import { domain_matches, path_matches } from './cookie.js'; * options: import('types').SSROptions; * state: import('types').SSRState; * route: import('types').SSRRoute | import('types').SSRErrorPage; - * prerender_default: true | false | 'auto'; + * prerender_default?: true | false | 'auto'; * }} opts */ export function create_fetch({ event, options, state, route, prerender_default }) { From b9be07b740eb3dd95ab5c04d05313c918e1dde3c Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 15:35:46 -0400 Subject: [PATCH 09/16] fix test --- packages/kit/test/apps/basics/test/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js index c659740d2f98..3720f72f97cd 100644 --- a/packages/kit/test/apps/basics/test/test.js +++ b/packages/kit/test/apps/basics/test/test.js @@ -554,7 +554,7 @@ test.describe('Errors', () => { expect(await page.textContent('h1')).toBe('500'); expect(await page.textContent('#message')).toBe( - 'This is your custom error page saying: "Cannot prerender pages that have endpoints with mutative methods"' + 'This is your custom error page saying: "Cannot prerender pages that have mutative methods"' ); }); From efe0dfb098dcf2e7b28c89b5662b7037b341903c Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 15:54:58 -0400 Subject: [PATCH 10/16] throw error unless entire app can be prerendered --- packages/adapter-static/index.js | 32 +++++++++++++++++++++++---- packages/adapter-static/test/utils.js | 1 - packages/kit/src/core/adapt/index.js | 2 ++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/adapter-static/index.js b/packages/adapter-static/index.js index 9068a0730dac..8d6deae6ff8b 100644 --- a/packages/adapter-static/index.js +++ b/packages/adapter-static/index.js @@ -1,3 +1,4 @@ +import path from 'path'; import { platforms } from './platforms.js'; /** @type {import('.').default} */ @@ -6,10 +7,33 @@ export default function (options) { name: '@sveltejs/adapter-static', async adapt(builder) { - if (!options?.fallback && !builder.config.kit.prerender.default) { - throw Error( - 'adapter-static requires `config.kit.prerender.default` to be `true` unless you set the `fallback: true` option to create a single-page app. See https://github.com/sveltejs/kit/tree/master/packages/adapter-static#spa-mode for more information' - ); + if (!options?.fallback) { + /** @type {string[]} */ + const dynamic_routes = []; + + // this is a bit of a hack — it allows us to know whether there are dynamic + // (i.e. prerender = false/'auto') routes without having dedicated API + // surface area for it + builder.createEntries((route) => { + dynamic_routes.push(route.id); + + return { + id: '', + filter: () => false, + complete: () => {} + }; + }); + + if (dynamic_routes.length > 0) { + const prefix = path.relative('.', builder.config.kit.files.routes); + builder.log.error( + `@sveltejs/adapter-static: cannot have dynamic routes unless using the 'fallback' option. See https://github.com/sveltejs/kit/tree/master/packages/adapter-static#spa-mode for more information` + ); + builder.log.error( + dynamic_routes.map((id) => ` - ${path.posix.join(prefix, id)}`).join('\n') + ); + throw new Error('Encountered dynamic routes'); + } } const platform = platforms.find((platform) => platform.test()); diff --git a/packages/adapter-static/test/utils.js b/packages/adapter-static/test/utils.js index 914f80ec4ad5..5f7bd122e4e8 100644 --- a/packages/adapter-static/test/utils.js +++ b/packages/adapter-static/test/utils.js @@ -38,7 +38,6 @@ export function run(app, callback) { console.error(`---\nstdout:\n${e.stdout}`); console.error(`---\nstderr:\n${e.stderr}`); console.groupEnd(); - assert.unreachable(e.message); } context.cwd = cwd; diff --git a/packages/kit/src/core/adapt/index.js b/packages/kit/src/core/adapt/index.js index ee020825de2c..26feb567498b 100644 --- a/packages/kit/src/core/adapt/index.js +++ b/packages/kit/src/core/adapt/index.js @@ -17,6 +17,8 @@ export async function adapt(config, build_data, prerendered, prerender_map, { lo config, build_data, routes: build_data.manifest_data.routes.filter((route) => { + if (!route.page && !route.endpoint) return false; + const prerender = prerender_map.get(route.id); return prerender === false || prerender === undefined || prerender === 'auto'; }), From 63ab1819f9f668f09a1a7f16eb017a7cea96ba42 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 16:16:44 -0400 Subject: [PATCH 11/16] ugh flakiness --- packages/kit/test/apps/basics/test/client.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js index 03da4032df27..1e49285d9cb1 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -672,12 +672,12 @@ test.describe.serial('Invalidation', () => { await page.click('button'); await page.waitForLoadState('networkidle'); - await page.waitForTimeout(0); // apparently necessary + await page.waitForTimeout(200); // apparently necessary expect(await page.textContent('h1')).toBe('a: 2, b: 3'); await page.click('button'); await page.waitForLoadState('networkidle'); - await page.waitForTimeout(0); + await page.waitForTimeout(200); expect(await page.textContent('h1')).toBe('a: 4, b: 5'); }); }); From 0bdee638717b33d45d53fac98429ddba6350a522 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 16:33:06 -0400 Subject: [PATCH 12/16] update docs --- documentation/docs/12-page-options.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/documentation/docs/12-page-options.md b/documentation/docs/12-page-options.md index a00448f1078c..e0ed3ef0cdb6 100644 --- a/documentation/docs/12-page-options.md +++ b/documentation/docs/12-page-options.md @@ -32,22 +32,29 @@ export const hydrate = false; ### prerender -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). +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 with the `prerender` annotation: +Prerendering happens automatically for any `+page` or `+server` file with the `prerender` annotation: ```js -/// file: +page.js/+page.server.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: ```js -/// file: +page.js/+page.server.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': + +```js +/// file: +page.js/+page.server.js/+server.js +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). From 66b155cced2c2b6e7211dd1c7c3404a6e5e7384e Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 17:04:44 -0400 Subject: [PATCH 13/16] update tests --- .../basics/src/routes/fetch-image/[...slug]/+server.js | 2 ++ .../prerendering/basics/src/routes/origin/+page.server.js | 2 ++ .../basics/src/routes/origin/message.json/+server.js | 4 ++++ .../basics/src/routes/page-server-options/+page.server.js | 1 - .../basics/src/routes/page-server-options/+page.svelte | 1 - packages/kit/test/prerendering/basics/test/test.js | 5 ----- .../src/routes/standalone-endpoint.json/+server.js | 2 ++ .../kit/test/prerendering/trailing-slash/svelte.config.js | 5 +++-- sites/kit.svelte.dev/svelte.config.js | 3 +-- 9 files changed, 14 insertions(+), 11 deletions(-) delete mode 100644 packages/kit/test/prerendering/basics/src/routes/page-server-options/+page.server.js delete mode 100644 packages/kit/test/prerendering/basics/src/routes/page-server-options/+page.svelte diff --git a/packages/kit/test/prerendering/basics/src/routes/fetch-image/[...slug]/+server.js b/packages/kit/test/prerendering/basics/src/routes/fetch-image/[...slug]/+server.js index 6d3a67e8e53f..e1494d291ad7 100644 --- a/packages/kit/test/prerendering/basics/src/routes/fetch-image/[...slug]/+server.js +++ b/packages/kit/test/prerendering/basics/src/routes/fetch-image/[...slug]/+server.js @@ -1,5 +1,7 @@ import * as fs from 'fs'; +export const prerender = true; + export async function GET({ params }) { const slug = params.slug.split('/'); const extension = slug[0].split('.').pop(); diff --git a/packages/kit/test/prerendering/basics/src/routes/origin/+page.server.js b/packages/kit/test/prerendering/basics/src/routes/origin/+page.server.js index 984bab08bc55..beb4362c1f23 100644 --- a/packages/kit/test/prerendering/basics/src/routes/origin/+page.server.js +++ b/packages/kit/test/prerendering/basics/src/routes/origin/+page.server.js @@ -1,3 +1,5 @@ +export const prerender = true; + export async function load({ url }) { const res = await fetch(new URL('/origin/message.json', url.origin).href); const { message } = await res.json(); diff --git a/packages/kit/test/prerendering/basics/src/routes/origin/message.json/+server.js b/packages/kit/test/prerendering/basics/src/routes/origin/message.json/+server.js index 2e53051d87ab..04e6ce42c8a8 100644 --- a/packages/kit/test/prerendering/basics/src/routes/origin/message.json/+server.js +++ b/packages/kit/test/prerendering/basics/src/routes/origin/message.json/+server.js @@ -1,5 +1,9 @@ import { json } from '@sveltejs/kit'; +// TODO remove this when we're able to replace the global `fetch` call in the +// neighbouring `+page.server.js` with SvelteKit's `fetch` +export const prerender = true; + export function GET() { return json({ message: 'hello' diff --git a/packages/kit/test/prerendering/basics/src/routes/page-server-options/+page.server.js b/packages/kit/test/prerendering/basics/src/routes/page-server-options/+page.server.js deleted file mode 100644 index d43d0cd2a55d..000000000000 --- a/packages/kit/test/prerendering/basics/src/routes/page-server-options/+page.server.js +++ /dev/null @@ -1 +0,0 @@ -export const prerender = false; diff --git a/packages/kit/test/prerendering/basics/src/routes/page-server-options/+page.svelte b/packages/kit/test/prerendering/basics/src/routes/page-server-options/+page.svelte deleted file mode 100644 index 3c3d6df7a541..000000000000 --- a/packages/kit/test/prerendering/basics/src/routes/page-server-options/+page.svelte +++ /dev/null @@ -1 +0,0 @@ -

This should not be visible

diff --git a/packages/kit/test/prerendering/basics/test/test.js b/packages/kit/test/prerendering/basics/test/test.js index 29a62b3cebe0..44d80bfff518 100644 --- a/packages/kit/test/prerendering/basics/test/test.js +++ b/packages/kit/test/prerendering/basics/test/test.js @@ -112,11 +112,6 @@ test('does not prerender page with shadow endpoint with non-load handler', () => assert.ok(!fs.existsSync(`${build}/shadowed-post/__data.js`)); }); -test('does not prerender page with prerender = false in +page.server.js', () => { - assert.ok(!fs.existsSync(`${build}/page-server-options.html`)); - assert.ok(!fs.existsSync(`${build}/page-server-options/__data.js`)); -}); - test('decodes paths when writing files', () => { let content = read('encoding/path with spaces.html'); assert.ok(content.includes('

path with spaces

')); diff --git a/packages/kit/test/prerendering/trailing-slash/src/routes/standalone-endpoint.json/+server.js b/packages/kit/test/prerendering/trailing-slash/src/routes/standalone-endpoint.json/+server.js index 82d3cb7b8345..f8d1402d3a3f 100644 --- a/packages/kit/test/prerendering/trailing-slash/src/routes/standalone-endpoint.json/+server.js +++ b/packages/kit/test/prerendering/trailing-slash/src/routes/standalone-endpoint.json/+server.js @@ -1,5 +1,7 @@ import { json } from '@sveltejs/kit'; +export const prerender = true; + export async function GET() { return json({ answer: 42 }); } diff --git a/packages/kit/test/prerendering/trailing-slash/svelte.config.js b/packages/kit/test/prerendering/trailing-slash/svelte.config.js index de260fe7c5fb..41249f6dd2f1 100644 --- a/packages/kit/test/prerendering/trailing-slash/svelte.config.js +++ b/packages/kit/test/prerendering/trailing-slash/svelte.config.js @@ -1,5 +1,7 @@ import adapter from '../../../../adapter-static/index.js'; +export const prerender = true; + /** @type {import('@sveltejs/kit').Config} */ const config = { kit: { @@ -8,8 +10,7 @@ const config = { }), prerender: { - default: true, - entries: ['*', '/standalone-endpoint.json'] + default: true }, trailingSlash: 'always' diff --git a/sites/kit.svelte.dev/svelte.config.js b/sites/kit.svelte.dev/svelte.config.js index bae891792d33..e46f95df7b58 100644 --- a/sites/kit.svelte.dev/svelte.config.js +++ b/sites/kit.svelte.dev/svelte.config.js @@ -6,8 +6,7 @@ const config = { adapter: adapter(), prerender: { - default: true, - entries: ['*'] + default: true } } }; From e26ed8cff28bb34e8e17ca3b8847cdee48ea5c48 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 17:08:19 -0400 Subject: [PATCH 14/16] changesets --- .changeset/proud-laws-exist.md | 5 +++++ .changeset/spicy-taxis-wave.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/proud-laws-exist.md create mode 100644 .changeset/spicy-taxis-wave.md diff --git a/.changeset/proud-laws-exist.md b/.changeset/proud-laws-exist.md new file mode 100644 index 000000000000..9ac3739fb24b --- /dev/null +++ b/.changeset/proud-laws-exist.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-static': patch +--- + +[breaking] require all routes to be prerenderable when not using fallback option diff --git a/.changeset/spicy-taxis-wave.md b/.changeset/spicy-taxis-wave.md new file mode 100644 index 000000000000..ead4036116f6 --- /dev/null +++ b/.changeset/spicy-taxis-wave.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +[breaking] add `prerender = 'auto'` option, and extend `prerender` option to endpoints From c20ae6fd6b9bc7a15dc267cb10b172f23bb88fd4 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 20:05:48 -0400 Subject: [PATCH 15/16] oops, bad merge --- packages/kit/src/exports/vite/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 56667e645df5..c5de104275da 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -421,7 +421,6 @@ function kit() { [ vite_config.build.outDir, results_path, - manifest_path, '' + verbose, JSON.stringify({ ...env.private, ...env.public }) ], From 64a4c757d0254040be2e8b4835c9b1729fdc7d03 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Tue, 30 Aug 2022 12:29:14 +0200 Subject: [PATCH 16/16] reuse PrerenderOption and make it a public type --- packages/kit/src/runtime/server/page/fetch.js | 2 +- packages/kit/types/index.d.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/kit/src/runtime/server/page/fetch.js b/packages/kit/src/runtime/server/page/fetch.js index 11f4d2f13b09..efef5f7b3e95 100644 --- a/packages/kit/src/runtime/server/page/fetch.js +++ b/packages/kit/src/runtime/server/page/fetch.js @@ -10,7 +10,7 @@ import { domain_matches, path_matches } from './cookie.js'; * options: import('types').SSROptions; * state: import('types').SSRState; * route: import('types').SSRRoute | import('types').SSRErrorPage; - * prerender_default?: true | false | 'auto'; + * prerender_default?: import('types').PrerenderOption; * }} opts */ export function create_fetch({ event, options, state, route, prerender_default }) { diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index a4b9cb024db4..f7525c71c730 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -19,6 +19,8 @@ import { import { SSRNodeLoader, SSRRoute, ValidatedConfig } from './internal.js'; import { HttpError, Redirect } from '../src/runtime/control.js'; +export { PrerenderOption } from './private.js'; + export interface Adapter { name: string; adapt(builder: Builder): MaybePromise;