Skip to content

Commit f9827cc

Browse files
authored
feat: lazy discovery of remote functions (#14293)
* WIP lazy discovery of remote functions * fix * partial fix * some progress * WIP * tweak * working but messy * WIP * WIP * unused * WIP * more * tidy up * fix adapter, make self-contained * regenerate * fix * changeset
1 parent 95d64ed commit f9827cc

File tree

15 files changed

+170
-249
lines changed

15 files changed

+170
-249
lines changed

.changeset/clear-wolves-worry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': minor
3+
---
4+
5+
feat: lazy discovery of remote functions

packages/kit/src/core/adapt/builder.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/** @import { Builder } from '@sveltejs/kit' */
22
/** @import { ResolvedConfig } from 'vite' */
33
/** @import { RouteDefinition } from '@sveltejs/kit' */
4-
/** @import { RouteData, ValidatedConfig, BuildData, ServerMetadata, ServerMetadataRoute, Prerendered, PrerenderMap, Logger } from 'types' */
4+
/** @import { RouteData, ValidatedConfig, BuildData, ServerMetadata, ServerMetadataRoute, Prerendered, PrerenderMap, Logger, RemoteChunk } from 'types' */
55
import colors from 'kleur';
66
import { createReadStream, createWriteStream, existsSync, statSync } from 'node:fs';
77
import { extname, resolve, join, dirname, relative } from 'node:path';
@@ -32,6 +32,7 @@ const extensions = ['.html', '.js', '.mjs', '.json', '.css', '.svg', '.xml', '.w
3232
* prerender_map: PrerenderMap;
3333
* log: Logger;
3434
* vite_config: ResolvedConfig;
35+
* remotes: RemoteChunk[]
3536
* }} opts
3637
* @returns {Builder}
3738
*/
@@ -43,7 +44,8 @@ export function create_builder({
4344
prerendered,
4445
prerender_map,
4546
log,
46-
vite_config
47+
vite_config,
48+
remotes
4749
}) {
4850
/** @type {Map<RouteDefinition, RouteData>} */
4951
const lookup = new Map();
@@ -145,7 +147,8 @@ export function create_builder({
145147
build_data,
146148
prerendered: [],
147149
relative_path: relativePath,
148-
routes: Array.from(filtered)
150+
routes: Array.from(filtered),
151+
remotes
149152
})
150153
});
151154
}
@@ -195,7 +198,8 @@ export function create_builder({
195198
relative_path: relativePath,
196199
routes: subset
197200
? subset.map((route) => /** @type {import('types').RouteData} */ (lookup.get(route)))
198-
: route_data.filter((route) => prerender_map.get(route.id) !== true)
201+
: route_data.filter((route) => prerender_map.get(route.id) !== true),
202+
remotes
199203
});
200204
},
201205

packages/kit/src/core/adapt/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { create_builder } from './builder.js';
88
* @param {import('types').Prerendered} prerendered
99
* @param {import('types').PrerenderMap} prerender_map
1010
* @param {import('types').Logger} log
11+
* @param {import('types').RemoteChunk[]} remotes
1112
* @param {import('vite').ResolvedConfig} vite_config
1213
*/
1314
export async function adapt(
@@ -17,6 +18,7 @@ export async function adapt(
1718
prerendered,
1819
prerender_map,
1920
log,
21+
remotes,
2022
vite_config
2123
) {
2224
// This is only called when adapter is truthy, so the cast is safe
@@ -32,6 +34,7 @@ export async function adapt(
3234
prerendered,
3335
prerender_map,
3436
log,
37+
remotes,
3538
vite_config
3639
});
3740

packages/kit/src/core/generate_manifest/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** @import { RemoteChunk } from 'types' */
12
import fs from 'node:fs';
23
import path from 'node:path';
34
import * as mime from 'mrmime';
@@ -18,9 +19,10 @@ import { uneval } from 'devalue';
1819
* prerendered: string[];
1920
* relative_path: string;
2021
* routes: import('types').RouteData[];
22+
* remotes: RemoteChunk[];
2123
* }} opts
2224
*/
23-
export function generate_manifest({ build_data, prerendered, relative_path, routes }) {
25+
export function generate_manifest({ build_data, prerendered, relative_path, routes, remotes }) {
2426
/**
2527
* @type {Map<any, number>} The new index of each node in the filtered nodes array
2628
*/
@@ -101,7 +103,7 @@ export function generate_manifest({ build_data, prerendered, relative_path, rout
101103
${(node_paths).map(loader).join(',\n')}
102104
],
103105
remotes: {
104-
${build_data.manifest_data.remotes.map((remote) => `'${remote.hash}': ${loader(join_relative(relative_path, resolve_symlinks(build_data.server_manifest, remote.file).chunk.file))}`).join(',\n')}
106+
${remotes.map((remote) => `'${remote.hash}': ${loader(join_relative(relative_path, `chunks/remote-${remote.hash}.js`))}`).join(',\n')}
105107
},
106108
routes: [
107109
${routes.map(route => {

packages/kit/src/core/postbuild/analyse.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** @import { RemoteChunk } from 'types' */
12
import { join } from 'node:path';
23
import { pathToFileURL } from 'node:url';
34
import { validate_server_exports } from '../../utils/exports.js';
@@ -11,7 +12,6 @@ import { check_feature } from '../../utils/features.js';
1112
import { createReadableStream } from '@sveltejs/kit/node';
1213
import { PageNodes } from '../../utils/page_nodes.js';
1314
import { build_server_nodes } from '../../exports/vite/build/build_server.js';
14-
import { validate_remote_functions } from '@sveltejs/kit/internal';
1515

1616
export default forked(import.meta.url, analyse);
1717

@@ -25,6 +25,7 @@ export default forked(import.meta.url, analyse);
2525
* env: Record<string, string>;
2626
* out: string;
2727
* output_config: import('types').RecursiveRequired<import('types').ValidatedConfig['kit']['output']>;
28+
* remotes: RemoteChunk[];
2829
* }} opts
2930
*/
3031
async function analyse({
@@ -35,7 +36,8 @@ async function analyse({
3536
tracked_features,
3637
env,
3738
out,
38-
output_config
39+
output_config,
40+
remotes
3941
}) {
4042
/** @type {import('@sveltejs/kit').SSRManifest} */
4143
const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
@@ -166,16 +168,14 @@ async function analyse({
166168
}
167169

168170
// analyse remotes
169-
for (const remote of manifest_data.remotes) {
171+
for (const remote of remotes) {
170172
const loader = manifest._.remotes[remote.hash];
171-
const module = await loader();
172-
173-
validate_remote_functions(module, remote.file);
173+
const { default: functions } = await loader();
174174

175175
const exports = new Map();
176176

177-
for (const name in module) {
178-
const info = /** @type {import('types').RemoteInfo} */ (module[name].__);
177+
for (const name in functions) {
178+
const info = /** @type {import('types').RemoteInfo} */ (functions[name].__);
179179
const type = info.type;
180180

181181
exports.set(name, {

packages/kit/src/core/postbuild/prerender.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
495495
for (const loader of Object.values(manifest._.remotes)) {
496496
const module = await loader();
497497

498-
for (const fn of Object.values(module)) {
498+
for (const fn of Object.values(module.default)) {
499499
if (fn?.__?.type === 'prerender') {
500500
prerender_functions.push(fn.__);
501501
should_prerender = true;

packages/kit/src/core/sync/create_manifest_data/index.js

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ import process from 'node:process';
44
import colors from 'kleur';
55
import { lookup } from 'mrmime';
66
import { list_files, runtime_directory } from '../../utils.js';
7-
import { posixify, resolve_entry, walk } from '../../../utils/filesystem.js';
7+
import { posixify, resolve_entry } from '../../../utils/filesystem.js';
88
import { parse_route_id } from '../../../utils/routing.js';
99
import { sort_routes } from './sort.js';
1010
import { isSvelte5Plus } from '../utils.js';
11-
import { hash } from '../../../utils/hash.js';
1211

1312
/**
1413
* Generates the manifest data used for the client-side manifest and types generation.
@@ -28,7 +27,6 @@ export default function create_manifest_data({
2827
const hooks = create_hooks(config, cwd);
2928
const matchers = create_matchers(config, cwd);
3029
const { nodes, routes } = create_routes_and_nodes(cwd, config, fallback);
31-
const remotes = create_remotes(config, cwd);
3230

3331
for (const route of routes) {
3432
for (const param of route.params) {
@@ -43,7 +41,6 @@ export default function create_manifest_data({
4341
hooks,
4442
matchers,
4543
nodes,
46-
remotes,
4744
routes
4845
};
4946
}
@@ -468,33 +465,6 @@ function create_routes_and_nodes(cwd, config, fallback) {
468465
};
469466
}
470467

471-
/**
472-
* @param {import('types').ValidatedConfig} config
473-
* @param {string} cwd
474-
*/
475-
function create_remotes(config, cwd) {
476-
if (!config.kit.experimental.remoteFunctions) return [];
477-
478-
const extensions = config.kit.moduleExtensions.map((ext) => `.remote${ext}`);
479-
480-
/** @type {import('types').ManifestData['remotes']} */
481-
const remotes = [];
482-
483-
// TODO could files live in other directories, including node_modules?
484-
for (const file of walk(config.kit.files.src)) {
485-
if (extensions.some((ext) => file.endsWith(ext))) {
486-
const posixified = posixify(path.relative(cwd, `${config.kit.files.src}/${file}`));
487-
488-
remotes.push({
489-
hash: hash(posixified),
490-
file: posixified
491-
});
492-
}
493-
}
494-
495-
return remotes;
496-
}
497-
498468
/**
499469
* @param {string} project_relative
500470
* @param {string} file

packages/kit/src/exports/internal/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,4 @@ export class ActionFailure {
6262
}
6363
}
6464

65-
export { validate_remote_functions } from './remote-functions.js';
65+
export { init_remote_functions } from './remote-functions.js';
Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
1+
/** @import { RemoteInfo } from 'types' */
2+
3+
/** @type {RemoteInfo['type'][]} */
4+
const types = ['command', 'form', 'prerender', 'query', 'query_batch'];
5+
16
/**
27
* @param {Record<string, any>} module
38
* @param {string} file
9+
* @param {string} hash
410
*/
5-
export function validate_remote_functions(module, file) {
11+
export function init_remote_functions(module, file, hash) {
612
if (module.default) {
713
throw new Error(
814
`Cannot export \`default\` from a remote module (${file}) — please use named exports instead`
915
);
1016
}
1117

12-
for (const name in module) {
13-
const type = /** @type {import('types').RemoteInfo['type']} */ (module[name]?.__?.type);
14-
15-
if (
16-
type !== 'form' &&
17-
type !== 'command' &&
18-
type !== 'query' &&
19-
type !== 'query_batch' &&
20-
type !== 'prerender'
21-
) {
18+
for (const [name, fn] of Object.entries(module)) {
19+
if (!types.includes(fn?.__?.type)) {
2220
throw new Error(
2321
`\`${name}\` exported from ${file} is invalid — all exports from this file must be remote functions`
2422
);
2523
}
24+
25+
fn.__.id = `${hash}/${name}`;
26+
fn.__.name = name;
2627
}
2728
}

0 commit comments

Comments
 (0)