@sveltejs/kit 3.0.0-next.20 → 3.0.0-next.22

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 (44) hide show
  1. package/package.json +7 -3
  2. package/src/cli.js +2 -2
  3. package/src/core/adapt/builder.js +14 -14
  4. package/src/core/adapt/index.js +16 -2
  5. package/src/core/config/index.js +33 -44
  6. package/src/core/config/options.js +66 -44
  7. package/src/core/env.js +3 -3
  8. package/src/core/postbuild/analyse.js +1 -1
  9. package/src/core/postbuild/prerender.js +48 -20
  10. package/src/core/sync/create_manifest_data/index.js +11 -11
  11. package/src/core/sync/sync.js +8 -8
  12. package/src/core/sync/write_app_types.js +2 -2
  13. package/src/core/sync/write_client_manifest.js +1 -1
  14. package/src/core/sync/write_server.js +14 -14
  15. package/src/core/sync/write_tsconfig/index.js +4 -4
  16. package/src/core/sync/write_types/index.js +7 -8
  17. package/src/exports/index.js +0 -10
  18. package/src/exports/public.d.ts +0 -590
  19. package/src/exports/remote/index.js +11 -0
  20. package/src/exports/remote/public.d.ts +519 -0
  21. package/src/exports/vite/build/build_server.js +2 -2
  22. package/src/exports/vite/dev/index.js +28 -31
  23. package/src/exports/vite/index.js +100 -49
  24. package/src/exports/vite/preview/index.js +10 -10
  25. package/src/exports/vite/public.d.ts +588 -0
  26. package/src/exports/vite/utils.js +1 -1
  27. package/src/runtime/app/server/public.d.ts +0 -518
  28. package/src/runtime/app/server/remote/command.js +1 -1
  29. package/src/runtime/app/server/remote/form.js +1 -1
  30. package/src/runtime/app/server/remote/prerender.js +1 -1
  31. package/src/runtime/app/server/remote/query.js +1 -1
  32. package/src/runtime/app/server/remote/requested.js +1 -1
  33. package/src/runtime/client/remote-functions/command.svelte.js +1 -1
  34. package/src/runtime/client/remote-functions/form.svelte.js +1 -1
  35. package/src/runtime/client/remote-functions/prerender.svelte.js +1 -1
  36. package/src/runtime/client/remote-functions/query/index.js +1 -1
  37. package/src/runtime/client/remote-functions/query-batch.svelte.js +1 -1
  38. package/src/runtime/client/remote-functions/query-live/index.js +1 -1
  39. package/src/runtime/client/remote-functions/shared.svelte.js +1 -1
  40. package/src/runtime/server/remote-functions.js +1 -1
  41. package/src/types/internal.d.ts +6 -10
  42. package/src/version.js +1 -1
  43. package/types/index.d.ts +2582 -2559
  44. package/types/index.d.ts.map +64 -60
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "3.0.0-next.20",
3
+ "version": "3.0.0-next.22",
4
4
  "description": "SvelteKit is the fastest way to build Svelte apps",
5
5
  "keywords": [
6
6
  "framework",
@@ -18,6 +18,7 @@
18
18
  "homepage": "https://svelte.dev",
19
19
  "type": "module",
20
20
  "dependencies": {
21
+ "@rolldown/pluginutils": "^1.0.1",
21
22
  "@standard-schema/spec": "^1.1.0",
22
23
  "@sveltejs/acorn-typescript": "^1.0.12",
23
24
  "acorn": "^8.18.0",
@@ -37,7 +38,6 @@
37
38
  "@types/node": "^22.19.19",
38
39
  "dts-buddy": "^0.8.3",
39
40
  "jsdom": "^30.0.0",
40
- "rolldown": "^1.2.3",
41
41
  "svelte": "^5.56.8",
42
42
  "svelte-preprocess": "^6.0.5",
43
43
  "typescript": "~6.0.3",
@@ -129,6 +129,10 @@
129
129
  "types": "./types/index.d.ts",
130
130
  "import": "./src/exports/params/index.js"
131
131
  },
132
+ "./remote": {
133
+ "types": "./types/index.d.ts",
134
+ "import": "./src/exports/remote/index.js"
135
+ },
132
136
  "./vite": {
133
137
  "types": "./types/index.d.ts",
134
138
  "import": "./src/exports/vite/index.js"
@@ -153,7 +157,7 @@
153
157
  "test:server-side-route-resolution:build": "pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test:server-side-route-resolution:build",
154
158
  "test:svelte-async:dev": "pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test:svelte-async:dev",
155
159
  "test:svelte-async:build": "pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test:svelte-async:build",
156
- "test:unit": "vitest run ./",
160
+ "test:unit": "vitest run -c vitest.kit.config.js",
157
161
  "tsc-native": "node node_modules/@typescript/native/bin/tsc",
158
162
  "generate:version": "node scripts/generate-version.js",
159
163
  "generate:types": "node scripts/generate-dts.js"
package/src/cli.js CHANGED
@@ -105,8 +105,8 @@ if (command === 'sync') {
105
105
  const sync = await import('./core/sync/sync.js');
106
106
  sync.all_types(sveltekit_config, vite_config.root);
107
107
 
108
- const explicit_env_entry = resolve_explicit_env_entry(sveltekit_config.kit);
109
- await sync.env(vite, sveltekit_config.kit, explicit_env_entry, vite_config.root, values.mode);
108
+ const explicit_env_entry = resolve_explicit_env_entry(sveltekit_config);
109
+ await sync.env(vite, sveltekit_config, explicit_env_entry, vite_config.root, values.mode);
110
110
  } catch (error) {
111
111
  handle_error(error);
112
112
  } finally {
@@ -141,15 +141,15 @@ export function create_builder({
141
141
  },
142
142
 
143
143
  async generateFallback(dest) {
144
- const manifest_path = `${config.kit.outDir}/output/server/manifest-full.js`;
145
- const env = loadEnv(vite_config.mode, config.kit.env.dir, '');
144
+ const manifest_path = `${config.outDir}/output/server/manifest-full.js`;
145
+ const env = loadEnv(vite_config.mode, config.env.dir, '');
146
146
 
147
147
  const fallback = await generate_fallback({
148
148
  manifest_path,
149
149
  env,
150
- out_dir: config.kit.outDir,
151
- origin: config.kit.paths.origin || 'http://sveltekit-prerender',
152
- assets: config.kit.files.assets
150
+ out_dir: config.outDir,
151
+ origin: config.paths.origin || 'http://sveltekit-prerender',
152
+ assets: config.files.assets
153
153
  });
154
154
 
155
155
  if (existsSync(dest)) {
@@ -164,8 +164,8 @@ export function create_builder({
164
164
  generateEnvModule() {
165
165
  if (!build_data.client?.uses_env_dynamic_public) return;
166
166
 
167
- const dest = `${config.kit.outDir}/output/prerendered/dependencies/${config.kit.appDir}`;
168
- const env = loadEnv(vite_config.mode, config.kit.env.dir, '');
167
+ const dest = `${config.outDir}/output/prerendered/dependencies/${config.appDir}`;
168
+ const env = loadEnv(vite_config.mode, config.env.dir, '');
169
169
 
170
170
  /** @type {Record<string, any>} */
171
171
  const values = {};
@@ -200,15 +200,15 @@ export function create_builder({
200
200
  },
201
201
 
202
202
  getBuildDirectory(name) {
203
- return `${config.kit.outDir}/${name}`;
203
+ return `${config.outDir}/${name}`;
204
204
  },
205
205
 
206
206
  getClientDirectory() {
207
- return `${config.kit.outDir}/output/client`;
207
+ return `${config.outDir}/output/client`;
208
208
  },
209
209
 
210
210
  getServerDirectory() {
211
- return `${config.kit.outDir}/output/server`;
211
+ return `${config.outDir}/output/server`;
212
212
  },
213
213
 
214
214
  getAppPath() {
@@ -216,14 +216,14 @@ export function create_builder({
216
216
  },
217
217
 
218
218
  writeClient(dest) {
219
- return copy(`${config.kit.outDir}/output/client`, dest, {
219
+ return copy(`${config.outDir}/output/client`, dest, {
220
220
  // avoid making vite build artefacts public
221
221
  filter: (basename) => basename !== '.vite'
222
222
  });
223
223
  },
224
224
 
225
225
  writePrerendered(dest) {
226
- const source = `${config.kit.outDir}/output/prerendered`;
226
+ const source = `${config.outDir}/output/prerendered`;
227
227
 
228
228
  return [
229
229
  ...copy(`${source}/pages`, dest),
@@ -233,11 +233,11 @@ export function create_builder({
233
233
  },
234
234
 
235
235
  writeServer(dest) {
236
- return copy(`${config.kit.outDir}/output/server`, dest);
236
+ return copy(`${config.outDir}/output/server`, dest);
237
237
  },
238
238
 
239
239
  hasServerInstrumentationFile() {
240
- return existsSync(`${config.kit.outDir}/output/server/instrumentation.server.js`);
240
+ return existsSync(`${config.outDir}/output/server/instrumentation.server.js`);
241
241
  },
242
242
 
243
243
  instrument({
@@ -23,12 +23,26 @@ export async function adapt(
23
23
  vite_config,
24
24
  explicit_env_config
25
25
  ) {
26
- const { name, adapt } = config.kit.adapter;
26
+ const { name, adapt } = config.adapter;
27
27
 
28
28
  console.log(styleText(['bold', 'cyan'], `\n> Using ${name}`));
29
29
 
30
+ let warned = false;
31
+
30
32
  const builder = create_builder({
31
- config,
33
+ config: {
34
+ ...config,
35
+ get kit() {
36
+ if (!warned) {
37
+ warned = true;
38
+ log.warn(
39
+ `Reading \`config.kit\` inside adapters is deprecated — it should access configuration on the \`config\` object directly. You may need to update your adapter`
40
+ );
41
+ }
42
+
43
+ return config;
44
+ }
45
+ },
32
46
  build_data,
33
47
  server_metadata,
34
48
  route_data: build_data.manifest_data.routes.filter((route) => route.page || route.endpoint),
@@ -1,5 +1,4 @@
1
- /** @import { Config, KitConfig } from '@sveltejs/kit' */
2
- /** @import { Options, SvelteConfig } from '@sveltejs/vite-plugin-svelte' */
1
+ /** @import { Config } from '@sveltejs/kit/vite' */
3
2
  /** @import { ValidatedConfig } from 'types' */
4
3
  /** @import { ResolvedConfig } from 'vite' */
5
4
  import fs from 'node:fs';
@@ -7,12 +6,7 @@ import path from 'node:path';
7
6
  import process from 'node:process';
8
7
  import * as url from 'node:url';
9
8
  import { styleText } from 'node:util';
10
- import {
11
- validate_kit_options,
12
- kit_options,
13
- kit_experimental_options,
14
- validate_svelte_options
15
- } from './options.js';
9
+ import { validate_options, kit_options, kit_experimental_options } from './options.js';
16
10
  import { resolve_entry } from '../../utils/filesystem.js';
17
11
  import { import_peer } from '../../utils/import.js';
18
12
  import { stackless } from '../../utils/error.js';
@@ -23,23 +17,21 @@ import { stackless } from '../../utils/error.js';
23
17
  * `vite-plugin-svelte`. SvelteKit makes no assumptions about which options
24
18
  * `vite-plugin-svelte` accepts — it plucks out its own options and passes
25
19
  * everything else along (`vite-plugin-svelte` does its own validation).
26
- * @param {KitConfig & Omit<Options, 'onwarn'> & Pick<SvelteConfig, 'vitePlugin'>} config
20
+ * @param {Config} config
27
21
  * @returns {{ svelte_config: Config, vite_plugin_svelte_config: Record<string, any> }}
28
22
  */
29
23
  export function split_config(config) {
30
- const { extensions, compilerOptions, vitePlugin, preprocess, ...rest } = config;
31
-
32
- /** @type {KitConfig} */
33
- const kit = {};
24
+ /** @type {Config} */
25
+ const svelte_config = {};
34
26
 
35
27
  /** @type {Record<string, any>} */
36
28
  const vite_plugin_svelte_config = {};
37
29
 
38
- for (const key in rest) {
30
+ for (const key in config) {
39
31
  if (key === 'experimental') {
40
32
  // `experimental` is a namespace that both SvelteKit and vite-plugin-svelte
41
33
  // use, so pluck out the flags SvelteKit recognises and pass the rest along
42
- const experimental = /** @type {Record<string, any>} */ (rest[key]) ?? {};
34
+ const experimental = /** @type {Record<string, any>} */ (config[key]) ?? {};
43
35
 
44
36
  /** @type {Record<string, any>} */
45
37
  const kit_experimental = {};
@@ -55,21 +47,21 @@ export function split_config(config) {
55
47
  }
56
48
 
57
49
  if (Object.keys(kit_experimental).length > 0) {
58
- kit.experimental = kit_experimental;
50
+ svelte_config.experimental = kit_experimental;
59
51
  }
60
52
  if (Object.keys(vps_experimental).length > 0) {
61
53
  vite_plugin_svelte_config.experimental = vps_experimental;
62
54
  }
63
55
  } else if (kit_options.includes(key)) {
64
56
  // @ts-expect-error - we've verified this is one of SvelteKit's own options
65
- kit[key] = rest[key];
57
+ svelte_config[key] = config[key];
66
58
  } else {
67
- vite_plugin_svelte_config[key] = /** @type {Record<string, any>} */ (rest)[key];
59
+ vite_plugin_svelte_config[key] = /** @type {Record<string, any>} */ (config)[key];
68
60
  }
69
61
  }
70
62
 
71
63
  return {
72
- svelte_config: { extensions, compilerOptions, vitePlugin, preprocess, kit },
64
+ svelte_config,
73
65
  vite_plugin_svelte_config
74
66
  };
75
67
  }
@@ -80,8 +72,8 @@ export function split_config(config) {
80
72
  * @param {string} cwd
81
73
  * @param {ValidatedConfig} config
82
74
  */
83
- export function load_template(cwd, { kit }) {
84
- const { files } = kit;
75
+ export function load_template(cwd, config) {
76
+ const { files } = config;
85
77
 
86
78
  const relative = path.relative(cwd, files.appTemplate);
87
79
 
@@ -107,11 +99,11 @@ export function load_template(cwd, { kit }) {
107
99
  * @param {ValidatedConfig} config
108
100
  */
109
101
  export function load_error_page(config) {
110
- let { errorTemplate } = config.kit.files;
102
+ let { errorTemplate } = config.files;
111
103
 
112
104
  // Don't do this inside resolving the config, because that would mean
113
105
  // adding/removing error.html isn't detected and would require a restart.
114
- if (!fs.existsSync(config.kit.files.errorTemplate)) {
106
+ if (!fs.existsSync(config.files.errorTemplate)) {
115
107
  errorTemplate = url.fileURLToPath(new URL('./default-error.html', import.meta.url));
116
108
  }
117
109
 
@@ -144,27 +136,27 @@ export function extract_svelte_config(vite_config) {
144
136
  */
145
137
  export function process_config(config, cwd) {
146
138
  if (
147
- config.kit.csp?.directives?.['require-trusted-types-for']?.includes('script') &&
148
- config.kit.serviceWorker.register &&
149
- resolve_entry(path.resolve(cwd, config.kit.files.serviceWorker)) &&
150
- !config.kit.csp?.directives?.['trusted-types']?.includes('sveltekit-trusted-url')
139
+ config.csp?.directives?.['require-trusted-types-for']?.includes('script') &&
140
+ config.serviceWorker.register &&
141
+ resolve_entry(path.resolve(cwd, config.files.serviceWorker)) &&
142
+ !config.csp?.directives?.['trusted-types']?.includes('sveltekit-trusted-url')
151
143
  ) {
152
144
  throw new Error(
153
145
  "The `csp.directives['trusted-types']` option must include 'sveltekit-trusted-url' when `serviceWorker.register` is true"
154
146
  );
155
147
  }
156
148
 
157
- config.kit.outDir = path.resolve(cwd, config.kit.outDir);
158
- config.kit.env.dir = path.resolve(cwd, config.kit.env.dir);
149
+ config.outDir = path.resolve(cwd, config.outDir);
150
+ config.env.dir = path.resolve(cwd, config.env.dir);
159
151
 
160
- for (const key in config.kit.files) {
152
+ for (const key in config.files) {
161
153
  if (key === 'hooks') {
162
- config.kit.files.hooks.client = path.resolve(cwd, config.kit.files.hooks.client);
163
- config.kit.files.hooks.server = path.resolve(cwd, config.kit.files.hooks.server);
164
- config.kit.files.hooks.universal = path.resolve(cwd, config.kit.files.hooks.universal);
154
+ config.files.hooks.client = path.resolve(cwd, config.files.hooks.client);
155
+ config.files.hooks.server = path.resolve(cwd, config.files.hooks.server);
156
+ config.files.hooks.universal = path.resolve(cwd, config.files.hooks.universal);
165
157
  } else if (key !== 'lib' /* TODO remove when we remove the `lib` option altogether */) {
166
158
  // @ts-expect-error
167
- config.kit.files[key] = path.resolve(cwd, config.kit.files[key]);
159
+ config.files[key] = path.resolve(cwd, config.files[key]);
168
160
  }
169
161
  }
170
162
 
@@ -183,11 +175,8 @@ export function validate_config(config) {
183
175
  );
184
176
  }
185
177
 
186
- const validated = /** @type {ValidatedConfig} */ ({
187
- ...validate_svelte_options(config, 'config'),
188
- kit: validate_kit_options(config.kit, 'config')
189
- });
190
- const files = validated.kit.files;
178
+ const validated = validate_options(config, 'config');
179
+ const files = validated.files;
191
180
 
192
181
  files.hooks.client ??= path.join(files.src, 'hooks.client');
193
182
  files.hooks.server ??= path.join(files.src, 'hooks.server');
@@ -198,13 +187,13 @@ export function validate_config(config) {
198
187
  files.appTemplate ??= path.join(files.src, 'app.html');
199
188
  files.errorTemplate ??= path.join(files.src, 'error.html');
200
189
 
201
- if (validated.kit.router.resolution === 'server') {
202
- if (validated.kit.router.type === 'hash') {
190
+ if (validated.router.resolution === 'server') {
191
+ if (validated.router.type === 'hash') {
203
192
  throw new Error(
204
193
  "The `router.resolution` option cannot be 'server' if `router.type` is 'hash'"
205
194
  );
206
195
  }
207
- if (validated.kit.output.bundleStrategy !== 'split') {
196
+ if (validated.output.bundleStrategy !== 'split') {
208
197
  throw new Error(
209
198
  "The `router.resolution` option cannot be 'server' if `output.bundleStrategy` is 'inline' or 'single'"
210
199
  );
@@ -212,8 +201,8 @@ export function validate_config(config) {
212
201
  }
213
202
 
214
203
  if (
215
- validated.kit.csp?.directives?.['require-trusted-types-for']?.includes('script') &&
216
- !validated.kit.csp?.directives?.['trusted-types']?.includes('svelte-trusted-html')
204
+ validated.csp?.directives?.['require-trusted-types-for']?.includes('script') &&
205
+ !validated.csp?.directives?.['trusted-types']?.includes('svelte-trusted-html')
217
206
  ) {
218
207
  throw new Error(
219
208
  "The `csp.directives['trusted-types']` option must include 'svelte-trusted-html'"
@@ -1,5 +1,4 @@
1
- /** @import { SvelteConfig } from '@sveltejs/vite-plugin-svelte' */
2
- /** @import { ValidatedKitConfig } from 'types' */
1
+ /** @import { ValidatedConfig } from 'types' */
3
2
  /** @import { Validator } from './types.js' */
4
3
  import { styleText } from 'node:util';
5
4
 
@@ -37,38 +36,13 @@ const directives = object({
37
36
  referrer: string_array()
38
37
  });
39
38
 
40
- /** @type {Validator<{ extensions: string[] } & SvelteConfig>} */
41
- export const validate_svelte_options = object(
42
- {
43
- extensions: validate(['.svelte'], (input, keypath) => {
44
- if (!Array.isArray(input) || !input.every((page) => typeof page === 'string')) {
45
- throw new Error(`${keypath} must be an array of strings`);
46
- }
47
-
48
- input.forEach((extension) => {
49
- if (extension[0] !== '.') {
50
- throw new Error(`Each member of ${keypath} must start with '.' — saw '${extension}'`);
51
- }
52
-
53
- if (!/^(\.[a-z0-9]+)+$/i.test(extension)) {
54
- throw new Error(`File extensions must be alphanumeric — saw '${extension}'`);
55
- }
56
- });
57
-
58
- return input;
59
- })
60
- },
61
- true
62
- );
63
-
64
39
  const prerender_handler = validate(undefined, (input, keypath) => {
65
40
  if (typeof input === 'function') return input;
66
41
  if (['fail', 'warn', 'ignore'].includes(input)) return input;
67
42
  throw new Error(`${keypath} should be "fail", "warn", "ignore" or a custom function`);
68
43
  });
69
44
 
70
- /** @type {Validator<ValidatedKitConfig>} */
71
- export const validate_kit_options = object({
45
+ const options = {
72
46
  adapter: validate(undefined, (input, keypath) => {
73
47
  if (typeof input !== 'object' || !input.adapt) {
74
48
  const message = `The SvelteKit Vite plugin ${keypath} should be an object with an \`adapt\` method`;
@@ -110,6 +84,8 @@ export const validate_kit_options = object({
110
84
  return input;
111
85
  }),
112
86
 
87
+ compilerOptions: any(),
88
+
113
89
  csp: object({
114
90
  mode: list(['auto', 'hash', 'nonce']),
115
91
  directives,
@@ -129,18 +105,39 @@ export const validate_kit_options = object({
129
105
  dir: string('')
130
106
  }),
131
107
 
132
- experimental: object({
133
- tracing: removed(
134
- (keypath) =>
135
- `\`${keypath}\` has been removed. Server-side tracing is now configured via \`tracing.server\``
136
- ),
137
- instrumentation: removed(
138
- (keypath) =>
139
- `\`${keypath}\` has been removed. \`src/instrumentation.server.js\` is now included in the build automatically when it exists; no opt-in is required`
140
- ),
141
- remoteFunctions: boolean(false),
142
- forkPreloads: boolean(false),
143
- handleRenderingErrors: removed()
108
+ experimental: object(
109
+ {
110
+ tracing: removed(
111
+ (keypath) =>
112
+ `\`${keypath}\` has been removed. Server-side tracing is now configured via \`tracing.server\``
113
+ ),
114
+ instrumentation: removed(
115
+ (keypath) =>
116
+ `\`${keypath}\` has been removed. \`src/instrumentation.server.js\` is now included in the build automatically when it exists; no opt-in is required`
117
+ ),
118
+ remoteFunctions: boolean(false),
119
+ forkPreloads: boolean(false),
120
+ handleRenderingErrors: removed()
121
+ },
122
+ true
123
+ ),
124
+
125
+ extensions: validate(['.svelte'], (input, keypath) => {
126
+ if (!Array.isArray(input) || !input.every((page) => typeof page === 'string')) {
127
+ throw new Error(`${keypath} must be an array of strings`);
128
+ }
129
+
130
+ input.forEach((extension) => {
131
+ if (extension[0] !== '.') {
132
+ throw new Error(`Each member of ${keypath} must start with '.' — saw '${extension}'`);
133
+ }
134
+
135
+ if (!/^(\.[a-z0-9]+)+$/i.test(extension)) {
136
+ throw new Error(`File extensions must be alphanumeric — saw '${extension}'`);
137
+ }
138
+ });
139
+
140
+ return input;
144
141
  }),
145
142
 
146
143
  files: object({
@@ -166,6 +163,16 @@ export const validate_kit_options = object({
166
163
 
167
164
  moduleExtensions: string_array(['.js', '.ts']),
168
165
 
166
+ kit: validate(undefined, (input) => {
167
+ const keys = Object.keys(input)
168
+ .map((key) => `\`${key}\``)
169
+ .join(', ');
170
+
171
+ throw new Error(
172
+ `SvelteKit configuration (${keys}) no longer lives inside a \`kit\` namespace. Pass it directly to the \`sveltekit(...)\` Vite plugin`
173
+ );
174
+ }),
175
+
169
176
  outDir: string('.svelte-kit'),
170
177
 
171
178
  output: object({
@@ -239,6 +246,8 @@ export const validate_kit_options = object({
239
246
  relative: boolean(true)
240
247
  }),
241
248
 
249
+ preprocess: any(),
250
+
242
251
  prerender: object({
243
252
  concurrency: number(1),
244
253
  crawl: boolean(true),
@@ -298,8 +307,16 @@ export const validate_kit_options = object({
298
307
  version: object({
299
308
  name: string(Date.now().toString()),
300
309
  pollInterval: number(3_600_000)
301
- })
302
- });
310
+ }),
311
+
312
+ vitePlugin: removed(
313
+ (keypath) =>
314
+ `\`${keypath}\` has been removed. Pass \`vite-plugin-svelte\` options directly to the \`sveltekit(...)\` Vite plugin`
315
+ )
316
+ };
317
+
318
+ /** @type {Validator<ValidatedConfig>} */
319
+ export const validate_options = object(options, true);
303
320
 
304
321
  /**
305
322
  * @param {Validator} fn
@@ -323,7 +340,7 @@ function deprecate(
323
340
  // Derive the names of SvelteKit's own config options from the schema, so they
324
341
  // stay in sync automatically. These are used to separate Kit's options from
325
342
  // `vite-plugin-svelte`'s options when config is passed via the Vite plugin.
326
- const kit_defaults = validate_kit_options({}, 'config');
343
+ const kit_defaults = validate_options({}, 'config');
327
344
 
328
345
  /** The names of the options that live under the `kit` namespace */
329
346
  export const kit_options = Object.keys(kit_defaults);
@@ -363,7 +380,8 @@ export function object(children, allow_unknown = false) {
363
380
  for (const key in input) {
364
381
  if (!(key in children)) {
365
382
  if (allow_unknown) {
366
- output[key] = input[key];
383
+ const value = input[key];
384
+ if (value !== undefined) output[key] = value;
367
385
  } else {
368
386
  let message = `Unexpected option ${keypath}.${key}`;
369
387
 
@@ -485,6 +503,10 @@ function fun(fallback) {
485
503
  });
486
504
  }
487
505
 
506
+ function any() {
507
+ return validate(undefined, (input) => input);
508
+ }
509
+
488
510
  /**
489
511
  * @param {string} input
490
512
  * @param {string} keypath
package/src/core/env.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /** @import { StandardSchemaV1 } from '@standard-schema/spec' */
2
2
  /** @import { EnvVarConfig } from '@sveltejs/kit/env' */
3
- /** @import { ValidatedKitConfig } from 'types' */
3
+ /** @import { ValidatedConfig } from 'types' */
4
4
  import path from 'node:path';
5
5
  import * as devalue from 'devalue';
6
6
  import { GENERATED_COMMENT } from '../constants.js';
@@ -16,7 +16,7 @@ import { get_runner } from '../runner.js';
16
16
  */
17
17
 
18
18
  /**
19
- * @param {import('types').ValidatedKitConfig} config
19
+ * @param {ValidatedConfig} config
20
20
  * @returns {string | null}
21
21
  */
22
22
  export function resolve_explicit_env_entry(config) {
@@ -25,7 +25,7 @@ export function resolve_explicit_env_entry(config) {
25
25
 
26
26
  /**
27
27
  * @param {typeof import('vite')} vite
28
- * @param {ValidatedKitConfig} kit
28
+ * @param {ValidatedConfig} kit
29
29
  * @param {string | null} file
30
30
  * @param {string} root
31
31
  * @param {string} mode
@@ -38,7 +38,7 @@ async function analyse({
38
38
  const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
39
39
 
40
40
  const vite_config = await load_vite_config(vite_config_file);
41
- const config = extract_svelte_config(vite_config).kit;
41
+ const config = extract_svelte_config(vite_config);
42
42
  const server_root = join(config.outDir, 'output');
43
43
 
44
44
  /** @type {import('types').ServerInternalModule} */
@@ -153,7 +153,7 @@ async function prerender({
153
153
 
154
154
  const vite_config = await load_vite_config(vite_config_file);
155
155
 
156
- const config = extract_svelte_config(vite_config).kit;
156
+ const config = extract_svelte_config(vite_config);
157
157
 
158
158
  const prerender_origin = config.paths.origin || 'http://sveltekit-prerender';
159
159
 
@@ -275,8 +275,8 @@ async function prerender({
275
275
  /** @type {Map<string, Promise<any>>} */
276
276
  const remote_responses = new Map();
277
277
 
278
- /** @type {(path: string) => void} */
279
- let progress_line = noop;
278
+ /** @type {null | { clear: () => void; update: (path: string) => void; updated: number }} */
279
+ let progress = null;
280
280
 
281
281
  if (is_tty) {
282
282
  // Where possible, provide progress feedback by showing the path we're
@@ -284,34 +284,51 @@ async function prerender({
284
284
  // This avoids the wall of text that happens when you prerender
285
285
  // many pages and log each response
286
286
  let current = false;
287
+ let mid_line = false;
287
288
  const stdout_write = process.stdout.write;
288
289
  const stderr_write = process.stderr.write;
289
290
 
290
- process.stdout.write = new Proxy(stdout_write, {
291
+ /** @type {ProxyHandler<typeof stdout_write>} */
292
+ const track_output = {
291
293
  apply(target, this_arg, args) {
292
- current = false;
294
+ const chunk = args[0];
295
+ if (chunk.length > 0) {
296
+ current = false;
297
+ mid_line =
298
+ typeof chunk === 'string' ? !chunk.endsWith('\n') : chunk[chunk.length - 1] !== 10;
299
+ }
293
300
  return Reflect.apply(target, this_arg, args);
294
301
  }
295
- });
302
+ };
296
303
 
297
- process.stderr.write = new Proxy(stderr_write, {
298
- apply(target, this_arg, args) {
299
- current = false;
300
- return Reflect.apply(target, this_arg, args);
301
- }
302
- });
304
+ process.stdout.write = new Proxy(stdout_write, track_output);
305
+ process.stderr.write = new Proxy(stderr_write, track_output);
306
+
307
+ progress = {
308
+ clear: () => {
309
+ // If app code writes to stdout or stderr, don't move the cursor to clear
310
+ // the previous progress log, because that will corrupt things
311
+ if (!current) return;
303
312
 
304
- progress_line = (path) => {
305
- // If app code writes to stdout or stderr, don't move the cursor to clear
306
- // the previous progress log, because that will corrupt things
307
- if (current) {
308
313
  moveCursor(process.stdout, 0, -1);
309
314
  clearLine(process.stdout, 0);
310
- }
315
+ },
311
316
 
312
- stdout_write.call(process.stdout, `rendering ${path}...\n`);
313
- current = true;
317
+ update: (path) => {
318
+ if (mid_line) {
319
+ // app output ended mid-line — start a fresh one rather than appending to it
320
+ stdout_write.call(process.stdout, '\n');
321
+ }
322
+
323
+ stdout_write.call(process.stdout, `crawling ${path}\n`);
324
+ current = true;
325
+ mid_line = false;
326
+ },
327
+
328
+ updated: 0
314
329
  };
330
+
331
+ console.log('');
315
332
  }
316
333
 
317
334
  /** @type {Set<string>} */
@@ -354,7 +371,17 @@ async function prerender({
354
371
  /** @type {Map<string, import('types').PrerenderDependency>} */
355
372
  const dependencies = new Map();
356
373
 
357
- progress_line(decoded);
374
+ if (progress) {
375
+ progress.clear();
376
+ progress.update(decoded);
377
+
378
+ if (Date.now() - progress.updated > 50) {
379
+ progress.updated = Date.now();
380
+
381
+ // without this, the update will rarely be visible, and progress will appear stuck
382
+ await new Promise((f) => setTimeout(f, 0));
383
+ }
384
+ }
358
385
 
359
386
  const request = new Request(prerender_origin + encoded);
360
387
 
@@ -693,6 +720,7 @@ async function prerender({
693
720
  }
694
721
 
695
722
  await q.done();
723
+ progress?.clear();
696
724
 
697
725
  // handle invalid fragment links
698
726
  for (const [key, referrers] of expected_hashlinks) {