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

chore: separate generated from non-generated server code #8429

Merged
merged 45 commits into from
Jan 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
4a3c913
rename node.server to node.has_server_load - more descriptive
Rich-Harris Jan 10, 2023
ca02c22
rename core/prerender to core/postbuild
Rich-Harris Jan 10, 2023
1970f5b
fix
Rich-Harris Jan 10, 2023
3a8e643
move logic around
Rich-Harris Jan 10, 2023
2b87faf
rename server/index.js to server/respond.js
Rich-Harris Jan 10, 2023
07efabf
move some logic around
Rich-Harris Jan 10, 2023
86f3392
move some stuff around
Rich-Harris Jan 10, 2023
9770072
remove options.paths
Rich-Harris Jan 10, 2023
be6a2f0
move read to internal request options
Rich-Harris Jan 10, 2023
03076ab
remove version from SSROptions
Rich-Harris Jan 10, 2023
9c1a012
tidy up
Rich-Harris Jan 10, 2023
9ed0d84
add note
Rich-Harris Jan 10, 2023
6c7b8f2
tidy up
Rich-Harris Jan 10, 2023
a1f7d06
remove public_env from SSROptions
Rich-Harris Jan 10, 2023
77c6446
Merge branch 'master' into gh-7967
Rich-Harris Jan 10, 2023
9740997
move logic to sync
Rich-Harris Jan 10, 2023
b647295
notes to self
Rich-Harris Jan 10, 2023
0d1a3f1
WIP
Rich-Harris Jan 10, 2023
d10609d
hack around the problem
Rich-Harris Jan 10, 2023
015e323
oops
Rich-Harris Jan 10, 2023
a2e9291
partial solution to stack traces
Rich-Harris Jan 10, 2023
173f77e
fix a few more tests
Rich-Harris Jan 10, 2023
c1cadd6
insane
Rich-Harris Jan 10, 2023
7850dc1
use __SVELTEKIT_DEV__ instead of state.dev
Rich-Harris Jan 10, 2023
c894408
fix
Rich-Harris Jan 10, 2023
2c032da
set globalThis.__SVELTEKIT_DEV__
Rich-Harris Jan 10, 2023
7ac306b
tidy some stuff up
Rich-Harris Jan 10, 2023
11e0744
add ambient declaration
Rich-Harris Jan 10, 2023
8f8d17a
set paths correctly
Rich-Harris Jan 11, 2023
1e9925a
remove import
Rich-Harris Jan 11, 2023
20a3c65
DRY
Rich-Harris Jan 11, 2023
a11b09d
reduce indirection
Rich-Harris Jan 11, 2023
6698f3a
use private fields
Rich-Harris Jan 11, 2023
17dd316
separate manifest from server configuration
Rich-Harris Jan 11, 2023
f0c10a3
tidy up
Rich-Harris Jan 11, 2023
40f5728
exclude SvelteKit deps from Vite processing
Rich-Harris Jan 11, 2023
6917725
regenerate server-internal.js as necessary
Rich-Harris Jan 11, 2023
80e6bcd
tidy up
Rich-Harris Jan 11, 2023
93eef70
see if this fixes windows
Rich-Harris Jan 11, 2023
d100ecf
of course it's a path separator issue
dummdidumm Jan 12, 2023
8be199d
remove unused exports
Rich-Harris Jan 12, 2023
6eaec6d
tidy up, see if this still works in windows
Rich-Harris Jan 12, 2023
0499951
remove some unused code
Rich-Harris Jan 12, 2023
a260d8a
Merge branch 'master' into gh-7967
dummdidumm Jan 13, 2023
8aa8d12
Create gorgeous-actors-run.md
Rich-Harris Jan 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/gorgeous-actors-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@sveltejs/kit": patch
---

chore: separate generated from non-generated server code
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"packages/package/test/fixtures/**/expected/**/*",
"packages/package/test/watch/expected/**/*",
"packages/package/test/watch/package/**/*",
"packages/kit/src/core/prerender/fixtures/**/*",
"packages/kit/src/core/postbuild/fixtures/**/*",
"packages/migrate/migrations/routes/*/samples.md"
],
"options": {
Expand Down
2 changes: 1 addition & 1 deletion packages/kit/src/core/adapt/builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export function create_builder({ config, build_data, routes, prerendered, log })

generateFallback(dest) {
// do prerendering in a subprocess so any dangling stuff gets killed upon completion
const script = fileURLToPath(new URL('../prerender/fallback.js', import.meta.url));
const script = fileURLToPath(new URL('../postbuild/fallback.js', import.meta.url));

const manifest_path = `${config.kit.outDir}/output/server/manifest-full.js`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,19 @@ installPolyfills();

const server_root = join(config.outDir, 'output');

/** @type {import('types').ServerInternalModule} */
const { set_building, set_paths } = await import(
pathToFileURL(`${server_root}/server/internal.js`).href
);

/** @type {import('types').ServerModule} */
const { Server, override } = await import(pathToFileURL(`${server_root}/server/index.js`).href);
const { Server } = await import(pathToFileURL(`${server_root}/server/index.js`).href);

/** @type {import('types').SSRManifest} */
const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;

override({
building: true,
paths: config.paths,
read: (file) => readFileSync(join(config.files.assets, file))
});
set_building(true);
set_paths(config.paths);

const server = new Server(manifest);
await server.init({ env: JSON.parse(env) });
Expand All @@ -36,7 +38,8 @@ const rendered = await server.respond(new Request(config.prerender.origin + '/[f
prerendering: {
fallback: true,
dependencies: new Map()
}
},
read: (file) => readFileSync(join(config.files.assets, file))
});

mkdirp(dirname(dest));
Expand Down
104 changes: 104 additions & 0 deletions packages/kit/src/core/postbuild/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { writeFileSync } from 'fs';
import { join } from 'path';
import { pathToFileURL } from 'url';
import { get_option } from '../../runtime/server/utils.js';
import {
validate_common_exports,
validate_page_server_exports,
validate_server_exports
} from '../../utils/exports.js';
import { load_config } from '../config/index.js';
import { prerender } from './prerender.js';

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

/** @type {import('types').SSRManifest} */
const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;

/** @type {import('types').PrerenderMap} */
const prerender_map = new Map();

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

const server_root = join(config.outDir, 'output');

/** @type {import('types').ServerInternalModule} */
const internal = await import(pathToFileURL(`${server_root}/server/internal.js`).href);

/** @type {import('types').ServerModule} */
const { Server } = await import(pathToFileURL(`${server_root}/server/index.js`).href);

// configure `import { building } from '$app/environment'` —
// essential we do this before analysing the code
internal.set_building(true);

// analyse routes
for (const route of manifest._.routes) {
if (route.endpoint) {
const mod = await route.endpoint();
if (mod.prerender !== undefined) {
validate_server_exports(mod, route.id);

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})`
);
}

prerender_map.set(route.id, mod.prerender);
}
}

if (route.page) {
const nodes = await Promise.all(
[...route.page.layouts, route.page.leaf].map((n) => {
if (n !== undefined) return manifest._.nodes[n]();
})
);

const layouts = nodes.slice(0, -1);
const page = nodes.at(-1);

for (const layout of layouts) {
if (layout) {
validate_common_exports(layout.server, route.id);
validate_common_exports(layout.universal, route.id);
}
}

if (page) {
validate_page_server_exports(page.server, route.id);
validate_common_exports(page.universal, route.id);
}

const should_prerender = get_option(nodes, 'prerender');
const prerender =
should_prerender === true ||
// Try prerendering if ssr is false and no server needed. Set it to 'auto' so that
// the route is not removed from the manifest, there could be a server load function.
// People can opt out of this behavior by explicitly setting prerender to false
(should_prerender !== false && get_option(nodes, 'ssr') === false && !page?.server?.actions
? 'auto'
: should_prerender ?? false);

prerender_map.set(route.id, prerender);
}
}

const { prerendered } = await prerender({
Server,
internal,
manifest,
prerender_map,
client_out_dir,
verbose,
env
});

writeFileSync(
results_path,
JSON.stringify({ prerendered, prerender_map }, (_key, value) =>
value instanceof Map ? Array.from(value.entries()) : value
)
);
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { readFileSync, writeFileSync } from 'fs';
import { dirname, join } from 'path';
import { pathToFileURL, URL } from 'url';
import { URL } from 'url';
import { installPolyfills } from '../../exports/node/polyfills.js';
import { mkdirp, posixify, walk } from '../../utils/filesystem.js';
import { should_polyfill } from '../../utils/platform.js';
Expand All @@ -11,16 +11,6 @@ import { escape_html_attr } from '../../utils/escape.js';
import { logger } from '../utils.js';
import { load_config } from '../config/index.js';
import { get_route_segments } from '../../utils/routing.js';
import { get_option } from '../../runtime/server/utils.js';
import {
validate_common_exports,
validate_page_server_exports,
validate_server_exports
} from '../../utils/exports.js';

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

prerender();

/**
* @template {{message: string}} T
Expand Down Expand Up @@ -52,22 +42,27 @@ const OK = 2;
const REDIRECT = 3;

/**
*
* @param {{
* prerendered: import('types').Prerendered;
* Server: typeof import('types').InternalServer;
* internal: import('types').ServerInternalModule;
* manifest: import('types').SSRManifest;
* prerender_map: import('types').PrerenderMap;
* }} data
* client_out_dir: string;
* verbose: string;
* env: string;
* }} opts
* @returns
*/
const output_and_exit = (data) => {
writeFileSync(
results_path,
JSON.stringify(data, (_key, value) =>
value instanceof Map ? Array.from(value.entries()) : value
)
);
process.exit(0);
};

export async function prerender() {
export async function prerender({
Server,
internal,
manifest,
prerender_map,
client_out_dir,
verbose,
env
}) {
/** @type {import('types').Prerendered} */
const prerendered = {
pages: new Map(),
Expand All @@ -76,9 +71,6 @@ export async function prerender() {
paths: []
};

/** @type {import('types').PrerenderMap} */
const prerender_map = new Map();

/** @type {Set<string>} */
const prerendered_routes = new Set();

Expand All @@ -94,29 +86,10 @@ export async function prerender() {
installPolyfills();
}

const server_root = join(config.outDir, 'output');

/** @type {import('types').ServerModule} */
const { Server, override } = await import(pathToFileURL(`${server_root}/server/index.js`).href);

/** @type {import('types').SSRManifest} */
const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;

/** @type {Map<string, string>} */
const saved = new Map();

override({
building: true,
paths: config.paths,
read: (file) => {
// stuff we just wrote
const filepath = saved.get(file);
if (filepath) return readFileSync(filepath);

// stuff in `static`
return readFileSync(join(config.files.assets, file));
}
});
internal.set_paths(config.paths);

const server = new Server(manifest);
await server.init({ env: JSON.parse(env) });
Expand Down Expand Up @@ -201,9 +174,19 @@ export async function prerender() {
const dependencies = new Map();

const response = await server.respond(new Request(config.prerender.origin + encoded), {
getClientAddress,
getClientAddress() {
throw new Error('Cannot read clientAddress during prerendering');
},
prerendering: {
dependencies
},
read: (file) => {
// stuff we just wrote
const filepath = saved.get(file);
if (filepath) return readFileSync(filepath);

// stuff in `static`
return readFileSync(join(config.files.assets, file));
}
});

Expand Down Expand Up @@ -367,58 +350,6 @@ export async function prerender() {
saved.set(file, dest);
}

for (const route of manifest._.routes) {
if (route.endpoint) {
const mod = await route.endpoint();
if (mod.prerender !== undefined) {
validate_server_exports(mod, route.id);

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})`
);
}

prerender_map.set(route.id, mod.prerender);
}
}

if (route.page) {
const nodes = await Promise.all(
[...route.page.layouts, route.page.leaf].map((n) => {
if (n !== undefined) return manifest._.nodes[n]();
})
);

const layouts = nodes.slice(0, -1);
const page = nodes.at(-1);

for (const layout of layouts) {
if (layout) {
validate_common_exports(layout.server, route.id);
validate_common_exports(layout.universal, route.id);
}
}

if (page) {
validate_page_server_exports(page.server, route.id);
validate_common_exports(page.universal, route.id);
}

const should_prerender = get_option(nodes, 'prerender');
const prerender =
should_prerender === true ||
// Try prerendering if ssr is false and no server needed. Set it to 'auto' so that
// the route is not removed from the manifest, there could be a server load function.
// People can opt out of this behavior by explicitly setting prerender to false
(should_prerender !== false && get_option(nodes, 'ssr') === false && !page?.server?.actions
? 'auto'
: should_prerender ?? false);

prerender_map.set(route.id, prerender);
}
}

for (const entry of config.prerender.entries) {
if (entry === '*') {
for (const [id, prerender] of prerender_map) {
Expand Down Expand Up @@ -467,10 +398,5 @@ export async function prerender() {
);
}

output_and_exit({ prerendered, prerender_map });
}

/** @return {string} */
function getClientAddress() {
throw new Error('Cannot read clientAddress during prerendering');
return { prerendered, prerender_map };
}
10 changes: 10 additions & 0 deletions packages/kit/src/core/sync/sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { write_root } from './write_root.js';
import { write_tsconfig } from './write_tsconfig.js';
import { write_types, write_all_types } from './write_types/index.js';
import { write_ambient } from './write_ambient.js';
import { write_server } from './write_server.js';

/**
* Initialize SvelteKit's generated files.
Expand All @@ -27,6 +28,7 @@ export async function create(config) {
const output = path.join(config.kit.outDir, 'generated');

write_client_manifest(config, manifest_data, output);
write_server(config, output);
dummdidumm marked this conversation as resolved.
Show resolved Hide resolved
write_root(manifest_data, output);
write_matchers(manifest_data, output);
await write_all_types(config, manifest_data);
Expand Down Expand Up @@ -57,3 +59,11 @@ export async function all(config, mode) {
init(config, mode);
return await create(config);
}

/**
* Regenerate server-internal.js in response to src/{app.html,error.html,service-worker.js} changing
* @param {import('types').ValidatedConfig} config
*/
export function server(config) {
write_server(config, path.join(config.kit.outDir, 'generated'));
}
Loading