@sveltejs/kit 1.0.0-next.501 → 1.0.0-next.503
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.
- package/package.json +1 -1
- package/postinstall.js +32 -23
- package/src/core/prerender/prerender.js +23 -0
- package/src/core/sync/write_types/index.js +87 -59
- package/src/exports/vite/preview/index.js +1 -1
- package/src/runtime/app/forms.js +2 -1
- package/src/runtime/client/client.js +10 -8
- package/src/runtime/server/endpoint.js +4 -2
- package/src/runtime/server/index.js +5 -0
- package/src/runtime/server/page/render.js +2 -1
- package/types/index.d.ts +1 -0
package/package.json
CHANGED
package/postinstall.js
CHANGED
|
@@ -4,35 +4,44 @@ import glob from 'tiny-glob/sync.js';
|
|
|
4
4
|
import { load_config } from './src/core/config/index.js';
|
|
5
5
|
import * as sync from './src/core/sync/sync.js';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
process.
|
|
7
|
+
try {
|
|
8
|
+
const cwd = process.env.INIT_CWD ?? process.cwd();
|
|
9
|
+
process.chdir(cwd);
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
if (fs.existsSync('package.json')) {
|
|
12
|
+
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
11
13
|
|
|
12
|
-
const directories = [];
|
|
14
|
+
const directories = [];
|
|
13
15
|
|
|
14
|
-
if (pkg.workspaces) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
} else {
|
|
19
|
-
directories.push(cwd);
|
|
20
|
-
}
|
|
16
|
+
if (pkg.workspaces) {
|
|
17
|
+
// we have to do this because of https://classic.yarnpkg.com/blog/2018/02/15/nohoist/
|
|
18
|
+
const packages = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces.packages;
|
|
21
19
|
|
|
22
|
-
for (const
|
|
23
|
-
|
|
20
|
+
for (const directory of packages) {
|
|
21
|
+
directories.push(...glob(directory, { cwd }).map((dir) => path.resolve(cwd, dir)));
|
|
22
|
+
}
|
|
23
|
+
} else {
|
|
24
|
+
directories.push(cwd);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
for (const cwd of directories) {
|
|
28
|
+
process.chdir(cwd);
|
|
24
29
|
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
if (!fs.existsSync('package.json')) continue;
|
|
31
|
+
if (!fs.existsSync('svelte.config.js')) continue;
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
34
|
+
if (!pkg.dependencies?.['@sveltejs/kit'] && !pkg.devDependencies?.['@sveltejs/kit']) continue;
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
try {
|
|
37
|
+
const config = await load_config();
|
|
38
|
+
await sync.all(config, 'development');
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.log('Error while trying to sync SvelteKit config');
|
|
41
|
+
console.log(error.stack);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
37
44
|
}
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error(error.stack);
|
|
38
47
|
}
|
|
@@ -85,6 +85,9 @@ export async function prerender() {
|
|
|
85
85
|
/** @type {import('types').PrerenderMap} */
|
|
86
86
|
const prerender_map = new Map();
|
|
87
87
|
|
|
88
|
+
/** @type {Set<string>} */
|
|
89
|
+
const prerendered_routes = new Set();
|
|
90
|
+
|
|
88
91
|
/** @type {import('types').ValidatedKitConfig} */
|
|
89
92
|
const config = (await load_config()).kit;
|
|
90
93
|
|
|
@@ -302,6 +305,9 @@ export async function prerender() {
|
|
|
302
305
|
|
|
303
306
|
if (written.has(file)) return;
|
|
304
307
|
|
|
308
|
+
const route_id = response.headers.get('x-sveltekit-routeid');
|
|
309
|
+
if (route_id !== null) prerendered_routes.add(route_id);
|
|
310
|
+
|
|
305
311
|
if (response_type === REDIRECT) {
|
|
306
312
|
const location = headers['location'];
|
|
307
313
|
|
|
@@ -410,6 +416,23 @@ export async function prerender() {
|
|
|
410
416
|
|
|
411
417
|
await q.done();
|
|
412
418
|
|
|
419
|
+
/** @type {string[]} */
|
|
420
|
+
const not_prerendered = [];
|
|
421
|
+
|
|
422
|
+
for (const [route_id, prerender] of prerender_map) {
|
|
423
|
+
if (prerender === true && !prerendered_routes.has(route_id)) {
|
|
424
|
+
not_prerendered.push(route_id);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (not_prerendered.length > 0) {
|
|
429
|
+
throw new Error(
|
|
430
|
+
`The following routes were marked as prerenderable, but were not prerendered:\n${not_prerendered.map(
|
|
431
|
+
(id) => ` - ${id}`
|
|
432
|
+
)}\n\nSee https://kit.svelte.dev/docs/page-options#prerender-troubleshooting for more info`
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
|
|
413
436
|
const rendered = await server.respond(new Request(config.prerender.origin + '/[fallback]'), {
|
|
414
437
|
getClientAddress,
|
|
415
438
|
prerendering: {
|
|
@@ -46,11 +46,82 @@ export async function write_all_types(config, manifest_data) {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// Read/write meta data on each invocation, not once per node process,
|
|
50
|
+
// it could be invoked by another process in the meantime.
|
|
51
|
+
const meta_data_file = `${types_dir}/route_meta_data.json`;
|
|
52
|
+
const has_meta_data = fs.existsSync(meta_data_file);
|
|
53
|
+
let meta_data = has_meta_data
|
|
54
|
+
? /** @type {Record<string, string[]>} */ (JSON.parse(fs.readFileSync(meta_data_file, 'utf-8')))
|
|
55
|
+
: {};
|
|
49
56
|
const routes_map = create_routes_map(manifest_data);
|
|
50
57
|
// For each directory, write $types.d.ts
|
|
51
58
|
for (const route of manifest_data.routes) {
|
|
52
|
-
|
|
59
|
+
if (!route.leaf && !route.layout && !route.endpoint) continue; // nothing to do
|
|
60
|
+
|
|
61
|
+
const outdir = path.join(config.kit.outDir, 'types', routes_dir, route.id);
|
|
62
|
+
|
|
63
|
+
// check if the types are out of date
|
|
64
|
+
/** @type {string[]} */
|
|
65
|
+
const input_files = [];
|
|
66
|
+
|
|
67
|
+
/** @type {import('types').PageNode | null} */
|
|
68
|
+
let node = route.leaf;
|
|
69
|
+
while (node) {
|
|
70
|
+
if (node.shared) input_files.push(node.shared);
|
|
71
|
+
if (node.server) input_files.push(node.server);
|
|
72
|
+
node = node.parent ?? null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** @type {import('types').PageNode | null} */
|
|
76
|
+
node = route.layout;
|
|
77
|
+
while (node) {
|
|
78
|
+
if (node.shared) input_files.push(node.shared);
|
|
79
|
+
if (node.server) input_files.push(node.server);
|
|
80
|
+
node = node.parent ?? null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (route.endpoint) {
|
|
84
|
+
input_files.push(route.endpoint.file);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
fs.mkdirSync(outdir, { recursive: true });
|
|
89
|
+
} catch {}
|
|
90
|
+
|
|
91
|
+
const output_files = compact(
|
|
92
|
+
fs.readdirSync(outdir).map((name) => {
|
|
93
|
+
const stats = fs.statSync(path.join(outdir, name));
|
|
94
|
+
if (stats.isDirectory()) return;
|
|
95
|
+
return {
|
|
96
|
+
name,
|
|
97
|
+
updated: stats.mtimeMs
|
|
98
|
+
};
|
|
99
|
+
})
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const source_last_updated = Math.max(
|
|
103
|
+
// ctimeMs includes move operations whereas mtimeMs does not
|
|
104
|
+
...input_files.map((file) => fs.statSync(file).ctimeMs)
|
|
105
|
+
);
|
|
106
|
+
const types_last_updated = Math.max(...output_files.map((file) => file.updated));
|
|
107
|
+
|
|
108
|
+
const should_generate =
|
|
109
|
+
// source files were generated more recently than the types
|
|
110
|
+
source_last_updated > types_last_updated ||
|
|
111
|
+
// no meta data file exists yet
|
|
112
|
+
!has_meta_data ||
|
|
113
|
+
// some file was deleted
|
|
114
|
+
!meta_data[route.id]?.every((file) => input_files.includes(file));
|
|
115
|
+
|
|
116
|
+
if (should_generate) {
|
|
117
|
+
// track which old files end up being surplus to requirements
|
|
118
|
+
const to_delete = new Set(output_files.map((file) => file.name));
|
|
119
|
+
update_types(config, routes_map, route, to_delete);
|
|
120
|
+
meta_data[route.id] = input_files;
|
|
121
|
+
}
|
|
53
122
|
}
|
|
123
|
+
|
|
124
|
+
fs.writeFileSync(meta_data_file, JSON.stringify(meta_data, null, '\t'));
|
|
54
125
|
}
|
|
55
126
|
|
|
56
127
|
/**
|
|
@@ -72,6 +143,7 @@ export async function write_types(config, manifest_data, file) {
|
|
|
72
143
|
|
|
73
144
|
const route = manifest_data.routes.find((route) => route.id === id);
|
|
74
145
|
if (!route) return; // this shouldn't ever happen
|
|
146
|
+
if (!route.leaf && !route.layout && !route.endpoint) return; // nothing to do
|
|
75
147
|
|
|
76
148
|
update_types(config, create_routes_map(manifest_data), route);
|
|
77
149
|
}
|
|
@@ -96,60 +168,12 @@ function create_routes_map(manifest_data) {
|
|
|
96
168
|
* @param {import('types').ValidatedConfig} config
|
|
97
169
|
* @param {Map<import('types').PageNode, import('types').RouteData>} routes
|
|
98
170
|
* @param {import('types').RouteData} route
|
|
171
|
+
* @param {Set<string>} [to_delete]
|
|
99
172
|
*/
|
|
100
|
-
function update_types(config, routes, route) {
|
|
101
|
-
if (!route.leaf && !route.layout && !route.endpoint) return; // nothing to do
|
|
102
|
-
|
|
173
|
+
function update_types(config, routes, route, to_delete = new Set()) {
|
|
103
174
|
const routes_dir = posixify(path.relative('.', config.kit.files.routes));
|
|
104
175
|
const outdir = path.join(config.kit.outDir, 'types', routes_dir, route.id);
|
|
105
176
|
|
|
106
|
-
// first, check if the types are out of date
|
|
107
|
-
const input_files = [];
|
|
108
|
-
|
|
109
|
-
/** @type {import('types').PageNode | null} */
|
|
110
|
-
let node = route.leaf;
|
|
111
|
-
while (node) {
|
|
112
|
-
if (node.shared) input_files.push(node.shared);
|
|
113
|
-
if (node.server) input_files.push(node.server);
|
|
114
|
-
node = node.parent ?? null;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/** @type {import('types').PageNode | null} */
|
|
118
|
-
node = route.layout;
|
|
119
|
-
while (node) {
|
|
120
|
-
if (node.shared) input_files.push(node.shared);
|
|
121
|
-
if (node.server) input_files.push(node.server);
|
|
122
|
-
node = node.parent ?? null;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (route.endpoint) {
|
|
126
|
-
input_files.push(route.endpoint.file);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
try {
|
|
130
|
-
fs.mkdirSync(outdir, { recursive: true });
|
|
131
|
-
} catch {}
|
|
132
|
-
|
|
133
|
-
const output_files = compact(
|
|
134
|
-
fs.readdirSync(outdir).map((name) => {
|
|
135
|
-
const stats = fs.statSync(path.join(outdir, name));
|
|
136
|
-
if (stats.isDirectory()) return;
|
|
137
|
-
return {
|
|
138
|
-
name,
|
|
139
|
-
updated: stats.mtimeMs
|
|
140
|
-
};
|
|
141
|
-
})
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
const source_last_updated = Math.max(...input_files.map((file) => fs.statSync(file).mtimeMs));
|
|
145
|
-
const types_last_updated = Math.max(...output_files.map((file) => file?.updated));
|
|
146
|
-
|
|
147
|
-
// types were generated more recently than the source files, so don't regenerate
|
|
148
|
-
if (types_last_updated > source_last_updated) return;
|
|
149
|
-
|
|
150
|
-
// track which old files end up being surplus to requirements
|
|
151
|
-
const to_delete = new Set(output_files.map((file) => file.name));
|
|
152
|
-
|
|
153
177
|
// now generate new types
|
|
154
178
|
const imports = [`import type * as Kit from '@sveltejs/kit';`];
|
|
155
179
|
|
|
@@ -180,7 +204,7 @@ function update_types(config, routes, route) {
|
|
|
180
204
|
`type OutputDataShape<T> = MaybeWithVoid<Omit<App.PageData, RequiredKeys<T>> & Partial<Pick<App.PageData, keyof T & keyof App.PageData>> & Record<string, any>>`
|
|
181
205
|
);
|
|
182
206
|
// null & {} == null, we need to prevent that in some situations
|
|
183
|
-
declarations.push(`type
|
|
207
|
+
declarations.push(`type EnsureDefined<T> = T extends null | undefined ? {} : T;`);
|
|
184
208
|
}
|
|
185
209
|
|
|
186
210
|
if (route.leaf) {
|
|
@@ -308,7 +332,7 @@ function process_node(node, outdir, is_page, all_pages_have_load = true) {
|
|
|
308
332
|
? `./proxy${replace_ext_with_js(basename)}`
|
|
309
333
|
: path_to_original(outdir, node.server);
|
|
310
334
|
|
|
311
|
-
type = `Expand<Kit.AwaitedActions<typeof import('${from}').actions
|
|
335
|
+
type = `Expand<Kit.AwaitedActions<typeof import('${from}').actions>> | undefined`;
|
|
312
336
|
}
|
|
313
337
|
}
|
|
314
338
|
exports.push(`export type ActionData = ${type};`);
|
|
@@ -329,9 +353,13 @@ function process_node(node, outdir, is_page, all_pages_have_load = true) {
|
|
|
329
353
|
written_proxies.push(`proxy${path.basename(node.shared)}`);
|
|
330
354
|
}
|
|
331
355
|
|
|
332
|
-
const type = get_data_type(
|
|
356
|
+
const type = get_data_type(
|
|
357
|
+
node.shared,
|
|
358
|
+
`${parent_type} & EnsureDefined<${prefix}ServerData>`,
|
|
359
|
+
proxy
|
|
360
|
+
);
|
|
333
361
|
|
|
334
|
-
data = `Expand<Omit<${parent_type}, keyof ${type}> &
|
|
362
|
+
data = `Expand<Omit<${parent_type}, keyof ${type}> & EnsureDefined<${type}>>`;
|
|
335
363
|
|
|
336
364
|
const output_data_shape =
|
|
337
365
|
!is_page && all_pages_have_load
|
|
@@ -345,7 +373,7 @@ function process_node(node, outdir, is_page, all_pages_have_load = true) {
|
|
|
345
373
|
} else if (server_data === 'null') {
|
|
346
374
|
data = `Expand<${parent_type}>`;
|
|
347
375
|
} else {
|
|
348
|
-
data = `Expand<Omit<${parent_type}, keyof ${prefix}ServerData> &
|
|
376
|
+
data = `Expand<Omit<${parent_type}, keyof ${prefix}ServerData> & EnsureDefined<${prefix}ServerData>>`;
|
|
349
377
|
}
|
|
350
378
|
|
|
351
379
|
exports.push(`export type ${prefix}Data = ${data};`);
|
|
@@ -396,14 +424,14 @@ function get_parent_type(node, type) {
|
|
|
396
424
|
parent = parent.parent;
|
|
397
425
|
}
|
|
398
426
|
|
|
399
|
-
let parent_str = `
|
|
427
|
+
let parent_str = `EnsureDefined<${parent_imports[0] || '{}'}>`;
|
|
400
428
|
for (let i = 1; i < parent_imports.length; i++) {
|
|
401
429
|
// Omit is necessary because a parent could have a property with the same key which would
|
|
402
430
|
// cause a type conflict. At runtime the child overwrites the parent property in this case,
|
|
403
431
|
// so reflect that in the type definition.
|
|
404
|
-
//
|
|
432
|
+
// EnsureDefined is necessary because {something: string} & null becomes null.
|
|
405
433
|
// Output types of server loads can be null but when passed in through the `parent` parameter they are the empty object instead.
|
|
406
|
-
parent_str = `Omit<${parent_str}, keyof ${parent_imports[i]}> &
|
|
434
|
+
parent_str = `Omit<${parent_str}, keyof ${parent_imports[i]}> & EnsureDefined<${parent_imports[i]}>`;
|
|
407
435
|
}
|
|
408
436
|
return parent_str;
|
|
409
437
|
}
|
|
@@ -46,7 +46,7 @@ export async function preview(vite, vite_config, svelte_config) {
|
|
|
46
46
|
|
|
47
47
|
const server = new Server(manifest);
|
|
48
48
|
await server.init({
|
|
49
|
-
env: loadEnv(vite_config.mode,
|
|
49
|
+
env: loadEnv(vite_config.mode, svelte_config.kit.env.dir, '')
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
return () => {
|
package/src/runtime/app/forms.js
CHANGED
|
@@ -73,7 +73,8 @@ export function enhance(form, submit = () => {}) {
|
|
|
73
73
|
const response = await fetch(action, {
|
|
74
74
|
method: 'POST',
|
|
75
75
|
headers: {
|
|
76
|
-
accept: 'application/json'
|
|
76
|
+
accept: 'application/json',
|
|
77
|
+
'x-sveltekit-action': 'true'
|
|
77
78
|
},
|
|
78
79
|
body: data,
|
|
79
80
|
signal: controller.signal
|
|
@@ -438,7 +438,11 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
438
438
|
}
|
|
439
439
|
|
|
440
440
|
const page_changed =
|
|
441
|
-
!current.url ||
|
|
441
|
+
!current.url ||
|
|
442
|
+
url.href !== current.url.href ||
|
|
443
|
+
current.error !== error ||
|
|
444
|
+
form !== undefined ||
|
|
445
|
+
data_changed;
|
|
442
446
|
|
|
443
447
|
if (page_changed) {
|
|
444
448
|
result.props.page = {
|
|
@@ -447,6 +451,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
447
451
|
routeId: route && route.id,
|
|
448
452
|
status,
|
|
449
453
|
url,
|
|
454
|
+
form,
|
|
450
455
|
// The whole page store is updated, but this way the object reference stays the same
|
|
451
456
|
data: data_changed ? data : page.data
|
|
452
457
|
};
|
|
@@ -1203,13 +1208,10 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1203
1208
|
goto(result.location, {}, []);
|
|
1204
1209
|
} else {
|
|
1205
1210
|
/** @type {Record<string, any>} */
|
|
1206
|
-
const props = {
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
props.page = page;
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1211
|
+
const props = {
|
|
1212
|
+
form: result.data,
|
|
1213
|
+
page: { ...page, form: result.data, status: result.status }
|
|
1214
|
+
};
|
|
1213
1215
|
const post_update = pre_update();
|
|
1214
1216
|
root.$set(props);
|
|
1215
1217
|
post_update();
|
|
@@ -54,7 +54,6 @@ export async function render_endpoint(event, mod, state) {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
if (state.prerendering) {
|
|
57
|
-
response.headers.set('x-sveltekit-routeid', /** @type {string} */ (event.routeId));
|
|
58
57
|
response.headers.set('x-sveltekit-prerender', String(prerender));
|
|
59
58
|
}
|
|
60
59
|
|
|
@@ -77,13 +76,16 @@ export async function render_endpoint(event, mod, state) {
|
|
|
77
76
|
* @param {import('types').RequestEvent} event
|
|
78
77
|
*/
|
|
79
78
|
export function is_endpoint_request(event) {
|
|
80
|
-
const { method } = event.request;
|
|
79
|
+
const { method, headers } = event.request;
|
|
81
80
|
|
|
82
81
|
if (method === 'PUT' || method === 'PATCH' || method === 'DELETE') {
|
|
83
82
|
// These methods exist exclusively for endpoints
|
|
84
83
|
return true;
|
|
85
84
|
}
|
|
86
85
|
|
|
86
|
+
// use:enhance uses a custom header to disambiguate
|
|
87
|
+
if (method === 'POST' && headers.get('x-sveltekit-action') === 'true') return false;
|
|
88
|
+
|
|
87
89
|
// GET/POST requests may be for endpoints or pages. We prefer endpoints if this isn't a text/html request
|
|
88
90
|
const accept = event.request.headers.get('accept') ?? '*/*';
|
|
89
91
|
return negotiate(accept, ['*', 'text/html']) !== 'text/html';
|
|
@@ -296,6 +296,11 @@ export async function respond(request, options, state) {
|
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
298
|
add_cookies_to_headers(response.headers, Array.from(new_cookies.values()));
|
|
299
|
+
|
|
300
|
+
if (state.prerendering && event.routeId !== null) {
|
|
301
|
+
response.headers.set('x-sveltekit-routeid', event.routeId);
|
|
302
|
+
}
|
|
303
|
+
|
|
299
304
|
return response;
|
|
300
305
|
}),
|
|
301
306
|
// TODO remove for 1.0
|
package/types/index.d.ts
CHANGED