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
---

[breaking] remove Prerendered.assets
Rich-Harris marked this conversation as resolved.
Show resolved Hide resolved
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
42 changes: 37 additions & 5 deletions packages/kit/src/core/prerender/prerender.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
import { readFileSync, writeFileSync } from 'fs';
import { dirname, join } from 'path';
import sade from 'sade';
import { pathToFileURL, URL } from 'url';
import { mkdirp, posixify, walk } from '../../utils/filesystem.js';
import { installPolyfills } from '../../node/polyfills.js';
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 prog = sade('prerender');
benmccann marked this conversation as resolved.
Show resolved Hide resolved
prog
.command('run', '', { default: true })
.describe('Runs prerendering. Only for internal use')
.option('--client_out_dir', "Vite's output directory", '')
.option('--results_path', 'Where to put the results', '')
.option('--manifest_path', "SvelteKit's manifest file", '')
.option('--verbose', 'Whether logging should be verbose', false)
.action(async (opts) => {
prerender(opts);
});
prog.parse(process.argv, { unknown: (arg) => `Unknown option: ${arg}` });

/**
* @param {Parameters<PrerenderErrorHandler>[0]} details
* @param {import('types').ValidatedKitConfig} config
Expand Down Expand Up @@ -49,15 +65,24 @@ function normalise_error_handler(log, config) {
const OK = 2;
const REDIRECT = 3;

/**
* @param {string} path
* @param {import('types').Prerendered} prerendered
*/
const output_and_exit = (path, prerendered) => {
writeFileSync(path, JSON.stringify(prerendered));
process.exit(0);
};

/**
* @param {{
* config: import('types').ValidatedKitConfig;
* client_out_dir: string;
* results_path: string;
* manifest_path: string;
* log: Logger;
* verbose: boolean;
* }} opts
*/
export async function prerender({ config, client_out_dir, manifest_path, log }) {
export async function prerender({ client_out_dir, results_path, manifest_path, verbose }) {
/** @type {import('types').Prerendered} */
const prerendered = {
pages: new Map(),
Expand All @@ -66,10 +91,17 @@ 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(results_path, prerendered);
return;
}

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

installPolyfills();
const { fetch } = globalThis;
globalThis.fetch = async (info, init) => {
Expand Down Expand Up @@ -349,7 +381,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(results_path, prerendered);
}

/** @return {string} */
Expand Down
40 changes: 23 additions & 17 deletions packages/kit/src/vite/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { spawnSync } from 'child_process';
import fs from 'fs';
import path from 'path';
import colors from 'kleur';
Expand All @@ -7,7 +8,6 @@ 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';
Expand Down Expand Up @@ -273,9 +273,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 @@ -320,12 +319,26 @@ function kit() {
process.env.SVELTEKIT_SERVER_BUILD_COMPLETED = 'true';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated to this PR, but pretty sure we can get rid of this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No objections assuming it's not used anywhere. It was an internal-only thing, so we shouldn't worry about anyone else relying on it

log.info('Prerendering');

prerendered = await prerender({
config: svelte_config.kit,
client_out_dir: vite_config.build.outDir,
manifest_path,
log
});
const results_path = `${svelte_config.kit.outDir}/generated/prerendered.json`;

// do prerendering in a subprocess so any dangling stuff gets killed upon completion
spawnSync(
'node',
[
'./node_modules/@sveltejs/kit/dist/prerender.js',
benmccann marked this conversation as resolved.
Show resolved Hide resolved
'--client_out_dir',
vite_config.build.outDir,
'--results_path',
results_path,
'--manifest_path',
manifest_path,
'--verbose',
'' + verbose
],
{ stdio: 'inherit' }
);

prerendered = JSON.parse(fs.readFileSync(results_path, 'utf8'));
benmccann marked this conversation as resolved.
Show resolved Hide resolved

if (options.service_worker_entry_file) {
if (svelte_config.kit.paths.assets) {
Expand Down Expand Up @@ -364,13 +377,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