Skip to content

Commit

Permalink
fix: generate fallback page before compressing (#8972)
Browse files Browse the repository at this point in the history
* generate fallback page before compressing - fixes #8971

* remove logging

* lint

---------

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
  • Loading branch information
Rich-Harris and dummdidumm committed Feb 9, 2023
1 parent 275bd61 commit eb94356
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 53 deletions.
5 changes: 5 additions & 0 deletions .changeset/rich-llamas-knock.md
@@ -0,0 +1,5 @@
---
'@sveltejs/adapter-static': patch
---

fix: generate fallback page before compressing
5 changes: 5 additions & 0 deletions .changeset/thirty-ways-dress.md
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

chore: refactor fallback generation
2 changes: 1 addition & 1 deletion packages/adapter-static/index.js
Expand Up @@ -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) {
Expand Down
31 changes: 8 additions & 23 deletions packages/kit/src/core/adapt/builder.js
@@ -1,14 +1,14 @@
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';
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);

Expand Down Expand Up @@ -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 }) => {
Expand Down
69 changes: 40 additions & 29 deletions 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<string, string>
* }} 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}`);
}

0 comments on commit eb94356

Please sign in to comment.