Skip to content

Commit f3b5bfb

Browse files
authored
feat: async SSR (#14447)
* chore: use catalog version for svelte dev dependency * WIP async SSR * bump * partial fix * bump * catalog version * WIP * tidy up * WIP * construct relative paths from event store * wait really typescript? * revert * fix * changeset * fix * use pkg.imports
1 parent d4efeb5 commit f3b5bfb

33 files changed

+417
-368
lines changed

.changeset/full-bats-itch.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: experimental async SSR

packages/kit/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@
8787
"generate:version": "node scripts/generate-version.js",
8888
"generate:types": "node scripts/generate-dts.js"
8989
},
90+
"imports": {
91+
"#app/paths": {
92+
"browser": "./src/runtime/app/paths/client.js",
93+
"default": "./src/runtime/app/paths/server.js"
94+
}
95+
},
9096
"exports": {
9197
"./package.json": "./package.json",
9298
".": {

packages/kit/scripts/generate-dts.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ await createBundle({
1212
'$app/environment': 'src/runtime/app/environment/types.d.ts',
1313
'$app/forms': 'src/runtime/app/forms.js',
1414
'$app/navigation': 'src/runtime/app/navigation.js',
15-
'$app/paths': 'src/runtime/app/paths/types.d.ts',
15+
'$app/paths': 'src/runtime/app/paths/public.d.ts',
1616
'$app/server': 'src/runtime/app/server/index.js',
1717
'$app/state': 'src/runtime/app/state/index.js',
1818
'$app/stores': 'src/runtime/app/stores.js'

packages/kit/src/core/sync/write_server.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ const server_template = ({
3131
}) => `
3232
import root from '../root.${isSvelte5Plus() ? 'js' : 'svelte'}';
3333
import { set_building, set_prerendering } from '__sveltekit/environment';
34-
import { set_assets } from '__sveltekit/paths';
34+
import { set_assets } from '$app/paths/internal/server';
3535
import { set_manifest, set_read_implementation } from '__sveltekit/server';
3636
import { set_private_env, set_public_env } from '${runtime_directory}/shared-server.js';
3737
3838
export const options = {
3939
app_template_contains_nonce: ${template.includes('%sveltekit.nonce%')},
40+
async: ${s(!!config.compilerOptions?.experimental?.async)},
4041
csp: ${s(config.kit.csp)},
4142
csrf_check_origin: ${s(config.kit.csrf.checkOrigin && !config.kit.csrf.trustedOrigins.includes('*'))},
4243
csrf_trusted_origins: ${s(config.kit.csrf.trustedOrigins)},

packages/kit/src/exports/vite/dev/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ export async function dev(vite, vite_config, svelte_config, get_remotes) {
522522
);
523523
set_fix_stack_trace(fix_stack_trace);
524524

525-
const { set_assets } = await vite.ssrLoadModule('__sveltekit/paths');
525+
const { set_assets } = await vite.ssrLoadModule('$app/paths/internal/server');
526526
set_assets(assets);
527527

528528
const server = new Server(manifest);

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

Lines changed: 14 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import {
3636
env_static_public,
3737
service_worker,
3838
sveltekit_environment,
39-
sveltekit_paths,
4039
sveltekit_server
4140
} from './module_ids.js';
4241
import { import_peer } from '../../utils/import.js';
@@ -318,26 +317,34 @@ async function kit({ svelte_config }) {
318317
// because they for example use esbuild.build with `platform: 'browser'`
319318
'esm-env',
320319
// This forces `$app/*` modules to be bundled, since they depend on
321-
// virtual modules like `__sveltekit/paths` (this isn't a valid bare
320+
// virtual modules like `__sveltekit/environment` (this isn't a valid bare
322321
// import, but it works with vite-node's externalization logic, which
323322
// uses basic concatenation)
324323
'@sveltejs/kit/src/runtime'
325324
]
326325
}
327326
};
328327

328+
const define = {
329+
__SVELTEKIT_APP_DIR__: s(kit.appDir),
330+
__SVELTEKIT_EMBEDDED__: s(kit.embedded),
331+
__SVELTEKIT_EXPERIMENTAL__REMOTE_FUNCTIONS__: s(kit.experimental.remoteFunctions),
332+
__SVELTEKIT_PATHS_ASSETS__: s(kit.paths.assets),
333+
__SVELTEKIT_PATHS_BASE__: s(kit.paths.base),
334+
__SVELTEKIT_PATHS_RELATIVE__: s(kit.paths.relative),
335+
__SVELTEKIT_CLIENT_ROUTING__: s(kit.router.resolution === 'client'),
336+
__SVELTEKIT_SERVER_TRACING_ENABLED__: s(kit.experimental.tracing.server)
337+
};
338+
329339
if (is_build) {
330340
if (!new_config.build) new_config.build = {};
331341
new_config.build.ssr = !secondary_build_started;
332342

333343
new_config.define = {
344+
...define,
334345
__SVELTEKIT_ADAPTER_NAME__: s(kit.adapter?.name),
335346
__SVELTEKIT_APP_VERSION_FILE__: s(`${kit.appDir}/version.json`),
336347
__SVELTEKIT_APP_VERSION_POLL_INTERVAL__: s(kit.version.pollInterval),
337-
__SVELTEKIT_EMBEDDED__: s(kit.embedded),
338-
__SVELTEKIT_EXPERIMENTAL__REMOTE_FUNCTIONS__: s(kit.experimental.remoteFunctions),
339-
__SVELTEKIT_CLIENT_ROUTING__: s(kit.router.resolution === 'client'),
340-
__SVELTEKIT_SERVER_TRACING_ENABLED__: s(kit.experimental.tracing.server),
341348
__SVELTEKIT_PAYLOAD__: new_config.build.ssr
342349
? '{}'
343350
: `globalThis.__sveltekit_${version_hash}`
@@ -348,11 +355,8 @@ async function kit({ svelte_config }) {
348355
}
349356
} else {
350357
new_config.define = {
358+
...define,
351359
__SVELTEKIT_APP_VERSION_POLL_INTERVAL__: '0',
352-
__SVELTEKIT_EMBEDDED__: s(kit.embedded),
353-
__SVELTEKIT_EXPERIMENTAL__REMOTE_FUNCTIONS__: s(kit.experimental.remoteFunctions),
354-
__SVELTEKIT_CLIENT_ROUTING__: s(kit.router.resolution === 'client'),
355-
__SVELTEKIT_SERVER_TRACING_ENABLED__: s(kit.experimental.tracing.server),
356360
__SVELTEKIT_PAYLOAD__: 'globalThis.__sveltekit_dev'
357361
};
358362

@@ -460,48 +464,6 @@ async function kit({ svelte_config }) {
460464
case service_worker:
461465
return create_service_worker_module(svelte_config);
462466

463-
// for internal use only. it's published as $app/paths externally
464-
// we use this alias so that we won't collide with user aliases
465-
case sveltekit_paths: {
466-
const { assets, base } = svelte_config.kit.paths;
467-
468-
// use the values defined in `global`, but fall back to hard-coded values
469-
// for the sake of things like Vitest which may import this module
470-
// outside the context of a page
471-
if (browser) {
472-
return dedent`
473-
export const base = ${global}?.base ?? ${s(base)};
474-
export const assets = ${global}?.assets ?? ${assets ? s(assets) : 'base'};
475-
export const app_dir = ${s(kit.appDir)};
476-
`;
477-
}
478-
479-
return dedent`
480-
export let base = ${s(base)};
481-
export let assets = ${assets ? s(assets) : 'base'};
482-
export const app_dir = ${s(kit.appDir)};
483-
484-
export const relative = ${svelte_config.kit.paths.relative};
485-
486-
const initial = { base, assets };
487-
488-
export function override(paths) {
489-
base = paths.base;
490-
assets = paths.assets;
491-
}
492-
493-
export function reset() {
494-
base = initial.base;
495-
assets = initial.assets;
496-
}
497-
498-
/** @param {string} path */
499-
export function set_assets(path) {
500-
assets = initial.assets = path;
501-
}
502-
`;
503-
}
504-
505467
case sveltekit_environment: {
506468
const { version } = svelte_config.kit;
507469

packages/kit/src/exports/vite/module_ids.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ export const env_dynamic_public = '\0virtual:env/dynamic/public';
99
export const service_worker = '\0virtual:service-worker';
1010

1111
export const sveltekit_environment = '\0virtual:__sveltekit/environment';
12-
export const sveltekit_paths = '\0virtual:__sveltekit/paths';
1312
export const sveltekit_server = '\0virtual:__sveltekit/server';
1413

1514
export const app_server = posixify(
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/** @import { Asset, RouteId, Pathname, ResolvedPathname } from '$app/types' */
2+
/** @import { ResolveArgs } from './types.js' */
3+
import { base, assets } from './internal/client.js';
4+
import { resolve_route } from '../../../utils/routing.js';
5+
6+
/**
7+
* Resolve the URL of an asset in your `static` directory, by prefixing it with [`config.kit.paths.assets`](https://svelte.dev/docs/kit/configuration#paths) if configured, or otherwise by prefixing it with the base path.
8+
*
9+
* During server rendering, the base path is relative and depends on the page currently being rendered.
10+
*
11+
* @example
12+
* ```svelte
13+
* <script>
14+
* import { asset } from '$app/paths';
15+
* </script>
16+
*
17+
* <img alt="a potato" src={asset('/potato.jpg')} />
18+
* ```
19+
* @since 2.26
20+
*
21+
* @param {Asset} file
22+
* @returns {string}
23+
*/
24+
export function asset(file) {
25+
return (assets || base) + file;
26+
}
27+
28+
/**
29+
* Resolve a pathname by prefixing it with the base path, if any, or resolve a route ID by populating dynamic segments with parameters.
30+
*
31+
* During server rendering, the base path is relative and depends on the page currently being rendered.
32+
*
33+
* @example
34+
* ```js
35+
* import { resolve } from '$app/paths';
36+
*
37+
* // using a pathname
38+
* const resolved = resolve(`/blog/hello-world`);
39+
*
40+
* // using a route ID plus parameters
41+
* const resolved = resolve('/blog/[slug]', {
42+
* slug: 'hello-world'
43+
* });
44+
* ```
45+
* @since 2.26
46+
*
47+
* @template {RouteId | Pathname} T
48+
* @param {ResolveArgs<T>} args
49+
* @returns {ResolvedPathname}
50+
*/
51+
export function resolve(...args) {
52+
// The type error is correct here, and if someone doesn't pass params when they should there's a runtime error,
53+
// but we don't want to adjust the internal resolve_route function to accept `undefined`, hence the type cast.
54+
return base + resolve_route(args[0], /** @type {Record<string, string>} */ (args[1]));
55+
}
56+
57+
export { base, assets, resolve as resolveRoute };
Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1 @@
1-
import { base, assets } from '__sveltekit/paths';
2-
import { resolve_route } from '../../../utils/routing.js';
3-
4-
/** @type {import('./types.d.ts').asset} */
5-
export function asset(file) {
6-
return (assets || base) + file;
7-
}
8-
9-
/** @type {import('./types.d.ts').resolve} */
10-
export function resolve(id, params) {
11-
// The type error is correct here, and if someone doesn't pass params when they should there's a runtime error,
12-
// but we don't want to adjust the internal resolve_route function to accept `undefined`, hence the type cast.
13-
return base + resolve_route(id, /** @type {Record<string, string>} */ (params));
14-
}
15-
16-
export { base, assets, resolve as resolveRoute };
1+
export * from '#app/paths';
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const base = __SVELTEKIT_PAYLOAD__?.base ?? __SVELTEKIT_PATHS_BASE__;
2+
export const assets = __SVELTEKIT_PAYLOAD__?.assets ?? base ?? __SVELTEKIT_PATHS_ASSETS__;
3+
export const app_dir = __SVELTEKIT_APP_DIR__;

0 commit comments

Comments
 (0)