@sveltejs/kit 3.0.0-next.24 → 3.0.0-next.25

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 (40) hide show
  1. package/package.json +12 -4
  2. package/src/constants.js +6 -0
  3. package/src/core/adapt/builder.js +1 -2
  4. package/src/core/env.js +3 -6
  5. package/src/core/postbuild/prerender.js +2 -2
  6. package/src/core/sync/write_server.js +3 -17
  7. package/src/core/utils.js +10 -0
  8. package/src/exports/adapter.js +22 -0
  9. package/src/exports/public.d.ts +1 -1
  10. package/src/exports/vite/build/service-worker.js +98 -0
  11. package/src/exports/vite/dev/index.js +17 -3
  12. package/src/exports/vite/index.js +41 -411
  13. package/src/exports/vite/plugins/env-vars.js +42 -0
  14. package/src/exports/vite/plugins/guard.js +205 -0
  15. package/src/exports/vite/utils.js +97 -0
  16. package/src/runtime/app/server/remote/query.js +2 -2
  17. package/src/runtime/client/client.js +4 -4
  18. package/src/runtime/form-utils.js +11 -19
  19. package/src/runtime/server/data/index.js +11 -26
  20. package/src/runtime/server/errors.js +7 -10
  21. package/src/runtime/server/fetch.js +14 -16
  22. package/src/runtime/server/index.js +28 -25
  23. package/src/runtime/server/internal.js +34 -4
  24. package/src/runtime/server/page/actions.js +6 -8
  25. package/src/runtime/server/page/data_serializer.js +6 -10
  26. package/src/runtime/server/page/index.js +9 -14
  27. package/src/runtime/server/page/render.js +16 -29
  28. package/src/runtime/server/page/respond_with_error.js +7 -9
  29. package/src/runtime/server/remote-functions.js +125 -125
  30. package/src/runtime/server/respond.js +53 -28
  31. package/src/runtime/server/state.js +1 -0
  32. package/src/runtime/server/utils.js +0 -7
  33. package/src/runtime/utils.js +41 -0
  34. package/src/types/global-private.d.ts +8 -0
  35. package/src/types/internal.d.ts +7 -11
  36. package/src/utils/filesystem.js +1 -1
  37. package/src/utils/streaming.js +5 -15
  38. package/src/version.js +1 -1
  39. package/types/index.d.ts +20 -1
  40. package/types/index.d.ts.map +4 -1
@@ -9,15 +9,7 @@ import path from 'node:path';
9
9
  import process from 'node:process';
10
10
  import { styleText } from 'node:util';
11
11
 
12
- import {
13
- and,
14
- code,
15
- exactRegex,
16
- importerId,
17
- include,
18
- not,
19
- prefixRegex
20
- } from '@rolldown/pluginutils';
12
+ import { code, include, prefixRegex } from '@rolldown/pluginutils';
21
13
  import MagicString from 'magic-string';
22
14
 
23
15
  import { copy, read, resolve_entry } from '../../utils/filesystem.js';
@@ -26,20 +18,19 @@ import { to_fs } from '../../utils/vite.js';
26
18
  import { create_exported_declarations } from '../../core/env.js';
27
19
  import * as sync from '../../core/sync/sync.js';
28
20
  import { load_and_validate_params } from '../../utils/params.js';
29
- import { runtime_directory, logger } from '../../core/utils.js';
21
+ import { runtime_directory, logger, get_global_name } from '../../core/utils.js';
30
22
  import { generate_manifest } from '../../core/generate_manifest/index.js';
31
23
  import { build_server_nodes } from './build/build_server.js';
32
24
  import { find_deps, resolve_symlinks } from './build/utils.js';
33
25
  import { dev } from './dev/index.js';
34
26
  import { preview } from './preview/index.js';
35
27
  import {
28
+ enforced_config,
36
29
  error_for_missing_config,
37
30
  get_config_aliases,
38
31
  is_remote_module,
39
- normalize_id,
40
32
  remote_module_pattern,
41
- server_only_directory_pattern,
42
- server_only_module_pattern
33
+ warn_overridden_config
43
34
  } from './utils.js';
44
35
  import { stackless } from '../../utils/error.js';
45
36
  import { adapt } from '../../core/adapt/index.js';
@@ -51,51 +42,16 @@ import { hash } from '../../utils/hash.js';
51
42
  import { dedent } from '../../core/sync/utils.js';
52
43
  import create_manifest_data from '../../core/sync/create_manifest_data/index.js';
53
44
  import { get_import_aliases, get_hash_import_keys } from '../../utils/imports.js';
54
- import { app_env_private, app_server } from './module_ids.js';
55
45
  import { import_peer } from '../../utils/import.js';
56
46
  import { compact } from '../../utils/array.js';
57
47
  import { should_ignore, has_children } from './static_analysis/utils.js';
58
48
  import { process_config, split_config, validate_config } from '../../core/config/index.js';
59
49
  import { treeshake_prerendered_remotes } from './build/remote.js';
60
50
  import { get_runner } from '../../runner.js';
61
- import { plugin_env_vars } from './plugins/env-vars.js';
51
+ import { plugin_env_vars, plugin_service_worker_env_vars } from './plugins/env-vars.js';
52
+ import { plugin_guard } from './plugins/guard.js';
62
53
  import { get_manifest_routes, write_app_manifest } from '../../core/sync/write_app_manifest.js';
63
-
64
- /** @type {import('./types.js').EnforcedConfig} */
65
- const enforced_config = {
66
- appType: true,
67
- base: true,
68
- build: {
69
- cssCodeSplit: true,
70
- emptyOutDir: true,
71
- lib: {
72
- entry: true,
73
- name: true,
74
- formats: true
75
- },
76
- manifest: true,
77
- outDir: true,
78
- rolldownOptions: {
79
- input: true,
80
- output: {
81
- format: true,
82
- entryFileNames: true,
83
- chunkFileNames: true,
84
- assetFileNames: true
85
- },
86
- preserveEntrySignatures: true
87
- },
88
- ssr: true
89
- },
90
- publicDir: true,
91
- resolve: {
92
- alias: {
93
- $app: true,
94
- $env: true,
95
- '<sveltekit:generated>': true
96
- }
97
- }
98
- };
54
+ import { plugin_service_worker_build } from './build/service-worker.js';
99
55
 
100
56
  const options_regex = /(export\s+const\s+(prerender|csr|ssr|trailingSlash))\s*=/s;
101
57
 
@@ -276,9 +232,6 @@ function kit({ svelte_config }) {
276
232
  /** @type {string} The base directory for the Vite builds */
277
233
  let out;
278
234
 
279
- /** @type {string} */
280
- let version_hash;
281
-
282
235
  /** @type {ResolvedConfig} */
283
236
  let vite_config;
284
237
 
@@ -299,16 +252,8 @@ function kit({ svelte_config }) {
299
252
 
300
253
  /** @type {string | null} */
301
254
  let service_worker_entry_file;
302
- /** @type {string} */
303
- let normalized_cwd;
304
255
  /** @type {Array<{ alias: string, path: string }>} */
305
256
  let normalized_aliases;
306
- /** @type {string} */
307
- let normalized_node_modules;
308
- /** @type {string} */
309
- let normalized_routes;
310
- /** @type {string} */
311
- let normalized_assets;
312
257
  /**
313
258
  * A map showing which features (such as `$app/server:read`) are defined
314
259
  * in which chunks, so that we can later determine which routes use which features
@@ -319,6 +264,9 @@ function kit({ svelte_config }) {
319
264
  const sourcemapIgnoreList = /** @param {string} relative_path */ (relative_path) =>
320
265
  relative_path.includes('node_modules') || relative_path.includes(kit.outDir);
321
266
 
267
+ /** @type {string} the `__sveltekit_xxx` name, without `globalThis.` */
268
+ let global_name;
269
+
322
270
  /** @type {string} name for `globalThis.__sveltekit_xxx` */
323
271
  let kit_global;
324
272
 
@@ -384,21 +332,17 @@ function kit({ svelte_config }) {
384
332
  out_dir = posixify(kit.outDir);
385
333
  out = `${out_dir}/output`;
386
334
 
387
- version_hash = hash(kit.version.name);
335
+ global_name = get_global_name(kit.version.name, !is_build);
336
+ kit_global = `globalThis.${global_name}`;
388
337
 
389
- kit_global = is_build
390
- ? `globalThis.__sveltekit_${version_hash}`
391
- : 'globalThis.__sveltekit_dev';
338
+ service_worker_entry_file = resolve_entry(kit.files.serviceWorker);
339
+ service_worker_entry_file &&= posixify(service_worker_entry_file);
392
340
 
393
341
  vite = await import_peer('vite', root);
394
342
 
395
343
  env = vite.loadEnv(config_env.mode, kit.env.dir, '');
396
344
 
397
- normalized_cwd = vite.normalizePath(root);
398
345
  normalized_aliases = get_import_aliases(root, vite.normalizePath.bind(vite));
399
- normalized_node_modules = vite.normalizePath(path.resolve(root, 'node_modules'));
400
- normalized_routes = vite.normalizePath(path.resolve(root, kit.files.routes));
401
- normalized_assets = vite.normalizePath(path.resolve(root, kit.files.assets));
402
346
 
403
347
  // Add `#`-prefixed import keys to the enforced config so users are warned
404
348
  // if they try to set them in their Vite config's resolve.alias
@@ -546,7 +490,12 @@ function kit({ svelte_config }) {
546
490
  __SVELTEKIT_SUPPORTS_ASYNC__: s(
547
491
  svelte_config.compilerOptions?.experimental?.async ?? false
548
492
  ),
549
- __SVELTEKIT_DEV__: s(!is_build)
493
+ __SVELTEKIT_DEV__: s(!is_build),
494
+ __SVELTEKIT_GLOBAL_NAME__: s(global_name),
495
+ __SVELTEKIT_CSRF_CHECK_ORIGIN__: s(!kit.csrf.trustedOrigins.includes('*')),
496
+ __SVELTEKIT_LINK_HEADER_PRELOAD__: s(kit.output.linkHeaderPreload),
497
+ __SVELTEKIT_PATHS_ORIGIN__: s(kit.paths.origin) ?? 'undefined',
498
+ __SVELTEKIT_SERVICE_WORKER__: s(kit.serviceWorker.register && !!service_worker_entry_file)
550
499
  };
551
500
 
552
501
  if (is_build) {
@@ -641,164 +590,6 @@ function kit({ svelte_config }) {
641
590
  /** @type {Record<string, EnvVarConfig<any>> | null} */
642
591
  let explicit_env_config = null;
643
592
 
644
- /** @type {Map<string, Set<string>>} */
645
- const import_map = new Map();
646
-
647
- /**
648
- * Ensures that client-side code can't accidentally import server-side code,
649
- * whether in `*.server.js` files, `$app/server`, any `/server/` directory, or `$app/env/private`
650
- * @type {Plugin}
651
- */
652
- const plugin_guard = {
653
- name: 'vite-plugin-sveltekit-guard',
654
-
655
- // Run this plugin before built-in resolution, so that relative imports
656
- // are added to the module graph
657
- enforce: 'pre',
658
-
659
- applyToEnvironment(environment) {
660
- // the import map is only read for client-side violations in `load`, so skip other environments
661
- return environment.config.consumer === 'client';
662
- },
663
-
664
- resolveId: {
665
- // composable filters are not accepted type-wise but still work during build
666
- // see https://github.com/vitejs/rolldown-vite/issues/605
667
- filter: /** @type {any} */ (
668
- /** @satisfies {TopLevelFilterExpression[]} */ ([
669
- include(and(importerId(/.+/), not(importerId(/index\.html$/))))
670
- ])
671
- ),
672
- async handler(id, importer, options) {
673
- // composable filters only work during build so we still need this guard for dev
674
- // see https://github.com/vitejs/rolldown-vite/issues/605
675
- if (importer && !importer.endsWith('index.html')) {
676
- const resolved = await this.resolve(id, importer, { ...options, skipSelf: true });
677
-
678
- if (resolved) {
679
- const normalized = normalize_id(resolved.id, normalized_aliases, normalized_cwd);
680
-
681
- let importers = import_map.get(normalized);
682
-
683
- if (!importers) {
684
- importers = new Set();
685
- import_map.set(normalized, importers);
686
- }
687
-
688
- importers.add(normalize_id(importer, normalized_aliases, normalized_cwd));
689
- }
690
- }
691
- }
692
- },
693
-
694
- load: {
695
- filter: {
696
- id: [
697
- exactRegex(app_server),
698
- exactRegex(app_env_private),
699
- server_only_module_pattern,
700
- server_only_directory_pattern
701
- ]
702
- },
703
- handler(id) {
704
- const normalized = normalize_id(id, normalized_aliases, normalized_cwd);
705
-
706
- let is_server_only = normalized === '$app/env/private' || normalized === '$app/server';
707
-
708
- // skip .server.js files outside the cwd or in node_modules, as the filename might not mean 'server-only module' in this context
709
- if (id.startsWith(normalized_cwd) && !id.startsWith(normalized_node_modules)) {
710
- // e.g. `server.ts` or `foo.server.ts`
711
- is_server_only ||= server_only_module_pattern.test(id);
712
-
713
- // e.g. `server/foo.ts`, unless in `src/routes` or `static`
714
- is_server_only ||=
715
- server_only_directory_pattern.test(id) &&
716
- !id.startsWith(normalized_routes + '/') &&
717
- !id.startsWith(normalized_assets + '/');
718
- }
719
-
720
- if (!is_server_only) return;
721
-
722
- // in dev, this doesn't exist, so we need to create it
723
- manifest_data ??= create_manifest_data(svelte_config, root);
724
-
725
- /** @type {Set<string>} */
726
- const entrypoints = new Set();
727
- for (const node of manifest_data.nodes) {
728
- if (node.component) entrypoints.add(node.component);
729
- if (node.universal) entrypoints.add(node.universal);
730
- }
731
-
732
- if (manifest_data.hooks.client) entrypoints.add(manifest_data.hooks.client);
733
- if (manifest_data.hooks.universal) entrypoints.add(manifest_data.hooks.universal);
734
-
735
- if (service_worker_entry_file) {
736
- entrypoints.add(posixify(path.relative(root, service_worker_entry_file)));
737
- }
738
-
739
- // Walk up the import graph from the server-only module, looking for a chain
740
- // that leads back to a client entrypoint. We search all candidates (not just
741
- // the first) because a module can be imported by both server and client code,
742
- // and a greedy first-match could follow a server-only branch that never
743
- // reaches an entrypoint — see https://github.com/sveltejs/kit/issues/16232
744
- /** @type {Set<string>} */
745
- const visited = new Set([normalized]);
746
-
747
- /**
748
- * @param {string} current
749
- * @param {string[]} chain
750
- * @returns {string[] | null}
751
- */
752
- function find_chain(current, chain) {
753
- const importers = import_map.get(current);
754
- if (!importers) return null;
755
-
756
- for (const importer of importers) {
757
- if (visited.has(importer)) continue;
758
- visited.add(importer);
759
-
760
- const next_chain = [...chain, importer];
761
- if (entrypoints.has(importer)) {
762
- return next_chain;
763
- }
764
- const result = find_chain(importer, next_chain);
765
- if (result) return result;
766
- }
767
- return null;
768
- }
769
-
770
- const chain = find_chain(normalized, [normalized]);
771
-
772
- if (chain) {
773
- if (chain.some((id) => remote_module_pattern.test(id))) {
774
- error_for_missing_config('remote functions', 'experimental.remoteFunctions', 'true');
775
- }
776
-
777
- const pyramid = chain
778
- .reverse()
779
- .map((id, i) => {
780
- return `${' '.repeat(i + 1)}${id}`;
781
- })
782
- .join(' imports\n');
783
-
784
- let message = `Cannot import ${normalized} into code that runs in the browser, as this could leak sensitive information.`;
785
- message += `\n\n${pyramid}`;
786
- message += `\n\nIf you're only using the import as a type, change it to \`import type\`.`;
787
-
788
- throw stackless(message);
789
- }
790
-
791
- // No chain from this server-only module to a client entrypoint was found —
792
- // the module is only imported from server code, which is valid.
793
- }
794
- },
795
-
796
- // avoid watch mode rebuilds using stale import map data
797
- buildEnd() {
798
- import_map.clear();
799
- }
800
- };
801
-
802
593
  /** @type {ViteDevServer} */
803
594
  let dev_server;
804
595
 
@@ -1003,127 +794,6 @@ function kit({ svelte_config }) {
1003
794
  /** @type {Array<{ path: string }> | null} */
1004
795
  let immutable = null;
1005
796
 
1006
- /**
1007
- * Creates the service worker virtual modules
1008
- * @type {Plugin}
1009
- */
1010
- const plugin_service_worker = {
1011
- name: 'vite-plugin-sveltekit-service-worker',
1012
-
1013
- config(config) {
1014
- service_worker_entry_file = resolve_entry(kit.files.serviceWorker);
1015
-
1016
- if (!service_worker_entry_file) return;
1017
-
1018
- service_worker_entry_file = posixify(service_worker_entry_file);
1019
-
1020
- if (kit.paths.assets) {
1021
- throw new Error('Cannot use service worker alongside config.paths.assets');
1022
- }
1023
-
1024
- const user_service_worker_output_config =
1025
- config.environments?.serviceWorker?.build?.rolldownOptions?.output;
1026
-
1027
- /** @type {import('vite').UserConfig} */
1028
- const new_config = {
1029
- environments: {
1030
- serviceWorker: {
1031
- define: {
1032
- __SVELTEKIT_PAYLOAD__: kit_global
1033
- },
1034
- build: {
1035
- modulePreload: false,
1036
- rolldownOptions: {
1037
- external: [`${kit.paths.base}/${kit.appDir}/env.js`],
1038
- input: {
1039
- 'service-worker': service_worker_entry_file
1040
- },
1041
- output: {
1042
- format: 'es',
1043
- entryFileNames: 'service-worker.js',
1044
- assetFileNames: `${kit.appDir}/immutable/assets/[name].[hash][extname]`,
1045
- codeSplitting:
1046
- (Array.isArray(user_service_worker_output_config)
1047
- ? user_service_worker_output_config[0].codeSplitting
1048
- : user_service_worker_output_config?.codeSplitting) ?? false
1049
- }
1050
- },
1051
- outDir: `${out}/client`,
1052
- minify: initial_config.build?.minify,
1053
- // avoid overwriting the client build Vite manifest
1054
- manifest: '.vite/service-worker-manifest.json'
1055
- },
1056
- consumer: 'client'
1057
- }
1058
- }
1059
- };
1060
-
1061
- warn_overridden_config(config, new_config);
1062
-
1063
- return new_config;
1064
- },
1065
-
1066
- // our serviceWorker environment only exists when building because Vite only
1067
- // supports the default client environment during development (for now)
1068
- applyToEnvironment(environment) {
1069
- return environment.name === 'serviceWorker';
1070
- },
1071
-
1072
- generateBundle(_, bundle) {
1073
- const invalid_modules = new Set();
1074
- const modules = new Map([
1075
- [`${runtime_directory}/app/forms/index.js`, '$app/forms'],
1076
- [`${runtime_directory}/app/navigation/index.js`, '$app/navigation'],
1077
- [`${runtime_directory}/app/state/index.js`, '$app/state']
1078
- ]);
1079
-
1080
- for (const output of Object.values(bundle)) {
1081
- if (output.type !== 'chunk') continue;
1082
-
1083
- for (const id of output.moduleIds) {
1084
- const module = modules.get(id);
1085
- if (module) invalid_modules.add(module);
1086
- }
1087
- }
1088
-
1089
- if (invalid_modules.size > 0) {
1090
- throw new Error(
1091
- `Cannot import ${Array.from(modules.values())
1092
- .filter((module) => invalid_modules.has(module))
1093
- .join(', ')} into service-worker code.`
1094
- );
1095
- }
1096
- }
1097
- };
1098
-
1099
- /** @type {Plugin} */
1100
- const plugin_service_worker_env = {
1101
- name: 'vite-plugin-sveltekit-service-worker-env',
1102
- configResolved() {
1103
- if (service_worker_entry_file) {
1104
- // @ts-expect-error transform is defined in this object
1105
- plugin_service_worker_env.transform.filter = {
1106
- id: exactRegex(service_worker_entry_file)
1107
- };
1108
- }
1109
- },
1110
- applyToEnvironment(environment) {
1111
- return !!service_worker_entry_file && environment.config.consumer === 'client';
1112
- },
1113
- transform: {
1114
- handler(code) {
1115
- // prepend the service worker with an import that configures
1116
- // `env`, in case `$app/env/public` is imported. In production
1117
- // this is required: dynamic public env vars aren't known at
1118
- // build time, so `env.js` is loaded at runtime. In dev, the
1119
- // imported module just inlines the current values instead.
1120
- return {
1121
- code: `import '<sveltekit:generated>/env/service-worker.js';\n${code}`
1122
- };
1123
- }
1124
- }
1125
- };
1126
-
1127
797
  /** @type {Map<string, Rolldown.RolldownOutput['output']>} */
1128
798
  const watch_build_output = new Map();
1129
799
  /** @type {(() => Promise<void>) | null} */
@@ -1252,7 +922,7 @@ function kit({ svelte_config }) {
1252
922
  manifest: true,
1253
923
  rolldownOptions: {
1254
924
  output: {
1255
- name: `__sveltekit_${version_hash}.app`,
925
+ name: `${global_name}.app`,
1256
926
  assetFileNames: `${app_immutable}/assets/[name].[hash][extname]`,
1257
927
  hoistTransitiveImports: false,
1258
928
  sourcemapIgnoreList
@@ -2041,9 +1711,26 @@ function kit({ svelte_config }) {
2041
1711
  plugin_env_vars(svelte_config, (vars) => {
2042
1712
  explicit_env_config = vars;
2043
1713
  }),
2044
- process.env.TEST !== 'true' ? plugin_guard : undefined,
2045
- plugin_service_worker,
2046
- plugin_service_worker_env,
1714
+ process.env.TEST !== 'true'
1715
+ ? plugin_guard(
1716
+ svelte_config,
1717
+ () => ({
1718
+ vite,
1719
+ root,
1720
+ normalized_aliases,
1721
+ service_worker_entry_file
1722
+ }),
1723
+ // in dev, this doesn't exist yet, so we need to create it
1724
+ () => (manifest_data ??= create_manifest_data(svelte_config, root))
1725
+ )
1726
+ : undefined,
1727
+ plugin_service_worker_build(svelte_config, () => ({
1728
+ service_worker_entry_file,
1729
+ kit_global,
1730
+ initial_config,
1731
+ out
1732
+ })),
1733
+ plugin_service_worker_env_vars(() => service_worker_entry_file),
2047
1734
  plugin_compile,
2048
1735
  plugin_adapter,
2049
1736
  svelte_config.adapter?.vite?.plugins?.post
@@ -2051,52 +1738,6 @@ function kit({ svelte_config }) {
2051
1738
  );
2052
1739
  }
2053
1740
 
2054
- /**
2055
- * @param {UserConfig} config
2056
- * @param {UserConfig} resolved_config
2057
- */
2058
- function warn_overridden_config(config, resolved_config) {
2059
- const overridden = find_overridden_config(config, resolved_config, enforced_config, '', []);
2060
-
2061
- if (overridden.length > 0) {
2062
- console.error(
2063
- styleText(
2064
- ['bold', 'red'],
2065
- 'The following Vite config options will be overridden by SvelteKit:'
2066
- ) + overridden.map((key) => `\n - ${key}`).join('')
2067
- );
2068
- }
2069
- }
2070
-
2071
- /**
2072
- * @param {Record<string, any>} config
2073
- * @param {Record<string, any>} resolved_config
2074
- * @param {import('./types.js').EnforcedConfig} enforced_config
2075
- * @param {string} path
2076
- * @param {string[]} out used locally to compute the return value
2077
- */
2078
- function find_overridden_config(config, resolved_config, enforced_config, path, out) {
2079
- if (config == null || resolved_config == null) {
2080
- return out;
2081
- }
2082
-
2083
- for (const key in enforced_config) {
2084
- if (typeof config === 'object' && key in config && key in resolved_config) {
2085
- const enforced = enforced_config[key];
2086
- const resolved = resolved_config[key];
2087
-
2088
- if (enforced === true) {
2089
- if (comparable(config[key]) !== comparable(resolved)) {
2090
- out.push(path + key);
2091
- }
2092
- } else {
2093
- find_overridden_config(config[key], resolved, enforced, path + key + '.', out);
2094
- }
2095
- }
2096
- }
2097
- return out;
2098
- }
2099
-
2100
1741
  /**
2101
1742
  * Collects the content-hashed files of a Vite manifest, in the shape of
2102
1743
  * `$app/manifest`'s `immutable` export.
@@ -2127,17 +1768,6 @@ const collect_immutable = (manifest, app_dir, inlined) => {
2127
1768
  return Array.from(files, (path) => ({ path }));
2128
1769
  };
2129
1770
 
2130
- /**
2131
- * Normalizes a config value for comparison, since Windows paths may use backslashes
2132
- * and differ in casing (e.g. the drive letter) depending on where they came from.
2133
- * @param {any} value
2134
- */
2135
- function comparable(value) {
2136
- if (typeof value !== 'string') return value;
2137
- const normalized = posixify(value);
2138
- return process.platform === 'win32' ? normalized.toLowerCase() : normalized;
2139
- }
2140
-
2141
1771
  /**
2142
1772
  * Replaces manifest data placeholder identifiers in output chunks with real
2143
1773
  * values, or strings that are valid JS (so thecode doesn't crash during prerendering)
@@ -2,6 +2,7 @@
2
2
  /** @import { EnvVarConfig } from '@sveltejs/kit/env' */
3
3
  /** @import { ValidatedConfig } from 'types' */
4
4
  import path from 'node:path';
5
+ import { exactRegex } from '@rolldown/pluginutils';
5
6
  import * as sync from '../../../core/sync/sync.js';
6
7
  import { create_env_modules, resolve_env_entry } from '../../../core/env.js';
7
8
  import { import_peer } from '../../../utils/import.js';
@@ -115,3 +116,44 @@ export function plugin_env_vars(config, callback) {
115
116
  }
116
117
  };
117
118
  }
119
+
120
+ /**
121
+ * @param {() => string | null} get_service_worker_entry_file
122
+ * @returns {Plugin}
123
+ */
124
+ export function plugin_service_worker_env_vars(get_service_worker_entry_file) {
125
+ /** @type {string | null} */
126
+ let service_worker_entry_file;
127
+
128
+ /** @satisfies {Plugin} */
129
+ const plugin = {
130
+ name: 'vite-plugin-sveltekit-service-worker-env',
131
+ configResolved() {
132
+ service_worker_entry_file = get_service_worker_entry_file();
133
+
134
+ if (service_worker_entry_file) {
135
+ plugin.transform.filter = {
136
+ id: exactRegex(service_worker_entry_file)
137
+ };
138
+ }
139
+ },
140
+ applyToEnvironment(environment) {
141
+ return !!service_worker_entry_file && environment.config.consumer === 'client';
142
+ },
143
+ transform: {
144
+ filter: {},
145
+ handler(code) {
146
+ // prepend the service worker with an import that configures
147
+ // `env`, in case `$app/env/public` is imported. In production
148
+ // this is required: dynamic public env vars aren't known at
149
+ // build time, so `env.js` is loaded at runtime. In dev, the
150
+ // imported module just inlines the current values instead.
151
+ return {
152
+ code: `import '<sveltekit:generated>/env/service-worker.js';\n${code}`
153
+ };
154
+ }
155
+ }
156
+ };
157
+
158
+ return plugin;
159
+ }