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

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 (68) hide show
  1. package/package.json +17 -17
  2. package/src/core/adapt/builder.js +18 -4
  3. package/src/core/adapt/index.js +1 -4
  4. package/src/core/config/index.js +64 -5
  5. package/src/core/config/options.js +73 -21
  6. package/src/core/env.js +35 -4
  7. package/src/core/postbuild/analyse.js +8 -12
  8. package/src/core/postbuild/crawl.js +22 -6
  9. package/src/core/postbuild/prerender.js +40 -23
  10. package/src/core/sync/create_manifest_data/index.js +23 -5
  11. package/src/core/sync/write_client_manifest.js +7 -0
  12. package/src/core/sync/write_server.js +13 -10
  13. package/src/core/sync/write_tsconfig.js +2 -4
  14. package/src/exports/index.js +32 -10
  15. package/src/exports/internal/env.js +1 -1
  16. package/src/exports/internal/index.js +6 -5
  17. package/src/exports/node/index.js +57 -6
  18. package/src/exports/public.d.ts +218 -114
  19. package/src/exports/vite/build/build_server.js +6 -1
  20. package/src/exports/vite/dev/index.js +10 -20
  21. package/src/exports/vite/index.js +306 -222
  22. package/src/exports/vite/preview/index.js +15 -7
  23. package/src/exports/vite/utils.js +8 -10
  24. package/src/runtime/app/env/types.d.ts +1 -1
  25. package/src/runtime/app/forms.js +22 -5
  26. package/src/runtime/app/paths/client.js +1 -3
  27. package/src/runtime/app/paths/public.d.ts +0 -28
  28. package/src/runtime/app/paths/server.js +7 -3
  29. package/src/runtime/app/server/remote/form.js +10 -3
  30. package/src/runtime/app/server/remote/query.js +3 -6
  31. package/src/runtime/app/server/remote/requested.js +8 -4
  32. package/src/runtime/app/server/remote/shared.js +5 -7
  33. package/src/runtime/client/client.js +190 -95
  34. package/src/runtime/client/fetcher.js +3 -2
  35. package/src/runtime/client/remote-functions/form.svelte.js +134 -24
  36. package/src/runtime/client/remote-functions/prerender.svelte.js +8 -2
  37. package/src/runtime/client/remote-functions/query/index.js +3 -2
  38. package/src/runtime/client/remote-functions/query/instance.svelte.js +26 -10
  39. package/src/runtime/client/remote-functions/query-batch.svelte.js +4 -3
  40. package/src/runtime/client/remote-functions/query-live/instance.svelte.js +26 -9
  41. package/src/runtime/client/remote-functions/shared.svelte.js +17 -7
  42. package/src/runtime/client/types.d.ts +9 -1
  43. package/src/runtime/client/utils.js +1 -1
  44. package/src/runtime/form-utils.js +84 -16
  45. package/src/runtime/server/cookie.js +22 -33
  46. package/src/runtime/server/csrf.js +65 -0
  47. package/src/runtime/server/data/index.js +7 -7
  48. package/src/runtime/server/env_module.js +0 -5
  49. package/src/runtime/server/index.js +1 -1
  50. package/src/runtime/server/page/actions.js +41 -26
  51. package/src/runtime/server/page/index.js +2 -1
  52. package/src/runtime/server/page/render.js +21 -23
  53. package/src/runtime/server/page/respond_with_error.js +7 -8
  54. package/src/runtime/server/remote.js +64 -27
  55. package/src/runtime/server/respond.js +81 -50
  56. package/src/runtime/server/utils.js +7 -7
  57. package/src/runtime/telemetry/otel.js +1 -1
  58. package/src/types/ambient.d.ts +5 -4
  59. package/src/types/global-private.d.ts +4 -4
  60. package/src/types/internal.d.ts +8 -10
  61. package/src/types/private.d.ts +33 -1
  62. package/src/types/synthetic/$lib.md +1 -1
  63. package/src/utils/error.js +11 -3
  64. package/src/utils/shared-iterator.js +5 -0
  65. package/src/utils/url.js +99 -2
  66. package/src/version.js +1 -1
  67. package/types/index.d.ts +340 -186
  68. package/types/index.d.ts.map +10 -9
@@ -1,7 +1,7 @@
1
- /** @import { Adapter, EnvVarConfig, KitConfig } from '@sveltejs/kit' */
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, EnvironmentOptions } from 'vite' */
4
+ /** @import { Plugin, Manifest, ResolvedConfig, UserConfig, ViteDevServer, Rolldown } from 'vite' */
5
5
  import fs from 'node:fs';
6
6
  import path from 'node:path';
7
7
  import process from 'node:process';
@@ -15,6 +15,7 @@ import {
15
15
  create_sveltekit_env,
16
16
  create_sveltekit_env_public,
17
17
  resolve_explicit_env_entry,
18
+ create_sveltekit_env_service_worker,
18
19
  create_sveltekit_env_service_worker_dev,
19
20
  create_sveltekit_env_private
20
21
  } from '../../core/env.js';
@@ -53,7 +54,7 @@ import {
53
54
  import { import_peer } from '../../utils/import.js';
54
55
  import { compact } from '../../utils/array.js';
55
56
  import { should_ignore, has_children } from './static_analysis/utils.js';
56
- import { process_config } from '../../core/config/index.js';
57
+ import { process_config, split_config } from '../../core/config/index.js';
57
58
  import { treeshake_prerendered_remotes } from './build/remote.js';
58
59
 
59
60
  /** @type {string} */
@@ -146,46 +147,60 @@ let vite_plugin_svelte;
146
147
 
147
148
  /**
148
149
  * Returns the SvelteKit Vite plugins.
149
- * Since version 2.62.0 you can pass [configuration](configuration) directly, in which case `svelte.config.js` is ignored.
150
- * @param {KitConfig & Omit<SvelteConfig, 'onwarn'>} [config]
150
+ * Any options that don't belong to SvelteKit are passed through to `vite-plugin-svelte`.
151
+ *
152
+ * Since version 3.0.0 you must pass [configuration](configuration) directly.
153
+ *
154
+ * Since version 2.62.0 you can pass configuration directly, in which case `svelte.config.js` is ignored.
155
+ *
156
+ * @param {KitConfig & Omit<Options, 'onwarn'> & Pick<SvelteConfig, 'vitePlugin'>} [config]
151
157
  * @returns {Promise<Plugin[]>}
152
158
  */
153
159
  export async function sveltekit(config) {
154
160
  const cwd = process.cwd();
155
161
 
156
- const { extensions, compilerOptions, vitePlugin, preprocess, ...rest } = config ?? {};
157
- const svelte_config = process_config(
158
- { extensions, compilerOptions, vitePlugin, preprocess, kit: rest },
159
- { cwd, source: 'SvelteKit options from Vite config' }
160
- );
161
-
162
- const config_file = ['svelte.config.js', 'svelte.config.ts'].find((file) => fs.existsSync(file));
163
-
164
- if (config_file) {
165
- const message = `${config_file} is no longer used. Please pass configuration via the \`sveltekit(...)\` plugin in your Vite config.`;
166
-
167
- if (!config) {
168
- throw new Error(message);
169
- }
170
-
171
- console.warn(message);
162
+ // any options passed to the plugin that SvelteKit doesn't use itself are
163
+ // forwarded to vite-plugin-svelte, which does its own validation
164
+ const split = split_config(config ?? {});
165
+ const svelte_config = process_config(split.svelte_config, { cwd });
166
+
167
+ if (Array.isArray(svelte_config.preprocess)) {
168
+ svelte_config.preprocess.push(warning_preprocessor);
169
+ } else if (svelte_config.preprocess) {
170
+ svelte_config.preprocess = [svelte_config.preprocess, warning_preprocessor];
171
+ } else {
172
+ svelte_config.preprocess = warning_preprocessor;
172
173
  }
173
174
 
174
- /** @type {Options} */
175
- const vite_plugin_svelte_options = {
176
- // we don't want vite-plugin-svelte to load the config file itself because
177
- // it will try to validate it without knowing that kit options are valid
175
+ vite_plugin_svelte = await import_peer('@sveltejs/vite-plugin-svelte', cwd);
176
+
177
+ /** @type {Partial<Options>} */
178
+ const inline_vps_config = {
179
+ preprocess: svelte_config.preprocess,
180
+ ...(svelte_config.vitePlugin ?? {}),
181
+ // pass through any options that SvelteKit doesn't use itself, so that
182
+ // the options SvelteKit manages always take precedence
183
+ ...split.vite_plugin_svelte_config,
184
+ // we don't want vite-plugin-svelte to load the svelte.config.js file because
185
+ // we expect options to be passed through the SvelteKit Vite plugin
178
186
  configFile: false
179
187
  };
180
188
 
181
- vite_plugin_svelte = await import_peer('@sveltejs/vite-plugin-svelte', cwd);
189
+ // vite-plugin-svelte inline config options need to be added conditionally
190
+ // because passing undefined causes it to crash
191
+ if (svelte_config.extensions) {
192
+ inline_vps_config.extensions = svelte_config.extensions;
193
+ }
194
+
195
+ if (svelte_config.compilerOptions) {
196
+ inline_vps_config.compilerOptions = svelte_config.compilerOptions;
197
+ }
182
198
 
183
199
  return [
184
- plugin_svelte_config({ vite_plugin_svelte_options, svelte_config }),
185
- ...vite_plugin_svelte.svelte(vite_plugin_svelte_options),
200
+ plugin_svelte_config(),
201
+ ...vite_plugin_svelte.svelte(inline_vps_config),
186
202
  ...kit({
187
- svelte_config,
188
- adapter: svelte_config.kit.adapter
203
+ svelte_config
189
204
  })
190
205
  ];
191
206
  }
@@ -196,15 +211,9 @@ function resolve_root(vite_config) {
196
211
  }
197
212
 
198
213
  /**
199
- * Resolves the Svelte config using the `vite.config.root` setting before any
200
- * of our other plugins try to access the config objects
201
- * @param {{
202
- * vite_plugin_svelte_options: Options;
203
- * svelte_config: import('types').ValidatedConfig;
204
- * }} options
205
214
  * @return {Plugin}
206
215
  */
207
- function plugin_svelte_config({ vite_plugin_svelte_options, svelte_config }) {
216
+ function plugin_svelte_config() {
208
217
  return {
209
218
  name: 'vite-plugin-sveltekit-resolve-svelte-config',
210
219
  // make sure it runs first
@@ -214,21 +223,15 @@ function plugin_svelte_config({ vite_plugin_svelte_options, svelte_config }) {
214
223
  handler(config) {
215
224
  root = resolve_root(config);
216
225
 
217
- /** @type {Options['preprocess']} */
218
- let preprocess = svelte_config.preprocess;
219
- if (Array.isArray(preprocess)) {
220
- preprocess = [...preprocess, warning_preprocessor];
221
- } else if (preprocess) {
222
- preprocess = [preprocess, warning_preprocessor];
223
- } else {
224
- preprocess = warning_preprocessor;
226
+ // TODO: mjs mts?
227
+ const config_file = ['svelte.config.js', 'svelte.config.ts'].find((file) =>
228
+ fs.existsSync(`${root}/${file}`)
229
+ );
230
+ if (config_file) {
231
+ throw new Error(
232
+ `${config_file} is no longer used. Please pass configuration via the \`sveltekit(...)\` plugin in your Vite config.`
233
+ );
225
234
  }
226
-
227
- vite_plugin_svelte_options.extensions = svelte_config.extensions;
228
- vite_plugin_svelte_options.preprocess = preprocess;
229
- vite_plugin_svelte_options.onwarn = svelte_config.onwarn;
230
- vite_plugin_svelte_options.compilerOptions = { ...svelte_config.compilerOptions };
231
- Object.assign(vite_plugin_svelte_options, svelte_config.vitePlugin);
232
235
  }
233
236
  },
234
237
  // TODO: do we even need to set `root` based on the final Vite config?
@@ -253,10 +256,9 @@ function plugin_svelte_config({ vite_plugin_svelte_options, svelte_config }) {
253
256
  *
254
257
  * @param {object} opts
255
258
  * @param {import('types').ValidatedConfig} opts.svelte_config options are only resolved after the Vite `config` hook runs
256
- * @param {Adapter | undefined} opts.adapter
257
259
  * @return {Plugin[]}
258
260
  */
259
- function kit({ svelte_config, adapter }) {
261
+ function kit({ svelte_config }) {
260
262
  /** @type {typeof import('vite')} */
261
263
  let vite;
262
264
 
@@ -309,6 +311,9 @@ function kit({ svelte_config, adapter }) {
309
311
  const sourcemapIgnoreList = /** @param {string} relative_path */ (relative_path) =>
310
312
  relative_path.includes('node_modules') || relative_path.includes(kit.outDir);
311
313
 
314
+ /** @type {string} name for `globalThis.__sveltekit_xxx` */
315
+ let kit_global;
316
+
312
317
  /** @type {Plugin} */
313
318
  const plugin_setup = {
314
319
  name: 'vite-plugin-sveltekit-setup',
@@ -336,10 +341,11 @@ function kit({ svelte_config, adapter }) {
336
341
 
337
342
  version_hash = hash(kit.version.name);
338
343
 
339
- env = loadEnv(config_env.mode, kit.env.dir, '');
344
+ kit_global = is_build
345
+ ? `globalThis.__sveltekit_${version_hash}`
346
+ : 'globalThis.__sveltekit_dev';
340
347
 
341
- service_worker_entry_file = resolve_entry(kit.files.serviceWorker);
342
- parsed_service_worker = path.parse(kit.files.serviceWorker);
348
+ env = loadEnv(config_env.mode, kit.env.dir, '');
343
349
 
344
350
  vite = await import_peer('vite', root);
345
351
 
@@ -350,10 +356,18 @@ function kit({ svelte_config, adapter }) {
350
356
  const allow = new Set([
351
357
  kit.files.lib,
352
358
  kit.files.routes,
359
+ kit.files.src,
353
360
  kit.outDir,
354
361
  path.resolve(root, kit.files.src),
355
362
  path.resolve(root, 'node_modules'),
356
- path.resolve(process.cwd(), 'node_modules')
363
+ // ensures that the client entry is served even if it's located outside
364
+ // the local node_modules, such as the pnpm global virtual store
365
+ runtime_directory,
366
+ path.resolve('node_modules'),
367
+ // include the directory that contains the workspaces declaration
368
+ // which usually also contains hoisted packages
369
+ // see https://vite.dev/guide/api-javascript#searchforworkspaceroot
370
+ path.resolve(vite.searchForWorkspaceRoot(process.cwd()), 'node_modules')
357
371
  ]);
358
372
 
359
373
  // We can only add directories to the allow list, so we find out
@@ -381,7 +395,7 @@ function kit({ svelte_config, adapter }) {
381
395
  sourcemapIgnoreList,
382
396
  watch: {
383
397
  ignored: [
384
- // Ignore all siblings of config.kit.outDir/generated
398
+ // Ignore all siblings of config.outDir/generated
385
399
  `${out_dir}/!(generated)`
386
400
  ]
387
401
  }
@@ -461,7 +475,7 @@ function kit({ svelte_config, adapter }) {
461
475
  if (is_build) {
462
476
  new_config.define = {
463
477
  ...define,
464
- __SVELTEKIT_ADAPTER_NAME__: s(adapter?.name),
478
+ __SVELTEKIT_ADAPTER_NAME__: s(kit.adapter?.name),
465
479
  __SVELTEKIT_APP_VERSION_FILE__: s(`${kit.appDir}/version.json`),
466
480
  __SVELTEKIT_APP_VERSION_POLL_INTERVAL__: s(kit.version.pollInterval)
467
481
  };
@@ -471,7 +485,7 @@ function kit({ svelte_config, adapter }) {
471
485
  new_config.define = {
472
486
  ...define,
473
487
  __SVELTEKIT_APP_VERSION_POLL_INTERVAL__: '0',
474
- __SVELTEKIT_PAYLOAD__: 'globalThis.__sveltekit_dev',
488
+ __SVELTEKIT_PAYLOAD__: kit_global,
475
489
  __SVELTEKIT_HAS_SERVER_LOAD__: 'true',
476
490
  __SVELTEKIT_HAS_UNIVERSAL_LOAD__: 'true'
477
491
  };
@@ -544,52 +558,28 @@ function kit({ svelte_config, adapter }) {
544
558
  });
545
559
  },
546
560
 
547
- resolveId(id, importer) {
548
- if (id === '__sveltekit/manifest') {
549
- return `${out_dir}/generated/client-optimized/app.js`;
550
- }
551
-
552
- // If importing from a service-worker, only allow $service-worker & $app/env/public, but none of the other virtual modules.
553
- // This check won't catch transitive imports, but it will warn when the import comes from a service-worker directly.
554
- // Transitive imports will be caught during the build.
555
- // TODO move this logic to plugin_guard. add a filter to this resolveId when doing so
556
- // TODO allow $app/env/public
557
- if (importer) {
558
- const parsed_importer = path.parse(importer);
559
-
560
- const importer_is_service_worker =
561
- parsed_importer.dir === parsed_service_worker.dir &&
562
- parsed_importer.name === parsed_service_worker.name;
563
-
564
- if (
565
- importer_is_service_worker &&
566
- id !== '$service-worker' &&
567
- id !== 'virtual:$app/env/public' &&
568
- id !== '__sveltekit/env/service-worker'
569
- ) {
570
- throw new Error(
571
- `Cannot import ${normalize_id(
572
- id,
573
- normalized_lib,
574
- normalized_cwd
575
- )} into service-worker code. Only the modules $service-worker and $app/env/public are available in service workers.`
576
- );
561
+ resolveId: {
562
+ filter: {
563
+ id: [exactRegex('$service-worker'), prefixRegex('__sveltekit/')]
564
+ },
565
+ handler(id) {
566
+ if (id === '__sveltekit/manifest') {
567
+ return `${out_dir}/generated/client-optimized/app.js`;
577
568
  }
578
- }
579
569
 
580
- if (id === '$service-worker') {
581
- // ids with :$ don't work with reverse proxies like nginx
582
- return `\0virtual:${id.substring(1)}`;
583
- }
570
+ if (id === '$service-worker') {
571
+ // ids with :$ don't work with reverse proxies like nginx
572
+ return `\0virtual:${id.substring(1)}`;
573
+ }
584
574
 
585
- if (id === '__sveltekit/remote') {
586
- return `${runtime_directory}/client/remote-functions/index.js`;
587
- }
575
+ if (id === '__sveltekit/remote') {
576
+ return `${runtime_directory}/client/remote-functions/index.js`;
577
+ }
588
578
 
589
- if (id.startsWith('__sveltekit/')) {
590
579
  return `\0virtual:${id}`;
591
580
  }
592
581
  },
582
+
593
583
  load: {
594
584
  filter: {
595
585
  id: [
@@ -603,10 +593,6 @@ function kit({ svelte_config, adapter }) {
603
593
  ]
604
594
  },
605
595
  handler(id) {
606
- const global = is_build
607
- ? `globalThis.__sveltekit_${version_hash}`
608
- : 'globalThis.__sveltekit_dev';
609
-
610
596
  switch (id) {
611
597
  case service_worker:
612
598
  return create_service_worker_module(svelte_config);
@@ -618,7 +604,7 @@ function kit({ svelte_config, adapter }) {
618
604
  return create_sveltekit_env_public(
619
605
  explicit_env_config,
620
606
  env,
621
- `const env = ${global}.env;`
607
+ `const env = ${kit_global}.env;`
622
608
  );
623
609
 
624
610
  case sveltekit_env_public_server:
@@ -632,7 +618,15 @@ function kit({ svelte_config, adapter }) {
632
618
  return create_sveltekit_env_private(explicit_env_config, env);
633
619
 
634
620
  case sveltekit_env_service_worker:
635
- return create_sveltekit_env_service_worker_dev(explicit_env_config, env, global);
621
+ return is_build
622
+ ? create_sveltekit_env_service_worker(
623
+ explicit_env_config,
624
+ env,
625
+ kit_global,
626
+ kit.paths.base,
627
+ kit.appDir
628
+ )
629
+ : create_sveltekit_env_service_worker_dev(explicit_env_config, env, kit_global);
636
630
 
637
631
  case sveltekit_server: {
638
632
  return dedent`
@@ -656,7 +650,10 @@ function kit({ svelte_config, adapter }) {
656
650
 
657
651
  /** @type {Map<string, Set<string>>} */
658
652
  const import_map = new Map();
659
- const server_only_pattern = /.*\.server\..+/;
653
+ // Matches any ID that has .server. in its filename
654
+ const server_only_module_pattern = /\.server\.[^/]+$/;
655
+ // Matches any ID that has /server/ in its path
656
+ const server_only_directory_pattern = /\/server\//;
660
657
 
661
658
  /**
662
659
  * Ensures that client-side code can't accidentally import server-side code,
@@ -706,8 +703,8 @@ function kit({ svelte_config, adapter }) {
706
703
  id: [
707
704
  exactRegex(app_server),
708
705
  exactRegex(app_env_private),
709
- /\/server\//,
710
- new RegExp(`${server_only_pattern.source}$`)
706
+ server_only_module_pattern,
707
+ server_only_directory_pattern
711
708
  ]
712
709
  },
713
710
  handler(id) {
@@ -722,8 +719,8 @@ function kit({ svelte_config, adapter }) {
722
719
  const is_server_only =
723
720
  normalized === '$app/env/private' ||
724
721
  normalized === '$app/server' ||
725
- normalized.startsWith('$lib/server/') ||
726
- (is_internal && server_only_pattern.test(path.basename(id)));
722
+ (normalized.startsWith('$lib/') && server_only_directory_pattern.test(id)) ||
723
+ (is_internal && server_only_module_pattern.test(id));
727
724
 
728
725
  // skip .server.js files outside the cwd or in node_modules, as the filename might not mean 'server-only module' in this context
729
726
  // TODO: address https://github.com/sveltejs/kit/issues/12529
@@ -965,7 +962,7 @@ function kit({ svelte_config, adapter }) {
965
962
  let prerendered;
966
963
 
967
964
  /** @type {Set<string>} */
968
- let build;
965
+ let build_files;
969
966
  /** @type {string} */
970
967
  let service_worker_code;
971
968
 
@@ -976,43 +973,132 @@ function kit({ svelte_config, adapter }) {
976
973
  const plugin_service_worker = {
977
974
  name: 'vite-plugin-sveltekit-service-worker',
978
975
 
976
+ config(config) {
977
+ service_worker_entry_file = resolve_entry(kit.files.serviceWorker);
978
+ parsed_service_worker = path.parse(kit.files.serviceWorker);
979
+
980
+ if (!service_worker_entry_file) return;
981
+
982
+ if (kit.paths.assets) {
983
+ throw new Error('Cannot use service worker alongside config.paths.assets');
984
+ }
985
+
986
+ const user_service_worker_output_config =
987
+ config.environments?.serviceWorker?.build?.rolldownOptions?.output;
988
+
989
+ /** @type {import('vite').UserConfig} */
990
+ const new_config = {
991
+ environments: {
992
+ serviceWorker: {
993
+ build: {
994
+ modulePreload: false,
995
+ rolldownOptions: {
996
+ external: [`${kit.paths.base}/${kit.appDir}/env.js`],
997
+ input: {
998
+ 'service-worker': service_worker_entry_file
999
+ },
1000
+ output: {
1001
+ format: 'es',
1002
+ entryFileNames: 'service-worker.js',
1003
+ assetFileNames: `${kit.appDir}/immutable/assets/[name].[hash][extname]`,
1004
+ codeSplitting:
1005
+ (Array.isArray(user_service_worker_output_config)
1006
+ ? user_service_worker_output_config[0].codeSplitting
1007
+ : user_service_worker_output_config?.codeSplitting) ?? false
1008
+ }
1009
+ },
1010
+ outDir: `${out}/client`,
1011
+ minify: initial_config.build?.minify,
1012
+ // avoid overwriting the client build Vite manifest
1013
+ manifest: '.vite/service-worker-manifest.json'
1014
+ },
1015
+ consumer: 'client'
1016
+ }
1017
+ }
1018
+ };
1019
+
1020
+ warn_overridden_config(config, new_config);
1021
+
1022
+ return new_config;
1023
+ },
1024
+
1025
+ // the serviceWorker environment only applies during build because Vite currently
1026
+ // only supports the default client environment during development
979
1027
  applyToEnvironment(environment) {
980
1028
  return environment.name === 'serviceWorker';
981
1029
  },
982
1030
 
983
- resolveId: {
984
- handler(id) {
985
- if (id.startsWith('$app/') || id === '$service-worker') {
986
- // ids with :$ don't work with reverse proxies like nginx
987
- return `\0virtual:${id.substring(1)}`;
988
- }
1031
+ resolveId(id, importer) {
1032
+ // If importing from a service-worker, only allow $service-worker & $app/env/public, but none of the other virtual modules.
1033
+ // This check won't catch transitive imports, but it will warn when the import comes from a service-worker directly.
1034
+ // Transitive imports will be caught during the build.
1035
+ if (importer) {
1036
+ const parsed_importer = path.parse(importer);
1037
+
1038
+ const importer_is_service_worker =
1039
+ parsed_importer.dir === parsed_service_worker.dir &&
1040
+ parsed_importer.name === parsed_service_worker.name;
989
1041
 
990
- if (id.startsWith('__sveltekit')) {
991
- return `\0virtual:${id}`;
1042
+ if (
1043
+ importer_is_service_worker &&
1044
+ id !== '$service-worker' &&
1045
+ id !== 'virtual:$app/env/public' &&
1046
+ id !== '__sveltekit/env/service-worker'
1047
+ ) {
1048
+ throw new Error(
1049
+ `Cannot import ${normalize_id(
1050
+ id,
1051
+ normalized_lib,
1052
+ normalized_cwd
1053
+ )} into service-worker code. Only the modules $service-worker and $app/env/public are available in service workers.`
1054
+ );
992
1055
  }
993
1056
  }
1057
+
1058
+ if (id.startsWith('$app/') || id === '$service-worker') {
1059
+ // ids with :$ don't work with reverse proxies like nginx
1060
+ return `\0virtual:${id.substring(1)}`;
1061
+ }
1062
+
1063
+ if (id.startsWith('__sveltekit')) {
1064
+ return `\0virtual:${id}`;
1065
+ }
994
1066
  },
995
1067
 
996
- load(id) {
997
- if (!build) {
998
- build = new Set();
999
- const manifest = vite_client_manifest ?? vite_server_manifest;
1000
- for (const key in manifest) {
1001
- const { file, css = [], assets = [] } = manifest[key];
1002
- build.add(file);
1003
- css.forEach((file) => build.add(file));
1004
- assets.forEach((file) => build.add(file));
1005
- }
1068
+ load: {
1069
+ filter: {
1070
+ id: [prefixRegex('\0virtual:')]
1071
+ },
1072
+ handler(id) {
1073
+ if (!build_files) {
1074
+ build_files = new Set();
1075
+ const manifest = vite_client_manifest ?? vite_server_manifest;
1076
+ for (const key in manifest) {
1077
+ const { file, css = [], assets = [] } = manifest[key];
1078
+ build_files.add(file);
1079
+ css.forEach((file) => build_files.add(file));
1080
+ assets.forEach((file) => build_files.add(file));
1081
+ }
1082
+
1083
+ if (kit.output.bundleStrategy === 'inline') {
1084
+ // the bundle and stylesheet are inlined into the page and their files
1085
+ // deleted, so they must not appear in the list of cacheable assets
1086
+ for (const file of build_files) {
1087
+ if (!fs.existsSync(`${out}/client/${file}`)) {
1088
+ build_files.delete(file);
1089
+ }
1090
+ }
1091
+ }
1006
1092
 
1007
- // in a service worker, `location` is the location of the service worker itself,
1008
- // which is guaranteed to be `<base>/service-worker.js`
1009
- const base = "location.pathname.split('/').slice(0, -1).join('/')";
1093
+ // in a service worker, `location` is the location of the service worker itself,
1094
+ // which is guaranteed to be `<base>/service-worker.js`
1095
+ const base = "location.pathname.split('/').slice(0, -1).join('/')";
1010
1096
 
1011
- service_worker_code = dedent`
1097
+ service_worker_code = dedent`
1012
1098
  export const base = /*@__PURE__*/ ${base};
1013
1099
 
1014
1100
  export const build = [
1015
- ${Array.from(build)
1101
+ ${Array.from(build_files)
1016
1102
  .map((file) => `base + ${s(`/${file}`)}`)
1017
1103
  .join(',\n')}
1018
1104
  ];
@@ -1029,34 +1115,41 @@ function kit({ svelte_config, adapter }) {
1029
1115
  ];
1030
1116
 
1031
1117
  export const version = ${s(kit.version.name)};
1032
- `;
1033
- }
1034
-
1035
- if (!id.startsWith('\0virtual:')) return;
1118
+ `;
1119
+ }
1036
1120
 
1037
- const global = is_build
1038
- ? `globalThis.__sveltekit_${version_hash}`
1039
- : 'globalThis.__sveltekit_dev';
1121
+ if (id === service_worker) {
1122
+ return service_worker_code;
1123
+ }
1040
1124
 
1041
- if (id === service_worker) {
1042
- return service_worker_code;
1043
- }
1125
+ if (id === sveltekit_env_service_worker) {
1126
+ return is_build
1127
+ ? create_sveltekit_env_service_worker(
1128
+ explicit_env_config,
1129
+ env,
1130
+ kit_global,
1131
+ kit.paths.base,
1132
+ kit.appDir
1133
+ )
1134
+ : create_sveltekit_env_service_worker_dev(explicit_env_config, env, kit_global);
1135
+ }
1044
1136
 
1045
- if (id === sveltekit_env_service_worker) {
1046
- return create_sveltekit_env_service_worker_dev(explicit_env_config, env, global);
1047
- }
1137
+ if (id === sveltekit_env_public_client) {
1138
+ return create_sveltekit_env_public(
1139
+ explicit_env_config,
1140
+ env,
1141
+ `const env = ${kit_global}.env;`
1142
+ );
1143
+ }
1048
1144
 
1049
- if (id === sveltekit_env_public_client) {
1050
- return create_sveltekit_env_public(explicit_env_config, env, `const env = ${global}.env;`);
1145
+ const normalized_cwd = vite.normalizePath(vite_config.root);
1146
+ const normalized_lib = vite.normalizePath(kit.files.lib);
1147
+ const relative = normalize_id(id, normalized_lib, normalized_cwd);
1148
+ const stripped = strip_virtual_prefix(relative);
1149
+ throw new Error(
1150
+ `Cannot import ${stripped} into service-worker code. Only the modules $service-worker and $app/env/public are available in service workers.`
1151
+ );
1051
1152
  }
1052
-
1053
- const normalized_cwd = vite.normalizePath(vite_config.root);
1054
- const normalized_lib = vite.normalizePath(kit.files.lib);
1055
- const relative = normalize_id(id, normalized_lib, normalized_cwd);
1056
- const stripped = strip_virtual_prefix(relative);
1057
- throw new Error(
1058
- `Cannot import ${stripped} into service-worker code. Only the modules $service-worker and $app/env/public are available in service workers.`
1059
- );
1060
1153
  }
1061
1154
  };
1062
1155
 
@@ -1069,10 +1162,11 @@ function kit({ svelte_config, adapter }) {
1069
1162
  id: service_worker_entry_file || '<skip>'
1070
1163
  },
1071
1164
  handler(code) {
1072
- // in dev, we prepend the service worker with an import that
1073
- // configures `env`, in case `$app/env/public` is imported,
1074
- // in prod, where we currently use non-module service
1075
- // workers, we have to use `importScripts` instead
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.
1076
1170
  return {
1077
1171
  code: `import '__sveltekit/env/service-worker';\n${code}`
1078
1172
  };
@@ -1106,6 +1200,7 @@ function kit({ svelte_config, adapter }) {
1106
1200
  const server_input = {
1107
1201
  index: `${runtime_directory}/server/index.js`,
1108
1202
  internal: `${out_dir}/generated/server/internal.js`,
1203
+ env: '__sveltekit/env',
1109
1204
  ['remote-entry']: `${runtime_directory}/app/server/remote/index.js`
1110
1205
  };
1111
1206
 
@@ -1156,8 +1251,8 @@ function kit({ svelte_config, adapter }) {
1156
1251
  path.join(kit.files.src, 'instrumentation.server')
1157
1252
  );
1158
1253
  if (server_instrumentation) {
1159
- if (adapter && !adapter.supports?.instrumentation?.()) {
1160
- throw new Error(`${server_instrumentation} is unsupported in ${adapter.name}.`);
1254
+ if (kit.adapter && !kit.adapter.supports?.instrumentation?.()) {
1255
+ throw new Error(`${server_instrumentation} is unsupported in ${kit.adapter.name}.`);
1161
1256
  }
1162
1257
  if (!kit.experimental.instrumentation.server) {
1163
1258
  error_for_missing_config(
@@ -1195,9 +1290,16 @@ function kit({ svelte_config, adapter }) {
1195
1290
  .map(() => '..')
1196
1291
  .join('/') + '/../';
1197
1292
 
1293
+ const relative = kit.paths.relative !== false || !!kit.paths.assets;
1294
+
1198
1295
  new_config = {
1199
1296
  appType: 'custom',
1200
- base: './',
1297
+ // Affects how Vite loads JS assets on the client.
1298
+ // If the initial HTML we render uses an absolute path for assets,
1299
+ // the additional chunks Vite loads must also use an absolute path.
1300
+ // Otherwise, you end up with additional chunks being loaded relative
1301
+ // to the current chunk rather than the root.
1302
+ base: relative ? './' : base,
1201
1303
  build: {
1202
1304
  cssCodeSplit: !inline,
1203
1305
  cssMinify:
@@ -1261,7 +1363,8 @@ function kit({ svelte_config, adapter }) {
1261
1363
  format: inline ? 'iife' : 'esm',
1262
1364
  entryFileNames: `${prefix}/[name].[hash].js`,
1263
1365
  chunkFileNames: `${prefix}/chunks/[hash].js`,
1264
- codeSplitting: svelte_config.kit.output.bundleStrategy === 'split'
1366
+ codeSplitting:
1367
+ svelte_config.kit.output.bundleStrategy === 'split' ? undefined : false
1265
1368
  },
1266
1369
  // This silences Rolldown warnings about not supporting `import.meta`
1267
1370
  // for the `iife` output format. We don't care because it's
@@ -1276,7 +1379,7 @@ function kit({ svelte_config, adapter }) {
1276
1379
  }
1277
1380
  },
1278
1381
  define: {
1279
- __SVELTEKIT_PAYLOAD__: `globalThis.__sveltekit_${version_hash}`
1382
+ __SVELTEKIT_PAYLOAD__: kit_global
1280
1383
  }
1281
1384
  }
1282
1385
  },
@@ -1292,9 +1395,7 @@ function kit({ svelte_config, adapter }) {
1292
1395
  // E.g. Vite generates `new URL('/asset.png', import.meta).href` for a relative path vs just '/asset.png'.
1293
1396
  // That's larger and takes longer to run and also causes an HTML diff between SSR and client
1294
1397
  // causing us to do a more expensive hydration check.
1295
- return {
1296
- relative: kit.paths.relative !== false || !!kit.paths.assets
1297
- };
1398
+ return { relative };
1298
1399
  }
1299
1400
 
1300
1401
  // _app/immutable/assets files
@@ -1308,29 +1409,6 @@ function kit({ svelte_config, adapter }) {
1308
1409
  },
1309
1410
  publicDir: kit.files.assets
1310
1411
  };
1311
-
1312
- if (service_worker_entry_file) {
1313
- /** @type {Record<string, EnvironmentOptions>} */ (
1314
- new_config.environments
1315
- ).serviceWorker = {
1316
- build: {
1317
- modulePreload: false,
1318
- rolldownOptions: {
1319
- input: {
1320
- 'service-worker': service_worker_entry_file
1321
- },
1322
- output: {
1323
- entryFileNames: 'service-worker.js',
1324
- assetFileNames: `${kit.appDir}/immutable/assets/[name].[hash][extname]`,
1325
- codeSplitting: false
1326
- }
1327
- },
1328
- outDir: `${out}/client`,
1329
- minify: initial_config.build?.minify
1330
- },
1331
- consumer: 'client'
1332
- };
1333
- }
1334
1412
  } else {
1335
1413
  new_config = {
1336
1414
  appType: 'custom',
@@ -1359,7 +1437,7 @@ function kit({ svelte_config, adapter }) {
1359
1437
  * @see https://vitejs.dev/guide/api-plugin.html#configureserver
1360
1438
  */
1361
1439
  async configureServer(vite) {
1362
- return await dev(vite, vite_config, svelte_config, () => remotes, root, adapter);
1440
+ return await dev(vite, vite_config, svelte_config, () => remotes, root);
1363
1441
  },
1364
1442
 
1365
1443
  /**
@@ -1367,7 +1445,7 @@ function kit({ svelte_config, adapter }) {
1367
1445
  * @see https://vitejs.dev/guide/api-plugin.html#configurepreviewserver
1368
1446
  */
1369
1447
  configurePreviewServer(vite) {
1370
- return preview(vite, vite_config, svelte_config, adapter);
1448
+ return preview(vite, vite_config, svelte_config);
1371
1449
  },
1372
1450
 
1373
1451
  renderChunk(code, chunk) {
@@ -1536,6 +1614,18 @@ function kit({ svelte_config, adapter }) {
1536
1614
  const deps_of = (entry, add_dynamic_css = false) =>
1537
1615
  find_deps(vite_manifest, posixify(path.relative(root, entry)), add_dynamic_css, root);
1538
1616
 
1617
+ const has_explicit_dynamic_public_env = Object.values(explicit_env_config ?? {}).some(
1618
+ (variable) => variable.public && !variable.static
1619
+ );
1620
+
1621
+ // the app only depends on runtime public env if it imports `$app/env/public`
1622
+ // *and* at least one public env var is actually dynamic (non-static)
1623
+ const uses_env_dynamic_public =
1624
+ has_explicit_dynamic_public_env &&
1625
+ client_chunks.some(
1626
+ (chunk) => chunk.type === 'chunk' && chunk.modules[sveltekit_env_public_client]
1627
+ );
1628
+
1539
1629
  if (svelte_config.kit.output.bundleStrategy === 'split') {
1540
1630
  const start = deps_of(`${runtime_directory}/client/entry.js`);
1541
1631
  const app = deps_of(`${out_dir}/generated/client-optimized/app.js`);
@@ -1546,9 +1636,7 @@ function kit({ svelte_config, adapter }) {
1546
1636
  imports: [...start.imports, ...app.imports],
1547
1637
  stylesheets: [...start.stylesheets, ...app.stylesheets],
1548
1638
  fonts: [...start.fonts, ...app.fonts],
1549
- uses_env_dynamic_public: client_chunks.some(
1550
- (chunk) => chunk.type === 'chunk' && chunk.modules[sveltekit_env_public_client]
1551
- )
1639
+ uses_env_dynamic_public
1552
1640
  };
1553
1641
 
1554
1642
  // In case of server-side route resolution, we create a purpose-built route manifest that is
@@ -1596,9 +1684,7 @@ function kit({ svelte_config, adapter }) {
1596
1684
  imports: start.imports,
1597
1685
  stylesheets: start.stylesheets,
1598
1686
  fonts: start.fonts,
1599
- uses_env_dynamic_public: client_chunks.some(
1600
- (chunk) => chunk.type === 'chunk' && chunk.modules[sveltekit_env_public_client]
1601
- )
1687
+ uses_env_dynamic_public
1602
1688
  };
1603
1689
 
1604
1690
  if (svelte_config.kit.output.bundleStrategy === 'inline') {
@@ -1615,6 +1701,12 @@ function kit({ svelte_config, adapter }) {
1615
1701
  script: read(`${out}/client/${start.file}`),
1616
1702
  style: /** @type {string | undefined} */ (style?.source)
1617
1703
  };
1704
+
1705
+ // the bundle and stylesheet are inlined into the page, so the
1706
+ // emitted files are never loaded
1707
+ fs.unlinkSync(`${out}/client/${start.file}`);
1708
+ fs.rmSync(`${out}/client/${start.file}.map`, { force: true });
1709
+ if (style) fs.unlinkSync(`${out}/client/${style.fileName}`);
1618
1710
  }
1619
1711
  }
1620
1712
 
@@ -1637,7 +1729,7 @@ function kit({ svelte_config, adapter }) {
1637
1729
  kit,
1638
1730
  manifest_data,
1639
1731
  vite_server_manifest,
1640
- vite_manifest,
1732
+ vite_client_manifest,
1641
1733
  assets_path,
1642
1734
  client_chunks,
1643
1735
  root
@@ -1685,17 +1777,16 @@ function kit({ svelte_config, adapter }) {
1685
1777
  );
1686
1778
 
1687
1779
  if (service_worker_entry_file) {
1688
- if (kit.paths.assets) {
1689
- throw new Error('Cannot use service worker alongside config.kit.paths.assets');
1690
- }
1691
-
1692
1780
  log.info('Building service worker');
1693
1781
 
1782
+ // mirror client settings that we couldn't set per environment in the config hook
1694
1783
  builder.environments.serviceWorker.config.define =
1695
1784
  builder.environments.client.config.define;
1696
1785
  builder.environments.serviceWorker.config.resolve.alias = [
1697
1786
  ...get_config_aliases(kit, vite_config.root)
1698
1787
  ];
1788
+
1789
+ // we have to overwrite this because it can't be configured per environment in the config hook
1699
1790
  builder.environments.serviceWorker.config.experimental.renderBuiltUrl = (filename) => {
1700
1791
  return {
1701
1792
  runtime: `new URL(${JSON.stringify(filename)}, location.href).pathname`
@@ -1709,10 +1800,9 @@ function kit({ svelte_config, adapter }) {
1709
1800
  `\nRun ${styleText(['bold', 'cyan'], 'npm run preview')} to preview your production build locally.`
1710
1801
  );
1711
1802
 
1712
- if (adapter) {
1803
+ if (kit.adapter) {
1713
1804
  const { adapt } = await import('../../core/adapt/index.js');
1714
1805
  await adapt(
1715
- adapter,
1716
1806
  svelte_config,
1717
1807
  build_data,
1718
1808
  metadata,
@@ -1734,17 +1824,6 @@ function kit({ svelte_config, adapter }) {
1734
1824
  }
1735
1825
  };
1736
1826
 
1737
- /** @type {Plugin} */
1738
- const plugin_adapter = {
1739
- name: 'vite-plugin-sveltekit-adapter',
1740
- apply: 'build',
1741
- // expose the adapter so that forked processes (e.g. prerendering)
1742
- // can retrieve it by resolving the Vite config
1743
- api: {
1744
- adapter
1745
- }
1746
- };
1747
-
1748
1827
  return [
1749
1828
  plugin_setup,
1750
1829
  plugin_remote,
@@ -1752,8 +1831,7 @@ function kit({ svelte_config, adapter }) {
1752
1831
  process.env.TEST !== 'true' ? plugin_guard : undefined,
1753
1832
  service_worker_entry_file && plugin_service_worker_env,
1754
1833
  plugin_service_worker,
1755
- plugin_compile,
1756
- plugin_adapter
1834
+ plugin_compile
1757
1835
  ].filter((p) => !!p);
1758
1836
  }
1759
1837
 
@@ -1789,13 +1867,18 @@ function find_overridden_config(config, resolved_config, enforced_config, path,
1789
1867
  for (const key in enforced_config) {
1790
1868
  if (typeof config === 'object' && key in config && key in resolved_config) {
1791
1869
  const enforced = enforced_config[key];
1870
+ const resolved = resolved_config[key];
1792
1871
 
1793
1872
  if (enforced === true) {
1794
- if (config[key] !== resolved_config[key]) {
1873
+ // Normalize path separators before comparing to avoid false positives on Windows,
1874
+ // where config values like `root` may use backslashes while SvelteKit uses forward slashes.
1875
+ const a = typeof config[key] === 'string' ? posixify(config[key]) : config[key];
1876
+ const b = typeof resolved === 'string' ? posixify(resolved) : resolved;
1877
+ if (a !== b) {
1795
1878
  out.push(path + key);
1796
1879
  }
1797
1880
  } else {
1798
- find_overridden_config(config[key], resolved_config[key], enforced, path + key + '.', out);
1881
+ find_overridden_config(config[key], resolved, enforced, path + key + '.', out);
1799
1882
  }
1800
1883
  }
1801
1884
  }
@@ -1810,6 +1893,7 @@ const create_service_worker_module = (config) => dedent`
1810
1893
  throw new Error('This module can only be imported inside a service worker');
1811
1894
  }
1812
1895
 
1896
+ export const base = location.pathname.split('/').slice(0, -1).join('/');
1813
1897
  export const build = [];
1814
1898
  export const files = [
1815
1899
  ${create_assets(config)