@sveltejs/kit 3.0.0-next.6 → 3.0.0-next.8

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.
Files changed (80) hide show
  1. package/package.json +8 -3
  2. package/src/core/adapt/builder.js +11 -39
  3. package/src/core/config/index.js +76 -71
  4. package/src/core/config/options.js +280 -285
  5. package/src/core/config/types.d.ts +1 -1
  6. package/src/core/env.js +86 -1
  7. package/src/core/generate_manifest/index.js +12 -15
  8. package/src/core/sync/create_manifest_data/index.js +7 -45
  9. package/src/core/sync/sync.js +0 -2
  10. package/src/core/sync/write_client_manifest.js +7 -21
  11. package/src/core/sync/write_non_ambient.js +12 -9
  12. package/src/core/sync/write_server.js +0 -4
  13. package/src/core/sync/write_types/index.js +28 -24
  14. package/src/core/utils.js +2 -2
  15. package/src/exports/index.js +3 -3
  16. package/src/exports/internal/client.js +5 -0
  17. package/src/exports/internal/index.js +1 -91
  18. package/src/exports/internal/{event.js → server/event.js} +1 -2
  19. package/src/exports/internal/server/index.js +33 -0
  20. package/src/exports/internal/shared.js +89 -0
  21. package/src/exports/node/index.js +5 -9
  22. package/src/exports/params.js +63 -0
  23. package/src/exports/public.d.ts +103 -46
  24. package/src/exports/url.js +84 -0
  25. package/src/exports/vite/dev/index.js +31 -20
  26. package/src/exports/vite/index.js +280 -199
  27. package/src/exports/vite/preview/index.js +14 -15
  28. package/src/exports/vite/utils.js +8 -10
  29. package/src/runtime/app/env/internal.js +4 -4
  30. package/src/runtime/app/forms.js +2 -2
  31. package/src/runtime/app/paths/client.js +3 -7
  32. package/src/runtime/app/paths/internal/client.js +4 -2
  33. package/src/runtime/app/paths/internal/server.js +2 -23
  34. package/src/runtime/app/paths/server.js +3 -3
  35. package/src/runtime/app/server/remote/query.js +6 -12
  36. package/src/runtime/app/state/client.js +1 -2
  37. package/src/runtime/app/stores.js +13 -76
  38. package/src/runtime/client/bundle.js +1 -1
  39. package/src/runtime/client/client-entry.js +3 -0
  40. package/src/runtime/client/client.js +230 -238
  41. package/src/runtime/client/entry.js +24 -3
  42. package/src/runtime/client/payload.js +17 -0
  43. package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
  44. package/src/runtime/client/remote-functions/form.svelte.js +11 -30
  45. package/src/runtime/client/remote-functions/prerender.svelte.js +10 -3
  46. package/src/runtime/client/remote-functions/query/instance.svelte.js +18 -9
  47. package/src/runtime/client/remote-functions/query-live/instance.svelte.js +16 -6
  48. package/src/runtime/client/remote-functions/shared.svelte.js +1 -2
  49. package/src/runtime/client/state.svelte.js +66 -49
  50. package/src/runtime/client/types.d.ts +3 -7
  51. package/src/runtime/client/utils.js +0 -96
  52. package/src/runtime/components/root.svelte +66 -0
  53. package/src/runtime/form-utils.js +16 -6
  54. package/src/runtime/server/cookie.js +17 -7
  55. package/src/runtime/server/index.js +1 -1
  56. package/src/runtime/server/page/index.js +7 -14
  57. package/src/runtime/server/page/load_data.js +1 -1
  58. package/src/runtime/server/page/render.js +72 -88
  59. package/src/runtime/server/page/server_routing.js +13 -9
  60. package/src/runtime/server/remote.js +23 -13
  61. package/src/runtime/server/respond.js +11 -8
  62. package/src/runtime/server/utils.js +28 -5
  63. package/src/runtime/telemetry/otel.js +1 -1
  64. package/src/runtime/types.d.ts +8 -0
  65. package/src/types/ambient.d.ts +5 -1
  66. package/src/types/global-private.d.ts +11 -18
  67. package/src/types/internal.d.ts +25 -30
  68. package/src/utils/error.js +1 -1
  69. package/src/utils/import.js +6 -1
  70. package/src/utils/mime.js +9 -0
  71. package/src/utils/params.js +66 -0
  72. package/src/utils/routing.js +90 -44
  73. package/src/utils/streaming.js +14 -4
  74. package/src/utils/url.js +0 -79
  75. package/src/version.js +1 -1
  76. package/types/index.d.ts +127 -125
  77. package/types/index.d.ts.map +12 -8
  78. package/src/core/sync/write_root.js +0 -148
  79. package/src/exports/internal/server.js +0 -22
  80. /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
@@ -1,7 +1,8 @@
1
1
  /** @import { EnvVarConfig, KitConfig } from '@sveltejs/kit' */
2
2
  /** @import { Options, SvelteConfig } from '@sveltejs/vite-plugin-svelte' */
3
3
  /** @import { PreprocessorGroup } from 'svelte/compiler' */
4
- /** @import { Plugin, Manifest, ResolvedConfig, UserConfig, ViteDevServer, Rolldown } from 'vite' */
4
+ /** @import { BuildData, ManifestData, Prerendered, ServerMetadata, RemoteInternals, ValidatedConfig, ValidatedKitConfig } from 'types' */
5
+ /** @import { Manifest, Plugin, ResolvedConfig, Rolldown, UserConfig, ViteDevServer } from 'vite' */
5
6
  import fs from 'node:fs';
6
7
  import path from 'node:path';
7
8
  import process from 'node:process';
@@ -17,10 +18,12 @@ import {
17
18
  resolve_explicit_env_entry,
18
19
  create_sveltekit_env_service_worker,
19
20
  create_sveltekit_env_service_worker_dev,
20
- create_sveltekit_env_private
21
+ create_sveltekit_env_private,
22
+ create_exported_declarations
21
23
  } from '../../core/env.js';
22
24
  import * as sync from '../../core/sync/sync.js';
23
25
  import { create_assets } from '../../core/sync/create_manifest_data/index.js';
26
+ import { load_and_validate_params } from '../../utils/params.js';
24
27
  import { runtime_directory, logger } from '../../core/utils.js';
25
28
  import { generate_manifest } from '../../core/generate_manifest/index.js';
26
29
  import { build_server_nodes } from './build/build_server.js';
@@ -54,10 +57,14 @@ import {
54
57
  import { import_peer } from '../../utils/import.js';
55
58
  import { compact } from '../../utils/array.js';
56
59
  import { should_ignore, has_children } from './static_analysis/utils.js';
57
- import { process_config, split_config } from '../../core/config/index.js';
60
+ import { process_config, split_config, validate_config } from '../../core/config/index.js';
58
61
  import { treeshake_prerendered_remotes } from './build/remote.js';
59
62
 
60
- /** @type {string} */
63
+ /**
64
+ * The posix-ified root of the project based on the Vite configuration.
65
+ * Populated after Vite plugins' `config` hooks run
66
+ * @type {string}
67
+ */
61
68
  let root;
62
69
 
63
70
  /** @type {import('./types.js').EnforcedConfig} */
@@ -162,7 +169,7 @@ export async function sveltekit(config) {
162
169
  // any options passed to the plugin that SvelteKit doesn't use itself are
163
170
  // forwarded to vite-plugin-svelte, which does its own validation
164
171
  const split = split_config(config ?? {});
165
- const svelte_config = process_config(split.svelte_config, { cwd });
172
+ const svelte_config = validate_config(split.svelte_config);
166
173
 
167
174
  if (Array.isArray(svelte_config.preprocess)) {
168
175
  svelte_config.preprocess.push(warning_preprocessor);
@@ -197,7 +204,7 @@ export async function sveltekit(config) {
197
204
  }
198
205
 
199
206
  return [
200
- plugin_svelte_config(),
207
+ plugin_root(),
201
208
  ...vite_plugin_svelte.svelte(inline_vps_config),
202
209
  ...kit({
203
210
  svelte_config
@@ -213,7 +220,7 @@ function resolve_root(vite_config) {
213
220
  /**
214
221
  * @return {Plugin}
215
222
  */
216
- function plugin_svelte_config() {
223
+ function plugin_root() {
217
224
  return {
218
225
  name: 'vite-plugin-sveltekit-resolve-svelte-config',
219
226
  // make sure it runs first
@@ -223,9 +230,8 @@ function plugin_svelte_config() {
223
230
  handler(config) {
224
231
  root = resolve_root(config);
225
232
 
226
- // TODO: mjs mts?
227
233
  const config_file = ['svelte.config.js', 'svelte.config.ts'].find((file) =>
228
- fs.existsSync(`${root}/${file}`)
234
+ fs.existsSync(path.join(root, file))
229
235
  );
230
236
  if (config_file) {
231
237
  throw new Error(
@@ -255,14 +261,14 @@ function plugin_svelte_config() {
255
261
  * - https://rolldown.rs/apis/plugin-api#output-generation-hooks
256
262
  *
257
263
  * @param {object} opts
258
- * @param {import('types').ValidatedConfig} opts.svelte_config options are only resolved after the Vite `config` hook runs
264
+ * @param {ValidatedConfig} opts.svelte_config
259
265
  * @return {Plugin[]}
260
266
  */
261
267
  function kit({ svelte_config }) {
262
268
  /** @type {typeof import('vite')} */
263
269
  let vite;
264
270
 
265
- /** @type {import('types').ValidatedKitConfig} */
271
+ /** @type {ValidatedKitConfig} */
266
272
  let kit;
267
273
  /** @type {string} `kit.outDir` but posix-ified */
268
274
  let out_dir;
@@ -281,17 +287,17 @@ function kit({ svelte_config }) {
281
287
  /** @type {Record<string, string>} */
282
288
  let env;
283
289
 
284
- /** @type {import('types').ManifestData} */
290
+ /** @type {ManifestData} */
285
291
  let manifest_data;
286
292
 
287
- /** @type {import('types').ServerMetadata | undefined} only set at build time once analysis is finished */
293
+ /** @type {ServerMetadata | undefined} only set at build time once analysis is finished */
288
294
  let build_metadata = undefined;
289
295
 
290
296
  /** @type {UserConfig} */
291
297
  let initial_config;
292
298
 
293
299
  /** @type {string | null} */
294
- let service_worker_entry_file = resolve_entry(svelte_config.kit.files.serviceWorker);
300
+ let service_worker_entry_file;
295
301
  /** @type {import('node:path').ParsedPath} */
296
302
  let parsed_service_worker;
297
303
 
@@ -321,10 +327,6 @@ function kit({ svelte_config }) {
321
327
  options: svelte_config
322
328
  },
323
329
 
324
- applyToEnvironment(environment) {
325
- return environment.name !== 'serviceWorker';
326
- },
327
-
328
330
  /**
329
331
  * Build the SvelteKit-provided Vite config to be merged with the user's vite.config.js file.
330
332
  * @see https://vitejs.dev/guide/api-plugin.html#config
@@ -335,7 +337,7 @@ function kit({ svelte_config }) {
335
337
  initial_config = config;
336
338
  is_build = config_env.command === 'build';
337
339
 
338
- ({ kit } = svelte_config);
340
+ ({ kit } = process_config(svelte_config, root));
339
341
  out_dir = posixify(kit.outDir);
340
342
  out = `${out_dir}/output`;
341
343
 
@@ -457,7 +459,7 @@ function kit({ svelte_config }) {
457
459
  }
458
460
 
459
461
  const define = {
460
- __SVELTEKIT_APP_DIR__: s(kit.appDir),
462
+ __SVELTEKIT_APP_DIR__: s(posixify(kit.appDir)),
461
463
  __SVELTEKIT_APP_VERSION__: s(kit.version.name),
462
464
  __SVELTEKIT_EMBEDDED__: s(kit.embedded),
463
465
  __SVELTEKIT_FORK_PRELOADS__: s(kit.experimental.forkPreloads),
@@ -466,8 +468,10 @@ function kit({ svelte_config }) {
466
468
  __SVELTEKIT_PATHS_RELATIVE__: s(kit.paths.relative),
467
469
  __SVELTEKIT_CLIENT_ROUTING__: s(kit.router.resolution === 'client'),
468
470
  __SVELTEKIT_HASH_ROUTING__: s(kit.router.type === 'hash'),
469
- __SVELTEKIT_SERVER_TRACING_ENABLED__: s(kit.experimental.tracing.server),
470
- __SVELTEKIT_EXPERIMENTAL_USE_TRANSFORM_ERROR__: s(kit.experimental.handleRenderingErrors),
471
+ __SVELTEKIT_SERVER_TRACING_ENABLED__: s(kit.tracing.server),
472
+ __SVELTEKIT_SUPPORTS_ASYNC__: s(
473
+ svelte_config.compilerOptions?.experimental?.async ?? false
474
+ ),
471
475
  __SVELTEKIT_ROOT__: s(root),
472
476
  __SVELTEKIT_DEV__: s(!is_build)
473
477
  };
@@ -485,7 +489,7 @@ function kit({ svelte_config }) {
485
489
  new_config.define = {
486
490
  ...define,
487
491
  __SVELTEKIT_APP_VERSION_POLL_INTERVAL__: '0',
488
- __SVELTEKIT_PAYLOAD__: kit_global,
492
+ __SVELTEKIT_PAYLOAD__: kit_global, // only relevant when bundleStrategy !== 'split'
489
493
  __SVELTEKIT_HAS_SERVER_LOAD__: 'true',
490
494
  __SVELTEKIT_HAS_UNIVERSAL_LOAD__: 'true'
491
495
  };
@@ -495,6 +499,23 @@ function kit({ svelte_config }) {
495
499
  /** @type {NonNullable<UserConfig['ssr']>} */ (new_config.ssr).external = ['cookie'];
496
500
  }
497
501
 
502
+ // Vite's `define` is a compile-time text replacement, but Vitest strips
503
+ // user `define` from the server config and reinstalls the values only as
504
+ // `globalThis` properties inside test workers, so anything
505
+ // that runs outside of a test will freak out over
506
+ // them not being defined
507
+ if (process.env.VITEST === 'true') {
508
+ for (const key in new_config.define) {
509
+ const value = new_config.define[key];
510
+ try {
511
+ /** @type {Record<string, any>} */ (globalThis)[key] = JSON.parse(value);
512
+ } catch {
513
+ // `kit_global` isn't JSON, so don't try to parse it. We may one day
514
+ // need to define it in Vitest somehow but for now, ignore it
515
+ }
516
+ }
517
+ }
518
+
498
519
  warn_overridden_config(config, new_config);
499
520
 
500
521
  return new_config;
@@ -519,10 +540,6 @@ function kit({ svelte_config }) {
519
540
  const plugin_virtual_modules = {
520
541
  name: 'vite-plugin-sveltekit-virtual-modules',
521
542
 
522
- applyToEnvironment(environment) {
523
- return environment.name !== 'serviceWorker';
524
- },
525
-
526
543
  async configResolved(config) {
527
544
  explicit_env_entry = resolve_explicit_env_entry(kit);
528
545
  explicit_env_config = await sync.env(kit, explicit_env_entry, config.root, config.mode);
@@ -558,6 +575,10 @@ function kit({ svelte_config }) {
558
575
  });
559
576
  },
560
577
 
578
+ applyToEnvironment(environment) {
579
+ return environment.name !== 'serviceWorker';
580
+ },
581
+
561
582
  resolveId: {
562
583
  filter: {
563
584
  id: [exactRegex('$service-worker'), prefixRegex('__sveltekit/')]
@@ -598,13 +619,13 @@ function kit({ svelte_config }) {
598
619
  return create_service_worker_module(svelte_config);
599
620
 
600
621
  case sveltekit_env:
601
- return create_sveltekit_env(explicit_env_config, env, explicit_env_entry);
622
+ return create_sveltekit_env(explicit_env_config, env, explicit_env_entry, !is_build);
602
623
 
603
624
  case sveltekit_env_public_client:
604
625
  return create_sveltekit_env_public(
605
626
  explicit_env_config,
606
627
  env,
607
- `const env = ${kit_global}.env;`
628
+ `import { payload } from ${s(`${runtime_directory}/client/payload.js`)};\nconst env = payload.env;`
608
629
  );
609
630
 
610
631
  case sveltekit_env_public_server:
@@ -630,18 +651,18 @@ function kit({ svelte_config }) {
630
651
 
631
652
  case sveltekit_server: {
632
653
  return dedent`
633
- export let read_implementation = null;
654
+ export let read_implementation = null;
634
655
 
635
- export let manifest = null;
656
+ export let manifest = null;
636
657
 
637
- export function set_read_implementation(fn) {
638
- read_implementation = fn;
639
- }
658
+ export function set_read_implementation(fn) {
659
+ read_implementation = fn;
660
+ }
640
661
 
641
- export function set_manifest(_) {
642
- manifest = _;
643
- }
644
- `;
662
+ export function set_manifest(_) {
663
+ manifest = _;
664
+ }
665
+ `;
645
666
  }
646
667
  }
647
668
  }
@@ -722,11 +743,7 @@ function kit({ svelte_config }) {
722
743
  (normalized.startsWith('$lib/') && server_only_directory_pattern.test(id)) ||
723
744
  (is_internal && server_only_module_pattern.test(id));
724
745
 
725
- // skip .server.js files outside the cwd or in node_modules, as the filename might not mean 'server-only module' in this context
726
- // TODO: address https://github.com/sveltejs/kit/issues/12529
727
- if (!is_server_only) {
728
- return;
729
- }
746
+ if (!is_server_only) return;
730
747
 
731
748
  // in dev, this doesn't exist, so we need to create it
732
749
  manifest_data ??= sync.all(svelte_config, root).manifest_data;
@@ -741,49 +758,56 @@ function kit({ svelte_config }) {
741
758
  if (manifest_data.hooks.client) entrypoints.add(manifest_data.hooks.client);
742
759
  if (manifest_data.hooks.universal) entrypoints.add(manifest_data.hooks.universal);
743
760
 
744
- const chain = [normalized];
745
-
746
- let current = normalized;
747
- let includes_remote_file = false;
761
+ // Walk up the import graph from the server-only module, looking for a chain
762
+ // that leads back to a client entrypoint. We search all candidates (not just
763
+ // the first) because a module can be imported by both server and client code,
764
+ // and a greedy first-match could follow a server-only branch that never
765
+ // reaches an entrypoint — see https://github.com/sveltejs/kit/issues/16232
766
+ /** @type {Set<string>} */
767
+ const visited = new Set([normalized]);
748
768
 
749
- while (true) {
769
+ /**
770
+ * @param {string} current
771
+ * @param {string[]} chain
772
+ * @returns {string[] | null}
773
+ */
774
+ function find_chain(current, chain) {
750
775
  const importers = import_map.get(current);
751
- if (!importers) break;
776
+ if (!importers) return null;
752
777
 
753
- const candidates = Array.from(importers).filter((importer) => !chain.includes(importer));
754
- if (candidates.length === 0) break;
778
+ for (const importer of importers) {
779
+ if (visited.has(importer)) continue;
780
+ visited.add(importer);
755
781
 
756
- chain.push((current = candidates[0]));
782
+ const next_chain = [...chain, importer];
783
+ if (entrypoints.has(importer)) {
784
+ return next_chain;
785
+ }
786
+ const result = find_chain(importer, next_chain);
787
+ if (result) return result;
788
+ }
789
+ return null;
790
+ }
757
791
 
758
- includes_remote_file ||= svelte_config.kit.moduleExtensions.some((ext) => {
759
- return current.endsWith(`.remote${ext}`);
760
- });
792
+ const chain = find_chain(normalized, [normalized]);
761
793
 
762
- if (entrypoints.has(current)) {
763
- const pyramid = chain
764
- .reverse()
765
- .map((id, i) => {
766
- return `${' '.repeat(i + 1)}${id}`;
767
- })
768
- .join(' imports\n');
769
-
770
- if (includes_remote_file) {
771
- error_for_missing_config(
772
- 'remote functions',
773
- 'kit.experimental.remoteFunctions',
774
- 'true'
775
- );
776
- }
794
+ if (chain) {
795
+ const pyramid = chain
796
+ .reverse()
797
+ .map((id, i) => {
798
+ return `${' '.repeat(i + 1)}${id}`;
799
+ })
800
+ .join(' imports\n');
777
801
 
778
- let message = `Cannot import ${normalized} into code that runs in the browser, as this could leak sensitive information.`;
779
- message += `\n\n${pyramid}`;
780
- message += `\n\nIf you're only using the import as a type, change it to \`import type\`.`;
802
+ let message = `Cannot import ${normalized} into code that runs in the browser, as this could leak sensitive information.`;
803
+ message += `\n\n${pyramid}`;
804
+ message += `\n\nIf you're only using the import as a type, change it to \`import type\`.`;
781
805
 
782
- throw stackless(message);
783
- }
806
+ throw stackless(message);
784
807
  }
785
808
 
786
- throw new Error('An impossible situation occurred');
809
+ // No chain from this server-only module to a client entrypoint was found —
810
+ // the module is only imported from server code, which is valid.
787
811
  }
788
812
  }
789
813
  };
@@ -805,7 +829,7 @@ function kit({ svelte_config }) {
805
829
  name: 'vite-plugin-sveltekit-remote',
806
830
 
807
831
  applyToEnvironment(environment) {
808
- return environment.name !== 'serviceWorker';
832
+ return svelte_config.kit.experimental.remoteFunctions && environment.name !== 'serviceWorker';
809
833
  },
810
834
 
811
835
  // prevent other plugins from resolving our remote virtual module
@@ -823,10 +847,6 @@ function kit({ svelte_config }) {
823
847
  id: prefixRegex('\0sveltekit-remote:')
824
848
  },
825
849
  handler(id) {
826
- if (!kit.experimental.remoteFunctions) {
827
- return null;
828
- }
829
-
830
850
  // On-the-fly generated entry point for remote file just forwards the original module
831
851
  // We're not using manualChunks because it can cause problems with circular dependencies
832
852
  // (e.g. https://github.com/sveltejs/kit/issues/14679) and module ordering in general
@@ -839,18 +859,10 @@ function kit({ svelte_config }) {
839
859
  },
840
860
 
841
861
  configureServer(_dev_server) {
842
- if (!kit.experimental.remoteFunctions) {
843
- return;
844
- }
845
-
846
862
  dev_server = _dev_server;
847
863
  },
848
864
 
849
865
  async transform(code, id) {
850
- if (!kit.experimental.remoteFunctions) {
851
- return;
852
- }
853
-
854
866
  const normalized = normalize_id(id, normalized_lib, normalized_cwd);
855
867
  if (!svelte_config.kit.moduleExtensions.some((ext) => normalized.endsWith(`.remote${ext}`))) {
856
868
  return;
@@ -876,7 +888,7 @@ function kit({ svelte_config }) {
876
888
  '\n\n' +
877
889
  dedent`
878
890
  import * as $$_self_$$ from './${path.basename(id)}';
879
- import { init_remote_functions as $$_init_$$ } from '@sveltejs/kit/internal';
891
+ import { init_remote_functions as $$_init_$$ } from '@sveltejs/kit/internal/server';
880
892
 
881
893
  ${dev_server ? 'await Promise.resolve()' : ''}
882
894
 
@@ -906,7 +918,7 @@ function kit({ svelte_config }) {
906
918
 
907
919
  // For the client, read the exports and create a new module that only contains fetch functions with the correct metadata
908
920
 
909
- /** @type {Map<string, import('types').RemoteInternals['type']>} */
921
+ /** @type {Map<string, RemoteInternals['type']>} */
910
922
  const map = new Map();
911
923
 
912
924
  // in dev, load the server module here (which will result in this hook
@@ -934,15 +946,17 @@ function kit({ svelte_config }) {
934
946
  }
935
947
  }
936
948
 
937
- let namespace = '__remote';
938
- let uid = 1;
939
- while (map.has(namespace)) namespace = `__remote${uid++}`;
940
-
941
- const exports = Array.from(map).map(([name, type]) => {
942
- return `export const ${name} = ${namespace}.${type}('${remote.hash}/${name}');`;
943
- });
949
+ const { namespace, declarations, reexports } = create_exported_declarations(
950
+ map.keys(),
951
+ (name, ns) => `${ns}.${map.get(name)}('${remote.hash}/${name}')`,
952
+ '__remote'
953
+ );
944
954
 
945
- let result = `import * as ${namespace} from '__sveltekit/remote';\n\n${exports.join('\n')}\n`;
955
+ let result = `import * as ${namespace} from '__sveltekit/remote';\n\n${declarations.join('\n')}`;
956
+ if (reexports.length > 0) {
957
+ result += `\nexport { ${reexports.join(', ')} };`;
958
+ }
959
+ result += '\n';
946
960
 
947
961
  if (dev_server) {
948
962
  result += `\nimport.meta.hot?.accept();\n`;
@@ -954,11 +968,31 @@ function kit({ svelte_config }) {
954
968
  }
955
969
  };
956
970
 
971
+ /** @type {Plugin} */
972
+ const plugin_remote_guard = {
973
+ name: 'vite-plugin-sveltekit-remote-guard',
974
+
975
+ applyToEnvironment() {
976
+ return !svelte_config.kit.experimental.remoteFunctions;
977
+ },
978
+
979
+ transform: {
980
+ filter: {
981
+ id: new RegExp(
982
+ `.remote(${svelte_config.kit.moduleExtensions.join('|')})$`.replaceAll('.', '\\.')
983
+ )
984
+ },
985
+ handler() {
986
+ error_for_missing_config('remote functions', 'experimental.remoteFunctions', 'true');
987
+ }
988
+ }
989
+ };
990
+
957
991
  /** @type {Manifest} */
958
992
  let vite_server_manifest;
959
993
  /** @type {Manifest | null} */
960
994
  let vite_client_manifest = null;
961
- /** @type {import('types').Prerendered} */
995
+ /** @type {Prerendered} */
962
996
  let prerendered;
963
997
 
964
998
  /** @type {Set<string>} */
@@ -979,6 +1013,8 @@ function kit({ svelte_config }) {
979
1013
 
980
1014
  if (!service_worker_entry_file) return;
981
1015
 
1016
+ service_worker_entry_file = posixify(service_worker_entry_file);
1017
+
982
1018
  if (kit.paths.assets) {
983
1019
  throw new Error('Cannot use service worker alongside config.paths.assets');
984
1020
  }
@@ -1022,8 +1058,8 @@ function kit({ svelte_config }) {
1022
1058
  return new_config;
1023
1059
  },
1024
1060
 
1025
- // the serviceWorker environment only applies during build because Vite currently
1026
- // only supports the default client environment during development
1061
+ // our serviceWorker environment only exists when building because Vite only
1062
+ // supports the default client environment during development (for now)
1027
1063
  applyToEnvironment(environment) {
1028
1064
  return environment.name === 'serviceWorker';
1029
1065
  },
@@ -1156,32 +1192,30 @@ function kit({ svelte_config }) {
1156
1192
  /** @type {Plugin} */
1157
1193
  const plugin_service_worker_env = {
1158
1194
  name: 'vite-plugin-sveltekit-service-worker-env',
1159
-
1160
- transform: {
1161
- filter: {
1162
- id: service_worker_entry_file || '<skip>'
1163
- },
1164
- handler(code) {
1165
- // prepend the service worker with an import that configures
1166
- // `env`, in case `$app/env/public` is imported. In production
1167
- // this is required: dynamic public env vars aren't known at
1168
- // build time, so `env.js` is loaded at runtime. In dev, the
1169
- // imported module just inlines the current values instead.
1170
- return {
1171
- code: `import '__sveltekit/env/service-worker';\n${code}`
1172
- };
1173
- }
1195
+ applyToEnvironment(environment) {
1196
+ return !!service_worker_entry_file && environment.config.consumer === 'client';
1197
+ },
1198
+ transform(code, id) {
1199
+ if (id !== service_worker_entry_file) return;
1200
+
1201
+ // prepend the service worker with an import that configures
1202
+ // `env`, in case `$app/env/public` is imported. In production
1203
+ // this is required: dynamic public env vars aren't known at
1204
+ // build time, so `env.js` is loaded at runtime. In dev, the
1205
+ // imported module just inlines the current values instead.
1206
+ return {
1207
+ code: `import '__sveltekit/env/service-worker';\n${code}`
1208
+ };
1174
1209
  }
1175
1210
  };
1176
1211
 
1212
+ /** @type {() => Promise<void> | undefined} */
1213
+ let finalise;
1214
+
1177
1215
  /** @type {Plugin} */
1178
1216
  const plugin_compile = {
1179
1217
  name: 'vite-plugin-sveltekit-compile',
1180
1218
 
1181
- applyToEnvironment(environment) {
1182
- return environment.name !== 'serviceWorker';
1183
- },
1184
-
1185
1219
  /**
1186
1220
  * Build the SvelteKit-provided Vite config to be merged with the user's vite.config.js file.
1187
1221
  * @see https://vitejs.dev/guide/api-plugin.html#config
@@ -1194,7 +1228,7 @@ function kit({ svelte_config }) {
1194
1228
  let new_config;
1195
1229
 
1196
1230
  if (is_build) {
1197
- const prefix = `${kit.appDir}/immutable`;
1231
+ const app_immutable = `${kit.appDir}/immutable`;
1198
1232
 
1199
1233
  /** @type {Record<string, string>} */
1200
1234
  const server_input = {
@@ -1229,11 +1263,10 @@ function kit({ svelte_config }) {
1229
1263
  }
1230
1264
  });
1231
1265
 
1232
- // ...and every matcher
1233
- Object.entries(manifest_data.matchers).forEach(([key, file]) => {
1234
- const name = posixify(path.join('entries/matchers', key));
1235
- server_input[name] = path.resolve(root, file);
1236
- });
1266
+ // ...and the params file
1267
+ if (manifest_data.params) {
1268
+ server_input['entries/params'] = path.resolve(root, manifest_data.params);
1269
+ }
1237
1270
 
1238
1271
  // ...and the hooks files
1239
1272
  if (manifest_data.hooks.server) {
@@ -1254,13 +1287,6 @@ function kit({ svelte_config }) {
1254
1287
  if (kit.adapter && !kit.adapter.supports?.instrumentation?.()) {
1255
1288
  throw new Error(`${server_instrumentation} is unsupported in ${kit.adapter.name}.`);
1256
1289
  }
1257
- if (!kit.experimental.instrumentation.server) {
1258
- error_for_missing_config(
1259
- '`instrumentation.server.js`',
1260
- 'kit.experimental.instrumentation.server',
1261
- 'true'
1262
- );
1263
- }
1264
1290
  server_input['instrumentation.server'] = server_instrumentation;
1265
1291
  }
1266
1292
 
@@ -1271,6 +1297,7 @@ function kit({ svelte_config }) {
1271
1297
  client_input['bundle'] = `${runtime_directory}/client/bundle.js`;
1272
1298
  } else {
1273
1299
  client_input['entry/start'] = `${runtime_directory}/client/entry.js`;
1300
+ client_input['entry/payload'] = `${runtime_directory}/client/payload.js`;
1274
1301
  client_input['entry/app'] = `${out_dir}/generated/client-optimized/app.js`;
1275
1302
  manifest_data.nodes.forEach((node, i) => {
1276
1303
  if (node.component || node.universal) {
@@ -1283,9 +1310,9 @@ function kit({ svelte_config }) {
1283
1310
 
1284
1311
  /** @type {string} */
1285
1312
  const base = (kit.paths.assets || kit.paths.base) + '/';
1286
- const root_to_assets = prefix + '/assets/';
1313
+ const root_to_assets = app_immutable + '/assets/';
1287
1314
  const assets_to_root =
1288
- prefix
1315
+ app_immutable
1289
1316
  .split('/')
1290
1317
  .map(() => '..')
1291
1318
  .join('/') + '/../';
@@ -1308,7 +1335,7 @@ function kit({ svelte_config }) {
1308
1335
  rolldownOptions: {
1309
1336
  output: {
1310
1337
  name: `__sveltekit_${version_hash}.app`,
1311
- assetFileNames: `${prefix}/assets/[name].[hash][extname]`,
1338
+ assetFileNames: `${app_immutable}/assets/[name].[hash][extname]`,
1312
1339
  hoistTransitiveImports: false,
1313
1340
  sourcemapIgnoreList
1314
1341
  },
@@ -1347,7 +1374,7 @@ function kit({ svelte_config }) {
1347
1374
  }
1348
1375
  }
1349
1376
  },
1350
- // during the initial server build we don't know yet
1377
+ // these are stubs that will be replaced after the initial server build
1351
1378
  define: {
1352
1379
  __SVELTEKIT_HAS_SERVER_LOAD__: 'true',
1353
1380
  __SVELTEKIT_HAS_UNIVERSAL_LOAD__: 'true',
@@ -1361,8 +1388,8 @@ function kit({ svelte_config }) {
1361
1388
  input: inline ? client_input['bundle'] : client_input,
1362
1389
  output: {
1363
1390
  format: inline ? 'iife' : 'esm',
1364
- entryFileNames: `${prefix}/[name].[hash].js`,
1365
- chunkFileNames: `${prefix}/chunks/[hash].js`,
1391
+ entryFileNames: `${app_immutable}/[name].[hash].js`,
1392
+ chunkFileNames: `${app_immutable}/chunks/[hash].js`,
1366
1393
  codeSplitting:
1367
1394
  svelte_config.kit.output.bundleStrategy === 'split' ? undefined : false
1368
1395
  },
@@ -1379,7 +1406,8 @@ function kit({ svelte_config }) {
1379
1406
  }
1380
1407
  },
1381
1408
  define: {
1382
- __SVELTEKIT_PAYLOAD__: kit_global
1409
+ __SVELTEKIT_PAYLOAD__:
1410
+ svelte_config.kit.output.bundleStrategy !== 'split' ? kit_global : 'undefined'
1383
1411
  }
1384
1412
  }
1385
1413
  },
@@ -1398,6 +1426,11 @@ function kit({ svelte_config }) {
1398
1426
  return { relative };
1399
1427
  }
1400
1428
 
1429
+ if (!relative) return;
1430
+
1431
+ // ensure assets loaded by CSS files are loaded relative to the
1432
+ // CSS file rather than the default of relative to the root
1433
+
1401
1434
  // _app/immutable/assets files
1402
1435
  if (filename.startsWith(root_to_assets)) {
1403
1436
  return `./${filename.slice(root_to_assets.length)}`;
@@ -1436,16 +1469,20 @@ function kit({ svelte_config }) {
1436
1469
  * Adds the SvelteKit middleware to do SSR in dev mode.
1437
1470
  * @see https://vitejs.dev/guide/api-plugin.html#configureserver
1438
1471
  */
1439
- async configureServer(vite) {
1440
- return await dev(vite, vite_config, svelte_config, () => remotes, root);
1472
+ async configureServer(server) {
1473
+ return await dev(server, vite_config, svelte_config, () => remotes, root);
1441
1474
  },
1442
1475
 
1443
1476
  /**
1444
1477
  * Adds the SvelteKit middleware to do SSR in preview mode.
1445
1478
  * @see https://vitejs.dev/guide/api-plugin.html#configurepreviewserver
1446
1479
  */
1447
- configurePreviewServer(vite) {
1448
- return preview(vite, vite_config, svelte_config);
1480
+ configurePreviewServer(server) {
1481
+ return preview(server, vite_config, svelte_config);
1482
+ },
1483
+
1484
+ applyToEnvironment(environment) {
1485
+ return environment.name !== 'serviceWorker';
1449
1486
  },
1450
1487
 
1451
1488
  renderChunk(code, chunk) {
@@ -1479,17 +1516,23 @@ function kit({ svelte_config }) {
1479
1516
  }
1480
1517
  mkdirp(out);
1481
1518
 
1519
+ await load_and_validate_params({
1520
+ routes: manifest_data.routes,
1521
+ params_path: manifest_data.params,
1522
+ root
1523
+ });
1524
+
1482
1525
  const { output: server_chunks } = /** @type {Rolldown.RolldownOutput} */ (
1483
1526
  await builder.build(builder.environments.ssr)
1484
1527
  );
1485
1528
 
1486
- const verbose = vite_config.logLevel === 'info';
1529
+ const verbose = builder.config.logLevel === 'info';
1487
1530
  const log = logger({ verbose });
1488
1531
 
1489
1532
  /** @type {Manifest} */
1490
1533
  vite_server_manifest = JSON.parse(read(`${out}/server/.vite/manifest.json`));
1491
1534
 
1492
- /** @type {import('types').BuildData} */
1535
+ /** @type {BuildData} */
1493
1536
  const build_data = {
1494
1537
  app_dir: kit.appDir,
1495
1538
  app_path: `${kit.paths.base.slice(1)}${kit.paths.base ? '/' : ''}${kit.appDir}`,
@@ -1627,15 +1670,28 @@ function kit({ svelte_config }) {
1627
1670
  );
1628
1671
 
1629
1672
  if (svelte_config.kit.output.bundleStrategy === 'split') {
1630
- const start = deps_of(`${runtime_directory}/client/entry.js`);
1673
+ const start_entry = posixify(path.relative(root, `${runtime_directory}/client/entry.js`));
1674
+ const start = find_deps(vite_manifest, start_entry, false, root);
1675
+ const runtime_entry = resolve_symlinks(vite_manifest, start_entry, root).chunk
1676
+ .dynamicImports?.[0]; // client/entry.js dynamically imports client/client-entry.js
1677
+ if (!runtime_entry) throw new Error('Could not find the client runtime chunk');
1678
+ const runtime = find_deps(vite_manifest, runtime_entry, false, root);
1631
1679
  const app = deps_of(`${out_dir}/generated/client-optimized/app.js`);
1632
1680
 
1633
1681
  build_data.client = {
1634
1682
  start: start.file,
1635
1683
  app: app.file,
1636
- imports: [...start.imports, ...app.imports],
1637
- stylesheets: [...start.stylesheets, ...app.stylesheets],
1638
- fonts: [...start.fonts, ...app.fonts],
1684
+ imports: Array.from(
1685
+ new Set([
1686
+ ...start.imports,
1687
+ runtime.file,
1688
+ ...runtime.imports,
1689
+ app.file,
1690
+ ...app.imports
1691
+ ])
1692
+ ),
1693
+ stylesheets: [...start.stylesheets, ...runtime.stylesheets, ...app.stylesheets],
1694
+ fonts: [...start.fonts, ...runtime.fonts, ...app.fonts],
1639
1695
  uses_env_dynamic_public
1640
1696
  };
1641
1697
 
@@ -1776,63 +1832,88 @@ function kit({ svelte_config }) {
1776
1832
  })};\n`
1777
1833
  );
1778
1834
 
1779
- if (service_worker_entry_file) {
1780
- log.info('Building service worker');
1781
-
1782
- // mirror client settings that we couldn't set per environment in the config hook
1783
- builder.environments.serviceWorker.config.define =
1784
- builder.environments.client.config.define;
1785
- builder.environments.serviceWorker.config.resolve.alias = [
1786
- ...get_config_aliases(kit, vite_config.root)
1787
- ];
1835
+ // defer the adapt step to run after any buildApp hooks the adapter might have
1836
+ finalise = async () => {
1837
+ // defer creating the service worker too because other plugins might build
1838
+ // the client environment again and overwrite our service worker which
1839
+ // outputs to the same directory
1840
+ if (service_worker_entry_file) {
1841
+ log.info('Building service worker');
1842
+
1843
+ // mirror client settings that we couldn't set per environment in the config hook
1844
+ builder.environments.serviceWorker.config.define =
1845
+ builder.environments.client.config.define;
1846
+ builder.environments.serviceWorker.config.resolve.alias = [
1847
+ ...get_config_aliases(kit, vite_config.root)
1848
+ ];
1788
1849
 
1789
- // we have to overwrite this because it can't be configured per environment in the config hook
1790
- builder.environments.serviceWorker.config.experimental.renderBuiltUrl = (filename) => {
1791
- return {
1792
- runtime: `new URL(${JSON.stringify(filename)}, location.href).pathname`
1850
+ // we have to overwrite this because it can't be configured per environment in the config hook
1851
+ builder.environments.serviceWorker.config.experimental.renderBuiltUrl = (filename) => {
1852
+ return {
1853
+ runtime: `new URL(${JSON.stringify(filename)}, location.href).pathname`
1854
+ };
1793
1855
  };
1794
- };
1795
1856
 
1796
- await builder.build(builder.environments.serviceWorker);
1797
- }
1798
-
1799
- console.log(
1800
- `\nRun ${styleText(['bold', 'cyan'], 'npm run preview')} to preview your production build locally.`
1801
- );
1802
-
1803
- if (kit.adapter) {
1804
- const { adapt } = await import('../../core/adapt/index.js');
1805
- await adapt(
1806
- svelte_config,
1807
- build_data,
1808
- metadata,
1809
- prerendered,
1810
- prerender_results.prerender_map,
1811
- log,
1812
- remotes,
1813
- vite_config,
1814
- explicit_env_config
1815
- );
1816
- } else {
1817
- console.log(styleText(['bold', 'yellow'], '\nNo adapter specified'));
1857
+ await builder.build(builder.environments.serviceWorker);
1858
+ }
1818
1859
 
1819
- const link = styleText(['bold', 'cyan'], 'https://svelte.dev/docs/kit/adapters');
1820
1860
  console.log(
1821
- `See ${link} to learn how to configure your app to run on the platform of your choosing`
1861
+ `\nRun ${styleText(['bold', 'cyan'], 'npm run preview')} to preview your production build locally.`
1822
1862
  );
1863
+
1864
+ if (kit.adapter) {
1865
+ const { adapt } = await import('../../core/adapt/index.js');
1866
+ await adapt(
1867
+ svelte_config,
1868
+ build_data,
1869
+ metadata,
1870
+ prerendered,
1871
+ prerender_results.prerender_map,
1872
+ log,
1873
+ remotes,
1874
+ vite_config,
1875
+ explicit_env_config
1876
+ );
1877
+ } else {
1878
+ console.log(styleText(['bold', 'yellow'], '\nNo adapter specified'));
1879
+
1880
+ const link = styleText(['bold', 'cyan'], 'https://svelte.dev/docs/kit/adapters');
1881
+ console.log(
1882
+ `See ${link} to learn how to configure your app to run on the platform of your choosing`
1883
+ );
1884
+ }
1885
+ };
1886
+ }
1887
+ };
1888
+
1889
+ /** @type {Plugin} */
1890
+ const plugin_adapter = {
1891
+ name: 'vite-plugin-sveltekit-adapter',
1892
+ apply: 'build',
1893
+ buildApp: {
1894
+ // this will run after any buildApp hooks provided by other Vite plugins
1895
+ // see https://vite.dev/guide/api-environment-frameworks#environments-during-build
1896
+ order: 'post',
1897
+ async handler() {
1898
+ await finalise?.();
1823
1899
  }
1824
1900
  }
1825
1901
  };
1826
1902
 
1827
- return [
1828
- plugin_setup,
1829
- plugin_remote,
1830
- plugin_virtual_modules,
1831
- process.env.TEST !== 'true' ? plugin_guard : undefined,
1832
- service_worker_entry_file && plugin_service_worker_env,
1833
- plugin_service_worker,
1834
- plugin_compile
1835
- ].filter((p) => !!p);
1903
+ return /** @type {Plugin[]} */ (
1904
+ [
1905
+ svelte_config.kit.adapter?.vite?.plugins,
1906
+ plugin_setup,
1907
+ plugin_remote_guard,
1908
+ plugin_remote,
1909
+ plugin_virtual_modules,
1910
+ process.env.TEST !== 'true' ? plugin_guard : undefined,
1911
+ plugin_service_worker,
1912
+ plugin_service_worker_env,
1913
+ plugin_compile,
1914
+ plugin_adapter
1915
+ ].filter(Boolean)
1916
+ );
1836
1917
  }
1837
1918
 
1838
1919
  /**
@@ -1886,7 +1967,7 @@ function find_overridden_config(config, resolved_config, enforced_config, path,
1886
1967
  }
1887
1968
 
1888
1969
  /**
1889
- * @param {import('types').ValidatedConfig} config
1970
+ * @param {ValidatedConfig} config
1890
1971
  */
1891
1972
  const create_service_worker_module = (config) => dedent`
1892
1973
  if (typeof self === 'undefined' || self instanceof ServiceWorkerGlobalScope === false) {