Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fix] prerender in subprocess #5678

Merged
merged 14 commits into from
Jul 25, 2022
5 changes: 5 additions & 0 deletions .changeset/witty-avocados-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

prerender in a subprocess
3 changes: 2 additions & 1 deletion packages/kit/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ export default [
{
input: {
cli: 'src/cli.js',
hooks: 'src/hooks.js',
node: 'src/node/index.js',
'node/polyfills': 'src/node/polyfills.js',
hooks: 'src/hooks.js',
prerender: 'src/core/prerender/prerender.js',
vite: 'src/vite/index.js'
},
output: {
Expand Down
38 changes: 29 additions & 9 deletions packages/kit/src/core/prerender/prerender.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ import { is_root_relative, resolve } from '../../utils/url.js';
import { queue } from './queue.js';
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';

/**
* @typedef {import('types').PrerenderErrorHandler} PrerenderErrorHandler
* @typedef {import('types').Logger} Logger
*/

const [, , client_out_dir, results_path, manifest_path, verbose] = process.argv;

prerender();

/**
* @param {Parameters<PrerenderErrorHandler>[0]} details
* @param {import('types').ValidatedKitConfig} config
Expand Down Expand Up @@ -50,14 +56,19 @@ const OK = 2;
const REDIRECT = 3;

/**
* @param {{
* config: import('types').ValidatedKitConfig;
* client_out_dir: string;
* manifest_path: string;
* log: Logger;
* }} opts
* @param {import('types').Prerendered} prerendered
*/
export async function prerender({ config, client_out_dir, manifest_path, log }) {
const output_and_exit = (prerendered) => {
writeFileSync(
results_path,
JSON.stringify(prerendered, (_key, value) =>
value instanceof Map ? Array.from(value.entries()) : value
)
);
process.exit(0);
};

export async function prerender() {
/** @type {import('types').Prerendered} */
const prerendered = {
pages: new Map(),
Expand All @@ -66,10 +77,19 @@ export async function prerender({ config, client_out_dir, manifest_path, log })
paths: []
};

/** @type {import('types').ValidatedKitConfig} */
const config = (await load_config()).kit;

if (!config.prerender.enabled) {
return prerendered;
output_and_exit(prerendered);
return;
}

/** @type {import('types').Logger} */
const log = logger({
verbose: verbose === 'true'
});

installPolyfills();
const { fetch } = globalThis;
globalThis.fetch = async (info, init) => {
Expand Down Expand Up @@ -349,7 +369,7 @@ export async function prerender({ config, client_out_dir, manifest_path, log })
mkdirp(dirname(file));
writeFileSync(file, await rendered.text());

return prerendered;
output_and_exit(prerendered);
}

/** @return {string} */
Expand Down
56 changes: 37 additions & 19 deletions packages/kit/src/vite/index.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import fs from 'fs';
import path from 'path';
import { fork } from 'node:child_process';
import fs, { existsSync } from 'node:fs';
import path from 'node:path';
import colors from 'kleur';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import * as vite from 'vite';
import { mkdirp, posixify, rimraf } from '../utils/filesystem.js';
import * as sync from '../core/sync/sync.js';
import { build_server } from './build/build_server.js';
import { build_service_worker } from './build/build_service_worker.js';
import { prerender } from '../core/prerender/prerender.js';
import { load_config } from '../core/config/index.js';
import { dev } from './dev/index.js';
import { generate_manifest } from '../core/generate_manifest/index.js';
import { get_runtime_directory, logger } from '../core/utils.js';
import { find_deps, get_default_config as get_default_build_config } from './build/utils.js';
import { preview } from './preview/index.js';
import { get_aliases, resolve_entry } from './utils.js';
import { fileURLToPath } from 'node:url';

const cwd = process.cwd();

Expand Down Expand Up @@ -273,9 +274,8 @@ function kit() {
* then use this hook to kick off builds for the server and service worker.
*/
async writeBundle(_options, bundle) {
log = logger({
verbose: vite_config.logLevel === 'info'
});
const verbose = vite_config.logLevel === 'info';
log = logger({ verbose });

fs.writeFileSync(
`${paths.client_out_dir}/${svelte_config.kit.appDir}/version.json`,
Expand Down Expand Up @@ -318,14 +318,39 @@ function kit() {
})};\n`
);

process.env.SVELTEKIT_SERVER_BUILD_COMPLETED = 'true';
log.info('Prerendering');
await new Promise((fulfil, reject) => {
const results_path = `${svelte_config.kit.outDir}/generated/prerendered.json`;

// do prerendering in a subprocess so any dangling stuff gets killed upon completion
const script = fileURLToPath(
new URL(
process.env.BUNDLED ? './prerender.js' : '../core/prerender/prerender.js',
import.meta.url
)
);

prerendered = await prerender({
config: svelte_config.kit,
client_out_dir: vite_config.build.outDir,
manifest_path,
log
const child = fork(
script,
[vite_config.build.outDir, results_path, manifest_path, '' + verbose],
{
stdio: 'inherit'
}
);

child.on('exit', (code) => {
if (code) {
reject(new Error(`Prerendering failed with code ${code}`));
} else {
prerendered = JSON.parse(fs.readFileSync(results_path, 'utf8'), (key, value) => {
if (key === 'pages' || key === 'assets' || key === 'redirects') {
return new Map(value);
}
return value;
});
fulfil(undefined);
}
});
});

if (options.service_worker_entry_file) {
Expand Down Expand Up @@ -365,13 +390,6 @@ function kit() {
`See ${colors.bold().cyan('https://kit.svelte.dev/docs/adapters')} to learn how to configure your app to run on the platform of your choosing`
);
}

if (svelte_config.kit.prerender.enabled) {
// this is necessary to close any open db connections, etc.
// TODO: prerender in a subprocess so we can exit in isolation and then remove this
// https://github.com/sveltejs/kit/issues/5306
process.exit(0);
}
},

/**
Expand Down