diff --git a/.changeset/rich-llamas-knock.md b/.changeset/rich-llamas-knock.md new file mode 100644 index 000000000000..84eb5b2599ef --- /dev/null +++ b/.changeset/rich-llamas-knock.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-static': patch +--- + +fix: generate fallback page before compressing diff --git a/.changeset/thirty-ways-dress.md b/.changeset/thirty-ways-dress.md new file mode 100644 index 000000000000..81afb188695e --- /dev/null +++ b/.changeset/thirty-ways-dress.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +chore: refactor fallback generation diff --git a/packages/adapter-static/index.js b/packages/adapter-static/index.js index 09c11d574b35..e4dd739fc4cc 100644 --- a/packages/adapter-static/index.js +++ b/packages/adapter-static/index.js @@ -64,7 +64,7 @@ See https://kit.svelte.dev/docs/page-options#prerender for more details` builder.writePrerendered(pages); if (fallback) { - builder.generateFallback(path.join(pages, fallback)); + await builder.generateFallback(path.join(pages, fallback)); } if (precompress) { diff --git a/packages/kit/src/core/adapt/builder.js b/packages/kit/src/core/adapt/builder.js index f30228d65823..e28ce02d9e15 100644 --- a/packages/kit/src/core/adapt/builder.js +++ b/packages/kit/src/core/adapt/builder.js @@ -1,7 +1,5 @@ -import { fork } from 'node:child_process'; import { existsSync, statSync, createReadStream, createWriteStream } from 'node:fs'; import { pipeline } from 'node:stream'; -import { fileURLToPath } from 'node:url'; import { promisify } from 'node:util'; import zlib from 'node:zlib'; import glob from 'tiny-glob'; @@ -9,6 +7,8 @@ import { copy, rimraf, mkdirp } from '../../utils/filesystem.js'; import { generate_manifest } from '../generate_manifest/index.js'; import { get_route_segments } from '../../utils/routing.js'; import { get_env } from '../../exports/vite/utils.js'; +import generate_fallback from '../postbuild/fallback.js'; +import { write } from '../sync/utils.js'; const pipe = promisify(pipeline); @@ -142,31 +142,16 @@ export function create_builder({ } }, - generateFallback(dest) { - // do prerendering in a subprocess so any dangling stuff gets killed upon completion - const script = fileURLToPath(new URL('../postbuild/fallback.js', import.meta.url)); - + async generateFallback(dest) { const manifest_path = `${config.kit.outDir}/output/server/manifest-full.js`; - const env = get_env(config.kit.env, 'production'); - return new Promise((fulfil, reject) => { - const child = fork( - script, - [dest, manifest_path, JSON.stringify({ ...env.private, ...env.public })], - { - stdio: 'inherit' - } - ); - - child.on('exit', (code) => { - if (code) { - reject(new Error(`Could not create a fallback page — failed with code ${code}`)); - } else { - fulfil(undefined); - } - }); + const fallback = await generate_fallback({ + manifest_path, + env: { ...env.private, ...env.public } }); + + write(dest, fallback); }, generateManifest: ({ relativePath, routes: subset }) => { diff --git a/packages/kit/src/core/postbuild/fallback.js b/packages/kit/src/core/postbuild/fallback.js index de49c1681cfe..dbce677d7094 100644 --- a/packages/kit/src/core/postbuild/fallback.js +++ b/packages/kit/src/core/postbuild/fallback.js @@ -1,43 +1,54 @@ -import { readFileSync, writeFileSync } from 'node:fs'; -import { dirname, join } from 'node:path'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; import { pathToFileURL } from 'node:url'; -import { mkdirp } from '../../utils/filesystem.js'; import { installPolyfills } from '../../exports/node/polyfills.js'; import { load_config } from '../config/index.js'; +import { forked } from '../../utils/fork.js'; -const [, , dest, manifest_path, env] = process.argv; +export default forked(import.meta.url, generate_fallback); -/** @type {import('types').ValidatedKitConfig} */ -const config = (await load_config()).kit; +/** + * @param {{ + * manifest_path: string; + * env: Record + * }} opts + */ +async function generate_fallback({ manifest_path, env }) { + /** @type {import('types').ValidatedKitConfig} */ + const config = (await load_config()).kit; -installPolyfills(); + installPolyfills(); -const server_root = join(config.outDir, 'output'); + const server_root = join(config.outDir, 'output'); -/** @type {import('types').ServerInternalModule} */ -const { set_building } = await import(pathToFileURL(`${server_root}/server/internal.js`).href); + /** @type {import('types').ServerInternalModule} */ + const { set_building } = await import(pathToFileURL(`${server_root}/server/internal.js`).href); -/** @type {import('types').ServerModule} */ -const { Server } = await import(pathToFileURL(`${server_root}/server/index.js`).href); + /** @type {import('types').ServerModule} */ + const { Server } = await import(pathToFileURL(`${server_root}/server/index.js`).href); -/** @type {import('types').SSRManifest} */ -const manifest = (await import(pathToFileURL(manifest_path).href)).manifest; + /** @type {import('types').SSRManifest} */ + const manifest = (await import(pathToFileURL(manifest_path).href)).manifest; -set_building(true); + set_building(true); -const server = new Server(manifest); -await server.init({ env: JSON.parse(env) }); + const server = new Server(manifest); + await server.init({ env }); -const rendered = await server.respond(new Request(config.prerender.origin + '/[fallback]'), { - getClientAddress: () => { - throw new Error('Cannot read clientAddress during prerendering'); - }, - prerendering: { - fallback: true, - dependencies: new Map() - }, - read: (file) => readFileSync(join(config.files.assets, file)) -}); + const response = await server.respond(new Request(config.prerender.origin + '/[fallback]'), { + getClientAddress: () => { + throw new Error('Cannot read clientAddress during prerendering'); + }, + prerendering: { + fallback: true, + dependencies: new Map() + }, + read: (file) => readFileSync(join(config.files.assets, file)) + }); -mkdirp(dirname(dest)); -writeFileSync(dest, await rendered.text()); + if (response.ok) { + return await response.text(); + } + + throw new Error(`Could not create a fallback page — failed with status ${response.status}`); +}