@sveltejs/kit 2.26.0 → 2.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +3 -2
- package/src/core/adapt/builder.js +6 -1
- package/src/core/config/options.js +4 -0
- package/src/core/generate_manifest/index.js +3 -0
- package/src/core/postbuild/analyse.js +25 -1
- package/src/core/postbuild/fallback.js +2 -1
- package/src/core/postbuild/prerender.js +41 -10
- package/src/core/sync/create_manifest_data/index.js +35 -1
- package/src/core/sync/write_server.js +4 -2
- package/src/core/sync/write_types/index.js +12 -5
- package/src/exports/index.js +1 -1
- package/src/exports/internal/index.js +3 -1
- package/src/exports/internal/remote-functions.js +21 -0
- package/src/exports/public.d.ts +162 -2
- package/src/exports/vite/build/build_remote.js +129 -0
- package/src/exports/vite/dev/index.js +7 -0
- package/src/exports/vite/index.js +123 -8
- package/src/exports/vite/module_ids.js +3 -2
- package/src/exports/vite/preview/index.js +3 -1
- package/src/runtime/app/navigation.js +1 -0
- package/src/runtime/app/server/index.js +2 -0
- package/src/runtime/app/server/remote/command.js +91 -0
- package/src/runtime/app/server/remote/form.js +124 -0
- package/src/runtime/app/server/remote/index.js +4 -0
- package/src/runtime/app/server/remote/prerender.js +163 -0
- package/src/runtime/app/server/remote/query.js +115 -0
- package/src/runtime/app/server/remote/shared.js +153 -0
- package/src/runtime/client/client.js +107 -39
- package/src/runtime/client/fetcher.js +1 -1
- package/src/runtime/client/remote-functions/command.js +71 -0
- package/src/runtime/client/remote-functions/form.svelte.js +312 -0
- package/src/runtime/client/remote-functions/index.js +4 -0
- package/src/runtime/client/remote-functions/prerender.svelte.js +166 -0
- package/src/runtime/client/remote-functions/query.svelte.js +219 -0
- package/src/runtime/client/remote-functions/shared.svelte.js +143 -0
- package/src/runtime/client/types.d.ts +2 -0
- package/src/runtime/server/data/index.js +6 -4
- package/src/runtime/server/event-state.js +41 -0
- package/src/runtime/server/index.js +12 -3
- package/src/runtime/server/page/actions.js +1 -1
- package/src/runtime/server/page/index.js +10 -3
- package/src/runtime/server/page/load_data.js +18 -12
- package/src/runtime/server/page/render.js +31 -5
- package/src/runtime/server/page/serialize_data.js +1 -1
- package/src/runtime/server/remote.js +237 -0
- package/src/runtime/server/respond.js +57 -36
- package/src/runtime/shared.js +61 -0
- package/src/types/global-private.d.ts +2 -0
- package/src/types/internal.d.ts +51 -4
- package/src/types/synthetic/$env+static+private.md +1 -1
- package/src/utils/routing.js +1 -1
- package/src/version.js +1 -1
- package/types/index.d.ts +266 -3
- package/types/index.d.ts.map +14 -1
- /package/src/{runtime → utils}/hash.js +0 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/** @import { ManifestData, ServerMetadata } from 'types' */
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { posixify } from '../../../utils/filesystem.js';
|
|
5
|
+
import { dedent } from '../../../core/sync/utils.js';
|
|
6
|
+
import { import_peer } from '../../../utils/import.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Moves the remote files to a sibling file and rewrites the original remote file to import from that sibling file,
|
|
10
|
+
* enhancing the remote functions with their hashed ID.
|
|
11
|
+
* This is not done through a self-import like during DEV because we want to treeshake prerendered remote functions
|
|
12
|
+
* later, which wouldn't work if we do a self-import and iterate over all exports (since we're reading them then).
|
|
13
|
+
* @param {string} out
|
|
14
|
+
* @param {ManifestData} manifest_data
|
|
15
|
+
*/
|
|
16
|
+
export function build_remotes(out, manifest_data) {
|
|
17
|
+
const dir = `${out}/server/remote`;
|
|
18
|
+
|
|
19
|
+
for (const remote of manifest_data.remotes) {
|
|
20
|
+
const entry = `${dir}/${remote.hash}.js`;
|
|
21
|
+
const tmp = `${remote.hash}.tmp.js`;
|
|
22
|
+
|
|
23
|
+
fs.renameSync(entry, `${dir}/${tmp}`);
|
|
24
|
+
fs.writeFileSync(
|
|
25
|
+
entry,
|
|
26
|
+
dedent`
|
|
27
|
+
import * as $$_self_$$ from './${tmp}';
|
|
28
|
+
|
|
29
|
+
for (const [name, fn] of Object.entries($$_self_$$)) {
|
|
30
|
+
fn.__.id = '${remote.hash}/' + name;
|
|
31
|
+
fn.__.name = name;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export * from './${tmp}';
|
|
35
|
+
`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* For each remote module, checks if there are treeshakeable prerendered remote functions,
|
|
43
|
+
* then accomplishes the treeshaking by rewriting the remote files to only include the non-prerendered imports,
|
|
44
|
+
* replacing the prerendered remote functions with a dummy function that should never be called,
|
|
45
|
+
* and doing a Vite build. This will not treeshake perfectly yet as everything except the remote files are treated as external,
|
|
46
|
+
* so it will not go into those files to check what can be treeshaken inside them.
|
|
47
|
+
* @param {string} out
|
|
48
|
+
* @param {ManifestData} manifest_data
|
|
49
|
+
* @param {ServerMetadata} metadata
|
|
50
|
+
*/
|
|
51
|
+
export async function treeshake_prerendered_remotes(out, manifest_data, metadata) {
|
|
52
|
+
if (manifest_data.remotes.length === 0) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const dir = posixify(`${out}/server/remote`);
|
|
57
|
+
|
|
58
|
+
const vite = /** @type {typeof import('vite')} */ (await import_peer('vite'));
|
|
59
|
+
const remote_entry = posixify(`${out}/server/remote-entry.js`);
|
|
60
|
+
|
|
61
|
+
const prefix = 'optimized/';
|
|
62
|
+
|
|
63
|
+
const input = {
|
|
64
|
+
// include this file in the bundle, so that Rollup understands
|
|
65
|
+
// that functions like `prerender` are side-effect free
|
|
66
|
+
[path.basename(remote_entry.slice(0, -3))]: remote_entry
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
for (const remote of manifest_data.remotes) {
|
|
70
|
+
const exports = metadata.remotes.get(remote.hash);
|
|
71
|
+
if (!exports) throw new Error('An impossible situation occurred');
|
|
72
|
+
|
|
73
|
+
/** @type {string[]} */
|
|
74
|
+
const dynamic = [];
|
|
75
|
+
|
|
76
|
+
/** @type {string[]} */
|
|
77
|
+
const prerendered = [];
|
|
78
|
+
|
|
79
|
+
for (const [name, value] of exports) {
|
|
80
|
+
(value.dynamic ? dynamic : prerendered).push(name);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const remote_file = posixify(`${dir}/${remote.hash}.js`);
|
|
84
|
+
|
|
85
|
+
fs.writeFileSync(
|
|
86
|
+
remote_file,
|
|
87
|
+
dedent`
|
|
88
|
+
import { ${dynamic.join(', ')} } from './${remote.hash}.tmp.js';
|
|
89
|
+
import { prerender } from '../${path.basename(remote_entry)}';
|
|
90
|
+
|
|
91
|
+
${prerendered.map((name) => `export const ${name} = prerender('unchecked', () => { throw new Error('Unexpectedly called prerender function. Did you forget to set { dynamic: true } ?') });`).join('\n')}
|
|
92
|
+
|
|
93
|
+
for (const [name, fn] of Object.entries({ ${Array.from(exports.keys()).join(', ')} })) {
|
|
94
|
+
fn.__.id = '${remote.hash}/' + name;
|
|
95
|
+
fn.__.name = name;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export { ${dynamic.join(', ')} };
|
|
99
|
+
`
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
input[prefix + remote.hash] = remote_file;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const bundle = await vite.build({
|
|
106
|
+
configFile: false,
|
|
107
|
+
build: {
|
|
108
|
+
ssr: true,
|
|
109
|
+
rollupOptions: {
|
|
110
|
+
external: (id) => {
|
|
111
|
+
if (id[0] === '.') return;
|
|
112
|
+
return !id.startsWith(dir);
|
|
113
|
+
},
|
|
114
|
+
input
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// @ts-expect-error TypeScript doesn't know what type `bundle` is
|
|
120
|
+
for (const chunk of bundle.output) {
|
|
121
|
+
if (chunk.name.startsWith(prefix)) {
|
|
122
|
+
fs.writeFileSync(`${dir}/${chunk.fileName.slice(prefix.length)}`, chunk.code);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
for (const remote of manifest_data.remotes) {
|
|
127
|
+
fs.unlinkSync(`${dir}/${remote.hash}.tmp.js`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -266,6 +266,12 @@ export async function dev(vite, vite_config, svelte_config) {
|
|
|
266
266
|
};
|
|
267
267
|
}),
|
|
268
268
|
prerendered_routes: new Set(),
|
|
269
|
+
remotes: Object.fromEntries(
|
|
270
|
+
manifest_data.remotes.map((remote) => [
|
|
271
|
+
remote.hash,
|
|
272
|
+
() => vite.ssrLoadModule(remote.file)
|
|
273
|
+
])
|
|
274
|
+
),
|
|
269
275
|
routes: compact(
|
|
270
276
|
manifest_data.routes.map((route) => {
|
|
271
277
|
if (!route.page && !route.endpoint) return null;
|
|
@@ -331,6 +337,7 @@ export async function dev(vite, vite_config, svelte_config) {
|
|
|
331
337
|
if (
|
|
332
338
|
file.startsWith(svelte_config.kit.files.routes + path.sep) ||
|
|
333
339
|
file.startsWith(svelte_config.kit.files.params + path.sep) ||
|
|
340
|
+
svelte_config.kit.moduleExtensions.some((ext) => file.endsWith(`.remote${ext}`)) ||
|
|
334
341
|
// in contrast to server hooks, client hooks are written to the client manifest
|
|
335
342
|
// and therefore need rebuilding when they are added/removed
|
|
336
343
|
file.startsWith(svelte_config.kit.files.hooks.client)
|
|
@@ -22,7 +22,7 @@ import { write_client_manifest } from '../../core/sync/write_client_manifest.js'
|
|
|
22
22
|
import prerender from '../../core/postbuild/prerender.js';
|
|
23
23
|
import analyse from '../../core/postbuild/analyse.js';
|
|
24
24
|
import { s } from '../../utils/misc.js';
|
|
25
|
-
import { hash } from '../../
|
|
25
|
+
import { hash } from '../../utils/hash.js';
|
|
26
26
|
import { dedent, isSvelte5Plus } from '../../core/sync/utils.js';
|
|
27
27
|
import {
|
|
28
28
|
env_dynamic_private,
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
} from './module_ids.js';
|
|
37
37
|
import { import_peer } from '../../utils/import.js';
|
|
38
38
|
import { compact } from '../../utils/array.js';
|
|
39
|
+
import { build_remotes, treeshake_prerendered_remotes } from './build/build_remote.js';
|
|
39
40
|
|
|
40
41
|
const cwd = process.cwd();
|
|
41
42
|
|
|
@@ -167,6 +168,9 @@ let secondary_build_started = false;
|
|
|
167
168
|
/** @type {import('types').ManifestData} */
|
|
168
169
|
let manifest_data;
|
|
169
170
|
|
|
171
|
+
/** @type {import('types').ServerMetadata['remotes'] | undefined} only set at build time */
|
|
172
|
+
let remote_exports = undefined;
|
|
173
|
+
|
|
170
174
|
/**
|
|
171
175
|
* Returns the SvelteKit Vite plugin. Vite executes Rollup hooks as well as some of its own.
|
|
172
176
|
* Background reading is available at:
|
|
@@ -213,6 +217,9 @@ async function kit({ svelte_config }) {
|
|
|
213
217
|
const service_worker_entry_file = resolve_entry(kit.files.serviceWorker);
|
|
214
218
|
const parsed_service_worker = path.parse(kit.files.serviceWorker);
|
|
215
219
|
|
|
220
|
+
const normalized_cwd = vite.normalizePath(cwd);
|
|
221
|
+
const normalized_lib = vite.normalizePath(kit.files.lib);
|
|
222
|
+
|
|
216
223
|
/**
|
|
217
224
|
* A map showing which features (such as `$app/server:read`) are defined
|
|
218
225
|
* in which chunks, so that we can later determine which routes use which features
|
|
@@ -322,7 +329,8 @@ async function kit({ svelte_config }) {
|
|
|
322
329
|
__SVELTEKIT_APP_VERSION_FILE__: s(`${kit.appDir}/version.json`),
|
|
323
330
|
__SVELTEKIT_APP_VERSION_POLL_INTERVAL__: s(kit.version.pollInterval),
|
|
324
331
|
__SVELTEKIT_DEV__: 'false',
|
|
325
|
-
__SVELTEKIT_EMBEDDED__: kit.embedded
|
|
332
|
+
__SVELTEKIT_EMBEDDED__: s(kit.embedded),
|
|
333
|
+
__SVELTEKIT_EXPERIMENTAL__REMOTE_FUNCTIONS__: s(kit.experimental.remoteFunctions),
|
|
326
334
|
__SVELTEKIT_CLIENT_ROUTING__: kit.router.resolution === 'client' ? 'true' : 'false'
|
|
327
335
|
};
|
|
328
336
|
|
|
@@ -333,7 +341,8 @@ async function kit({ svelte_config }) {
|
|
|
333
341
|
new_config.define = {
|
|
334
342
|
__SVELTEKIT_APP_VERSION_POLL_INTERVAL__: '0',
|
|
335
343
|
__SVELTEKIT_DEV__: 'true',
|
|
336
|
-
__SVELTEKIT_EMBEDDED__: kit.embedded
|
|
344
|
+
__SVELTEKIT_EMBEDDED__: s(kit.embedded),
|
|
345
|
+
__SVELTEKIT_EXPERIMENTAL__REMOTE_FUNCTIONS__: s(kit.experimental.remoteFunctions),
|
|
337
346
|
__SVELTEKIT_CLIENT_ROUTING__: kit.router.resolution === 'client' ? 'true' : 'false'
|
|
338
347
|
};
|
|
339
348
|
|
|
@@ -381,8 +390,6 @@ async function kit({ svelte_config }) {
|
|
|
381
390
|
parsed_importer.name === parsed_service_worker.name;
|
|
382
391
|
|
|
383
392
|
if (importer_is_service_worker && id !== '$service-worker' && id !== '$env/static/public') {
|
|
384
|
-
const normalized_cwd = vite.normalizePath(cwd);
|
|
385
|
-
const normalized_lib = vite.normalizePath(kit.files.lib);
|
|
386
393
|
throw new Error(
|
|
387
394
|
`Cannot import ${normalize_id(
|
|
388
395
|
id,
|
|
@@ -400,6 +407,9 @@ async function kit({ svelte_config }) {
|
|
|
400
407
|
// ids with :$ don't work with reverse proxies like nginx
|
|
401
408
|
return `\0virtual:${id.substring(1)}`;
|
|
402
409
|
}
|
|
410
|
+
if (id === '__sveltekit/remote') {
|
|
411
|
+
return `${runtime_directory}/client/remote-functions/index.js`;
|
|
412
|
+
}
|
|
403
413
|
if (id.startsWith('__sveltekit/')) {
|
|
404
414
|
return `\0virtual:${id}`;
|
|
405
415
|
}
|
|
@@ -413,8 +423,6 @@ async function kit({ svelte_config }) {
|
|
|
413
423
|
: 'globalThis.__sveltekit_dev';
|
|
414
424
|
|
|
415
425
|
if (options?.ssr === false && process.env.TEST !== 'true') {
|
|
416
|
-
const normalized_cwd = vite.normalizePath(cwd);
|
|
417
|
-
const normalized_lib = vite.normalizePath(kit.files.lib);
|
|
418
426
|
if (
|
|
419
427
|
is_illegal(id, {
|
|
420
428
|
cwd: normalized_cwd,
|
|
@@ -580,6 +588,93 @@ Tips:
|
|
|
580
588
|
}
|
|
581
589
|
};
|
|
582
590
|
|
|
591
|
+
/** @type {import('vite').ViteDevServer} */
|
|
592
|
+
let dev_server;
|
|
593
|
+
|
|
594
|
+
/** @type {import('vite').Plugin} */
|
|
595
|
+
const plugin_remote = {
|
|
596
|
+
name: 'vite-plugin-sveltekit-remote',
|
|
597
|
+
|
|
598
|
+
configureServer(_dev_server) {
|
|
599
|
+
dev_server = _dev_server;
|
|
600
|
+
},
|
|
601
|
+
|
|
602
|
+
async transform(code, id, opts) {
|
|
603
|
+
if (!svelte_config.kit.moduleExtensions.some((ext) => id.endsWith(`.remote${ext}`))) {
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
const file = posixify(path.relative(cwd, id));
|
|
608
|
+
const hashed = hash(file);
|
|
609
|
+
|
|
610
|
+
if (opts?.ssr) {
|
|
611
|
+
// in dev, add metadata to remote functions by self-importing
|
|
612
|
+
if (dev_server) {
|
|
613
|
+
return (
|
|
614
|
+
code +
|
|
615
|
+
dedent`
|
|
616
|
+
import * as $$_self_$$ from './${path.basename(id)}';
|
|
617
|
+
import { validate_remote_functions as $$_validate_$$ } from '@sveltejs/kit/internal';
|
|
618
|
+
|
|
619
|
+
$$_validate_$$($$_self_$$, ${s(file)});
|
|
620
|
+
|
|
621
|
+
for (const [name, fn] of Object.entries($$_self_$$)) {
|
|
622
|
+
fn.__.id = ${s(hashed)} + '/' + name;
|
|
623
|
+
fn.__.name = name;
|
|
624
|
+
}
|
|
625
|
+
`
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// in prod, return as-is, and augment the build result instead.
|
|
630
|
+
// this allows us to treeshake non-dynamic `prerender` functions
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// For the client, read the exports and create a new module that only contains fetch functions with the correct metadata
|
|
635
|
+
|
|
636
|
+
/** @type {Map<string, import('types').RemoteInfo['type']>} */
|
|
637
|
+
const remotes = new Map();
|
|
638
|
+
|
|
639
|
+
// in dev, load the server module here (which will result in this hook
|
|
640
|
+
// being called again with `opts.ssr === true` if the module isn't
|
|
641
|
+
// already loaded) so we can determine what it exports
|
|
642
|
+
if (dev_server) {
|
|
643
|
+
const module = await dev_server.ssrLoadModule(id);
|
|
644
|
+
|
|
645
|
+
for (const [name, value] of Object.entries(module)) {
|
|
646
|
+
const type = value?.__?.type;
|
|
647
|
+
if (type) {
|
|
648
|
+
remotes.set(name, type);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// in prod, we already built and analysed the server code before
|
|
654
|
+
// building the client code, so `remote_exports` is populated
|
|
655
|
+
else if (remote_exports) {
|
|
656
|
+
const exports = remote_exports.get(hashed);
|
|
657
|
+
if (!exports) throw new Error('Expected to find metadata for remote file ' + id);
|
|
658
|
+
|
|
659
|
+
for (const [name, value] of exports) {
|
|
660
|
+
remotes.set(name, value.type);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
let namespace = '__remote';
|
|
665
|
+
let uid = 1;
|
|
666
|
+
while (remotes.has(namespace)) namespace = `__remote${uid++}`;
|
|
667
|
+
|
|
668
|
+
const exports = Array.from(remotes).map(([name, type]) => {
|
|
669
|
+
return `export const ${name} = ${namespace}.${type}('${hashed}/${name}');`;
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
return {
|
|
673
|
+
code: `import * as ${namespace} from '__sveltekit/remote';\n\n${exports.join('\n')}\n`
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
|
|
583
678
|
/** @type {import('vite').Plugin} */
|
|
584
679
|
const plugin_compile = {
|
|
585
680
|
name: 'vite-plugin-sveltekit-compile',
|
|
@@ -602,6 +697,7 @@ Tips:
|
|
|
602
697
|
if (ssr) {
|
|
603
698
|
input.index = `${runtime_directory}/server/index.js`;
|
|
604
699
|
input.internal = `${kit.outDir}/generated/server/internal.js`;
|
|
700
|
+
input['remote-entry'] = `${runtime_directory}/app/server/remote/index.js`;
|
|
605
701
|
|
|
606
702
|
// add entry points for every endpoint...
|
|
607
703
|
manifest_data.routes.forEach((route) => {
|
|
@@ -633,6 +729,11 @@ Tips:
|
|
|
633
729
|
const name = posixify(path.join('entries/matchers', key));
|
|
634
730
|
input[name] = path.resolve(file);
|
|
635
731
|
});
|
|
732
|
+
|
|
733
|
+
// ...and every .remote file
|
|
734
|
+
for (const remote of manifest_data.remotes) {
|
|
735
|
+
input[`remote/${remote.hash}`] = path.resolve(remote.file);
|
|
736
|
+
}
|
|
636
737
|
} else if (svelte_config.kit.output.bundleStrategy !== 'split') {
|
|
637
738
|
input['bundle'] = `${runtime_directory}/client/bundle.js`;
|
|
638
739
|
} else {
|
|
@@ -834,6 +935,8 @@ Tips:
|
|
|
834
935
|
output_config: svelte_config.output
|
|
835
936
|
});
|
|
836
937
|
|
|
938
|
+
remote_exports = metadata.remotes;
|
|
939
|
+
|
|
837
940
|
log.info('Building app');
|
|
838
941
|
|
|
839
942
|
// create client build
|
|
@@ -984,6 +1087,9 @@ Tips:
|
|
|
984
1087
|
static_exports
|
|
985
1088
|
);
|
|
986
1089
|
|
|
1090
|
+
// ...make sure remote exports have their IDs assigned...
|
|
1091
|
+
build_remotes(out, manifest_data);
|
|
1092
|
+
|
|
987
1093
|
// ...and prerender
|
|
988
1094
|
const { prerendered, prerender_map } = await prerender({
|
|
989
1095
|
hash: kit.router.type === 'hash',
|
|
@@ -1005,6 +1111,9 @@ Tips:
|
|
|
1005
1111
|
})};\n`
|
|
1006
1112
|
);
|
|
1007
1113
|
|
|
1114
|
+
// remove prerendered remote functions
|
|
1115
|
+
await treeshake_prerendered_remotes(out, manifest_data, metadata);
|
|
1116
|
+
|
|
1008
1117
|
if (service_worker_entry_file) {
|
|
1009
1118
|
if (kit.paths.assets) {
|
|
1010
1119
|
throw new Error('Cannot use service worker alongside config.kit.paths.assets');
|
|
@@ -1075,7 +1184,13 @@ Tips:
|
|
|
1075
1184
|
}
|
|
1076
1185
|
};
|
|
1077
1186
|
|
|
1078
|
-
return [
|
|
1187
|
+
return [
|
|
1188
|
+
plugin_setup,
|
|
1189
|
+
kit.experimental.remoteFunctions && plugin_remote,
|
|
1190
|
+
plugin_virtual_modules,
|
|
1191
|
+
plugin_guard,
|
|
1192
|
+
plugin_compile
|
|
1193
|
+
].filter((p) => !!p);
|
|
1079
1194
|
}
|
|
1080
1195
|
|
|
1081
1196
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import { posixify } from '../../utils/filesystem.js';
|
|
2
3
|
|
|
3
4
|
export const env_static_private = '\0virtual:env/static/private';
|
|
4
5
|
export const env_static_public = '\0virtual:env/static/public';
|
|
@@ -11,6 +12,6 @@ export const sveltekit_environment = '\0virtual:__sveltekit/environment';
|
|
|
11
12
|
export const sveltekit_paths = '\0virtual:__sveltekit/paths';
|
|
12
13
|
export const sveltekit_server = '\0virtual:__sveltekit/server';
|
|
13
14
|
|
|
14
|
-
export const app_server =
|
|
15
|
-
new URL('../../runtime/app/server/index.js', import.meta.url)
|
|
15
|
+
export const app_server = posixify(
|
|
16
|
+
fileURLToPath(new URL('../../runtime/app/server/index.js', import.meta.url))
|
|
16
17
|
);
|
|
@@ -128,8 +128,10 @@ export async function preview(vite, vite_config, svelte_config) {
|
|
|
128
128
|
|
|
129
129
|
const { pathname, search } = new URL(/** @type {string} */ (req.url), 'http://dummy');
|
|
130
130
|
|
|
131
|
+
const dir = pathname.startsWith(`/${svelte_config.kit.appDir}/remote/`) ? 'data' : 'pages';
|
|
132
|
+
|
|
131
133
|
let filename = normalizePath(
|
|
132
|
-
join(svelte_config.kit.outDir,
|
|
134
|
+
join(svelte_config.kit.outDir, `output/prerendered/${dir}` + pathname)
|
|
133
135
|
);
|
|
134
136
|
|
|
135
137
|
try {
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/** @import { RemoteCommand } from '@sveltejs/kit' */
|
|
2
|
+
/** @import { RemoteInfo, MaybePromise } from 'types' */
|
|
3
|
+
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
4
|
+
import { getRequestEvent } from '../event.js';
|
|
5
|
+
import { check_experimental, create_validator, run_remote_function } from './shared.js';
|
|
6
|
+
import { get_event_state } from '../../../server/event-state.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates a remote command. When called from the browser, the function will be invoked on the server via a `fetch` call.
|
|
10
|
+
*
|
|
11
|
+
* See [Remote functions](https://svelte.dev/docs/kit/remote-functions#command) for full documentation.
|
|
12
|
+
*
|
|
13
|
+
* @template Output
|
|
14
|
+
* @overload
|
|
15
|
+
* @param {() => Output} fn
|
|
16
|
+
* @returns {RemoteCommand<void, Output>}
|
|
17
|
+
* @since 2.27
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Creates a remote command. When called from the browser, the function will be invoked on the server via a `fetch` call.
|
|
21
|
+
*
|
|
22
|
+
* See [Remote functions](https://svelte.dev/docs/kit/remote-functions#command) for full documentation.
|
|
23
|
+
*
|
|
24
|
+
* @template Input
|
|
25
|
+
* @template Output
|
|
26
|
+
* @overload
|
|
27
|
+
* @param {'unchecked'} validate
|
|
28
|
+
* @param {(arg: Input) => Output} fn
|
|
29
|
+
* @returns {RemoteCommand<Input, Output>}
|
|
30
|
+
* @since 2.27
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Creates a remote command. When called from the browser, the function will be invoked on the server via a `fetch` call.
|
|
34
|
+
*
|
|
35
|
+
* See [Remote functions](https://svelte.dev/docs/kit/remote-functions#command) for full documentation.
|
|
36
|
+
*
|
|
37
|
+
* @template {StandardSchemaV1} Schema
|
|
38
|
+
* @template Output
|
|
39
|
+
* @overload
|
|
40
|
+
* @param {Schema} validate
|
|
41
|
+
* @param {(arg: StandardSchemaV1.InferOutput<Schema>) => Output} fn
|
|
42
|
+
* @returns {RemoteCommand<StandardSchemaV1.InferOutput<Schema>, Output>}
|
|
43
|
+
* @since 2.27
|
|
44
|
+
*/
|
|
45
|
+
/**
|
|
46
|
+
* @template Input
|
|
47
|
+
* @template Output
|
|
48
|
+
* @param {any} validate_or_fn
|
|
49
|
+
* @param {(arg?: Input) => Output} [maybe_fn]
|
|
50
|
+
* @returns {RemoteCommand<Input, Output>}
|
|
51
|
+
* @since 2.27
|
|
52
|
+
*/
|
|
53
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
54
|
+
export function command(validate_or_fn, maybe_fn) {
|
|
55
|
+
check_experimental('command');
|
|
56
|
+
|
|
57
|
+
/** @type {(arg?: Input) => Output} */
|
|
58
|
+
const fn = maybe_fn ?? validate_or_fn;
|
|
59
|
+
|
|
60
|
+
/** @type {(arg?: any) => MaybePromise<Input>} */
|
|
61
|
+
const validate = create_validator(validate_or_fn, maybe_fn);
|
|
62
|
+
|
|
63
|
+
/** @type {RemoteInfo} */
|
|
64
|
+
const __ = { type: 'command', id: '', name: '' };
|
|
65
|
+
|
|
66
|
+
/** @type {RemoteCommand<Input, Output> & { __: RemoteInfo }} */
|
|
67
|
+
const wrapper = (arg) => {
|
|
68
|
+
const event = getRequestEvent();
|
|
69
|
+
|
|
70
|
+
if (!event.isRemoteRequest) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`Cannot call a command (\`${__.name}(${maybe_fn ? '...' : ''})\`) during server-side rendering`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get_event_state(event).refreshes ??= {};
|
|
77
|
+
|
|
78
|
+
const promise = Promise.resolve(run_remote_function(event, true, arg, validate, fn));
|
|
79
|
+
|
|
80
|
+
// @ts-expect-error
|
|
81
|
+
promise.updates = () => {
|
|
82
|
+
throw new Error(`Cannot call '${__.name}(...).updates(...)' on the server`);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
return /** @type {ReturnType<RemoteCommand<Input, Output>>} */ (promise);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
Object.defineProperty(wrapper, '__', { value: __ });
|
|
89
|
+
|
|
90
|
+
return wrapper;
|
|
91
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/** @import { RemoteForm } from '@sveltejs/kit' */
|
|
2
|
+
/** @import { RemoteInfo, MaybePromise } from 'types' */
|
|
3
|
+
import { getRequestEvent } from '../event.js';
|
|
4
|
+
import { check_experimental, run_remote_function } from './shared.js';
|
|
5
|
+
import { get_event_state } from '../../../server/event-state.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates a form object that can be spread onto a `<form>` element.
|
|
9
|
+
*
|
|
10
|
+
* See [Remote functions](https://svelte.dev/docs/kit/remote-functions#form) for full documentation.
|
|
11
|
+
*
|
|
12
|
+
* @template T
|
|
13
|
+
* @param {(data: FormData) => MaybePromise<T>} fn
|
|
14
|
+
* @returns {RemoteForm<T>}
|
|
15
|
+
* @since 2.27
|
|
16
|
+
*/
|
|
17
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
18
|
+
// @ts-ignore we don't want to prefix `fn` with an underscore, as that will be user-visible
|
|
19
|
+
export function form(fn) {
|
|
20
|
+
check_experimental('form');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {string | number | boolean} [key]
|
|
24
|
+
*/
|
|
25
|
+
function create_instance(key) {
|
|
26
|
+
/** @type {RemoteForm<T>} */
|
|
27
|
+
const instance = {};
|
|
28
|
+
|
|
29
|
+
instance.method = 'POST';
|
|
30
|
+
instance.onsubmit = () => {};
|
|
31
|
+
|
|
32
|
+
Object.defineProperty(instance, 'enhance', {
|
|
33
|
+
value: () => {
|
|
34
|
+
return { action: instance.action, method: instance.method, onsubmit: instance.onsubmit };
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const button_props = {
|
|
39
|
+
type: 'submit',
|
|
40
|
+
onclick: () => {}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
Object.defineProperty(button_props, 'enhance', {
|
|
44
|
+
value: () => {
|
|
45
|
+
return { type: 'submit', formaction: instance.buttonProps.formaction, onclick: () => {} };
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
Object.defineProperty(instance, 'buttonProps', {
|
|
50
|
+
value: button_props
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
/** @type {RemoteInfo} */
|
|
54
|
+
const __ = {
|
|
55
|
+
type: 'form',
|
|
56
|
+
name: '',
|
|
57
|
+
id: '',
|
|
58
|
+
/** @param {FormData} form_data */
|
|
59
|
+
fn: async (form_data) => {
|
|
60
|
+
const event = getRequestEvent();
|
|
61
|
+
const state = get_event_state(event);
|
|
62
|
+
|
|
63
|
+
state.refreshes ??= {};
|
|
64
|
+
|
|
65
|
+
const result = await run_remote_function(event, true, form_data, (d) => d, fn);
|
|
66
|
+
|
|
67
|
+
// We don't need to care about args or deduplicating calls, because uneval results are only relevant in full page reloads
|
|
68
|
+
// where only one form submission is active at the same time
|
|
69
|
+
if (!event.isRemoteRequest) {
|
|
70
|
+
state.form_result = [key, result];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
Object.defineProperty(instance, '__', { value: __ });
|
|
78
|
+
|
|
79
|
+
Object.defineProperty(instance, 'action', {
|
|
80
|
+
get: () => `?/remote=${__.id}`,
|
|
81
|
+
enumerable: true
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
Object.defineProperty(button_props, 'formaction', {
|
|
85
|
+
get: () => `?/remote=${__.id}`,
|
|
86
|
+
enumerable: true
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
Object.defineProperty(instance, 'result', {
|
|
90
|
+
get() {
|
|
91
|
+
try {
|
|
92
|
+
const { form_result } = get_event_state(getRequestEvent());
|
|
93
|
+
return form_result && form_result[0] === key ? form_result[1] : undefined;
|
|
94
|
+
} catch {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if (key == undefined) {
|
|
101
|
+
Object.defineProperty(instance, 'for', {
|
|
102
|
+
/** @type {RemoteForm<any>['for']} */
|
|
103
|
+
value: (key) => {
|
|
104
|
+
const state = get_event_state(getRequestEvent());
|
|
105
|
+
let instance = (state.form_instances ??= new Map()).get(key);
|
|
106
|
+
|
|
107
|
+
if (!instance) {
|
|
108
|
+
instance = create_instance(key);
|
|
109
|
+
instance.__.id = `${__.id}/${encodeURIComponent(JSON.stringify(key))}`;
|
|
110
|
+
instance.__.name = __.name;
|
|
111
|
+
|
|
112
|
+
state.form_instances.set(key, instance);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return instance;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return instance;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return create_instance();
|
|
124
|
+
}
|