@sveltejs/kit 1.0.0-next.421 → 1.0.0-next.424
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/src/core/sync/write_types.js +35 -18
- package/src/runtime/client/client.js +43 -9
- package/src/runtime/server/endpoint.js +24 -10
- package/src/runtime/server/index.js +30 -16
- package/src/runtime/server/page/index.js +8 -11
- package/src/runtime/server/page/load_data.js +48 -2
- package/src/runtime/server/page/render.js +22 -19
- package/src/runtime/server/page/respond_with_error.js +1 -0
- package/src/vite/build/utils.js +3 -0
- package/src/vite/dev/index.js +1 -0
- package/src/vite/index.js +3 -0
- package/src/vite/utils.js +14 -2
- package/types/index.d.ts +1 -1
- package/types/internal.d.ts +3 -0
package/package.json
CHANGED
|
@@ -139,22 +139,34 @@ function get_groups(manifest_data, routes_dir) {
|
|
|
139
139
|
return group;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
// first, sort nodes
|
|
143
|
-
const nodes = [...manifest_data.nodes].sort(
|
|
144
|
-
|
|
142
|
+
// first, sort nodes (necessary for finding the nearest layout more efficiently)...
|
|
143
|
+
const nodes = [...manifest_data.nodes].sort((n1, n2) => {
|
|
144
|
+
// Sort by path length first...
|
|
145
|
+
const path_length_diff =
|
|
145
146
|
/** @type {string} */ (n1.component ?? n1.shared ?? n1.server).split('/').length -
|
|
146
|
-
/** @type {string} */ (n2.component ?? n2.shared ?? n2.server).split('/').length
|
|
147
|
-
|
|
147
|
+
/** @type {string} */ (n2.component ?? n2.shared ?? n2.server).split('/').length;
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
path_length_diff ||
|
|
151
|
+
// ...on ties, sort named layouts first
|
|
152
|
+
(path.basename(n1.component || '').includes('-')
|
|
153
|
+
? -1
|
|
154
|
+
: path.basename(n2.component || '').includes('-')
|
|
155
|
+
? 1
|
|
156
|
+
: 0)
|
|
157
|
+
);
|
|
158
|
+
});
|
|
148
159
|
|
|
149
160
|
// ...then, populate `directories` with +page/+layout files...
|
|
150
161
|
for (let i = 0; i < nodes.length; i += 1) {
|
|
151
162
|
/** @type {Node} */
|
|
152
163
|
const node = { ...nodes[i] }; // shallow copy so we don't mutate the original when setting parent
|
|
153
164
|
|
|
165
|
+
const file_path = /** @type {string} */ (node.component ?? node.shared ?? node.server);
|
|
154
166
|
// skip default layout/error
|
|
155
|
-
if (!
|
|
167
|
+
if (!file_path.startsWith(routes_dir)) continue;
|
|
156
168
|
|
|
157
|
-
const parts =
|
|
169
|
+
const parts = file_path.split('/');
|
|
158
170
|
|
|
159
171
|
const file = /** @type {string} */ (parts.pop());
|
|
160
172
|
const dir = parts.join('/').slice(routes_dir.length + 1);
|
|
@@ -273,7 +285,7 @@ function write_types_for_dir(config, manifest_data, routes_dir, dir, groups, ts)
|
|
|
273
285
|
manifest_data.routes.forEach((route) => {
|
|
274
286
|
if (route.type === 'page' && route.id.startsWith(dir + '/')) {
|
|
275
287
|
// TODO this is O(n^2), see if we need to speed it up
|
|
276
|
-
for (const name of parse_route_id(route.id).names) {
|
|
288
|
+
for (const name of parse_route_id(route.id.slice(dir.length + 1)).names) {
|
|
277
289
|
layout_params.add(name);
|
|
278
290
|
}
|
|
279
291
|
}
|
|
@@ -414,7 +426,7 @@ function process_node(ts, node, outdir, params, groups) {
|
|
|
414
426
|
written_proxies.push(write(`${outdir}/proxy${basename}`, proxy.code));
|
|
415
427
|
}
|
|
416
428
|
|
|
417
|
-
server_data = get_data_type(node.server, '
|
|
429
|
+
server_data = get_data_type(node.server, 'null', proxy);
|
|
418
430
|
server_load = `Kit.ServerLoad<${params}, ${get_parent_type('LayoutServerData')}, OutputData>`;
|
|
419
431
|
|
|
420
432
|
if (proxy) {
|
|
@@ -438,6 +450,8 @@ function process_node(ts, node, outdir, params, groups) {
|
|
|
438
450
|
server_data = 'null';
|
|
439
451
|
}
|
|
440
452
|
|
|
453
|
+
const parent_type = get_parent_type('LayoutData');
|
|
454
|
+
|
|
441
455
|
if (node.shared) {
|
|
442
456
|
const content = fs.readFileSync(node.shared, 'utf8');
|
|
443
457
|
const proxy = tweak_types(ts, content, shared_names);
|
|
@@ -445,29 +459,32 @@ function process_node(ts, node, outdir, params, groups) {
|
|
|
445
459
|
written_proxies.push(write(`${outdir}/proxy${path.basename(node.shared)}`, proxy.code));
|
|
446
460
|
}
|
|
447
461
|
|
|
448
|
-
|
|
449
|
-
|
|
462
|
+
const type = get_data_type(node.shared, `${parent_type} & ${server_data}`, proxy);
|
|
463
|
+
|
|
464
|
+
data = `Omit<${parent_type}, keyof ${type}> & ${type}`;
|
|
465
|
+
load = `Kit.Load<${params}, ${server_data}, ${parent_type}, OutputData>`;
|
|
466
|
+
} else if (server_data === 'null') {
|
|
467
|
+
data = parent_type;
|
|
450
468
|
} else {
|
|
451
|
-
data = server_data
|
|
469
|
+
data = `Omit<${parent_type}, keyof ${server_data}> & ${server_data}`;
|
|
452
470
|
}
|
|
453
471
|
|
|
454
472
|
return { data, server_data, load, server_load, errors, written_proxies };
|
|
455
473
|
|
|
456
474
|
/**
|
|
457
475
|
* @param {string} file_path
|
|
458
|
-
* @param {string} method
|
|
459
476
|
* @param {string} fallback
|
|
460
477
|
* @param {Proxy} proxy
|
|
461
478
|
*/
|
|
462
|
-
function get_data_type(file_path,
|
|
479
|
+
function get_data_type(file_path, fallback, proxy) {
|
|
463
480
|
if (proxy) {
|
|
464
|
-
if (proxy.exports.includes(
|
|
481
|
+
if (proxy.exports.includes('load')) {
|
|
465
482
|
// If the file wasn't tweaked, we can use the return type of the original file.
|
|
466
483
|
// The advantage is that type updates are reflected without saving.
|
|
467
484
|
const from = proxy.modified
|
|
468
485
|
? `./proxy${replace_ext_with_js(path.basename(file_path))}`
|
|
469
486
|
: path_to_original(outdir, file_path);
|
|
470
|
-
return `Kit.AwaitedProperties<Awaited<ReturnType<typeof import('${from}')
|
|
487
|
+
return `Kit.AwaitedProperties<Awaited<ReturnType<typeof import('${from}').load>>>`;
|
|
471
488
|
} else {
|
|
472
489
|
return fallback;
|
|
473
490
|
}
|
|
@@ -713,12 +730,12 @@ export function find_nearest_layout(routes_dir, nodes, start_idx) {
|
|
|
713
730
|
}
|
|
714
731
|
|
|
715
732
|
let common_path = path.dirname(start_file);
|
|
716
|
-
if (match[1] === 'layout' && !name) {
|
|
733
|
+
if (match[1] === 'layout' && !match[2] && !name) {
|
|
717
734
|
// We are a default layout, so we skip the current level
|
|
718
735
|
common_path = path.dirname(common_path);
|
|
719
736
|
}
|
|
720
737
|
|
|
721
|
-
for (let i = start_idx; i >= 0; i -= 1) {
|
|
738
|
+
for (let i = start_idx - 1; i >= 0; i -= 1) {
|
|
722
739
|
const node = nodes[i];
|
|
723
740
|
const file = /** @type {string} */ (node.component || node.shared || node.server);
|
|
724
741
|
|
|
@@ -268,7 +268,22 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
268
268
|
navigation_result.props.page.url = url;
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
-
|
|
271
|
+
if (import.meta.env.DEV) {
|
|
272
|
+
// Nasty hack to silence harmless warnings the user can do nothing about
|
|
273
|
+
const warn = console.warn;
|
|
274
|
+
console.warn = (...args) => {
|
|
275
|
+
if (
|
|
276
|
+
args.length !== 1 ||
|
|
277
|
+
!/<(Layout|Page)> was created with unknown prop '(data|errors)'/.test(args[0])
|
|
278
|
+
) {
|
|
279
|
+
warn(...args);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
root.$set(navigation_result.props);
|
|
283
|
+
tick().then(() => (console.warn = warn));
|
|
284
|
+
} else {
|
|
285
|
+
root.$set(navigation_result.props);
|
|
286
|
+
}
|
|
272
287
|
} else {
|
|
273
288
|
initialize(navigation_result);
|
|
274
289
|
}
|
|
@@ -347,11 +362,30 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
347
362
|
|
|
348
363
|
page = result.props.page;
|
|
349
364
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
365
|
+
if (import.meta.env.DEV) {
|
|
366
|
+
// Nasty hack to silence harmless warnings the user can do nothing about
|
|
367
|
+
const warn = console.warn;
|
|
368
|
+
console.warn = (...args) => {
|
|
369
|
+
if (
|
|
370
|
+
args.length !== 1 ||
|
|
371
|
+
!/<(Layout|Page)> was created with unknown prop '(data|errors)'/.test(args[0])
|
|
372
|
+
) {
|
|
373
|
+
warn(...args);
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
root = new Root({
|
|
377
|
+
target,
|
|
378
|
+
props: { ...result.props, stores },
|
|
379
|
+
hydrate: true
|
|
380
|
+
});
|
|
381
|
+
console.warn = warn;
|
|
382
|
+
} else {
|
|
383
|
+
root = new Root({
|
|
384
|
+
target,
|
|
385
|
+
props: { ...result.props, stores },
|
|
386
|
+
hydrate: true
|
|
387
|
+
});
|
|
388
|
+
}
|
|
355
389
|
|
|
356
390
|
if (router_enabled) {
|
|
357
391
|
const navigation = { from: null, to: new URL(location.href) };
|
|
@@ -403,10 +437,10 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
403
437
|
let data = {};
|
|
404
438
|
let data_changed = false;
|
|
405
439
|
for (let i = 0; i < filtered.length; i += 1) {
|
|
406
|
-
|
|
440
|
+
data = { ...data, ...filtered[i].data };
|
|
407
441
|
// Only set props if the node actually updated. This prevents needless rerenders.
|
|
408
|
-
if (!current.branch.some((node) => node === filtered[i])) {
|
|
409
|
-
result.props[`data_${i}`] =
|
|
442
|
+
if (data_changed || !current.branch.some((node) => node === filtered[i])) {
|
|
443
|
+
result.props[`data_${i}`] = data;
|
|
410
444
|
data_changed = true;
|
|
411
445
|
}
|
|
412
446
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { HttpError, Redirect } from '../../index/private.js';
|
|
1
2
|
import { check_method_names, method_not_allowed } from './utils.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -29,16 +30,29 @@ export async function render_endpoint(event, route) {
|
|
|
29
30
|
return method_not_allowed(mod, method);
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (!(response instanceof Response)) {
|
|
37
|
-
return new Response(
|
|
38
|
-
`Invalid response from route ${event.url.pathname}: handler should return a Response object`,
|
|
39
|
-
{ status: 500 }
|
|
33
|
+
try {
|
|
34
|
+
const response = await handler(
|
|
35
|
+
/** @type {import('types').RequestEvent<Record<string, any>>} */ (event)
|
|
40
36
|
);
|
|
41
|
-
}
|
|
42
37
|
|
|
43
|
-
|
|
38
|
+
if (!(response instanceof Response)) {
|
|
39
|
+
return new Response(
|
|
40
|
+
`Invalid response from route ${event.url.pathname}: handler should return a Response object`,
|
|
41
|
+
{ status: 500 }
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return response;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (error instanceof HttpError) {
|
|
48
|
+
return new Response(error.message, { status: error.status });
|
|
49
|
+
} else if (error instanceof Redirect) {
|
|
50
|
+
return new Response(undefined, {
|
|
51
|
+
status: error.status,
|
|
52
|
+
headers: { Location: error.location }
|
|
53
|
+
});
|
|
54
|
+
} else {
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
44
58
|
}
|
|
@@ -118,6 +118,9 @@ export async function respond(request, options, state) {
|
|
|
118
118
|
/** @type {import('types').ResponseHeaders} */
|
|
119
119
|
const headers = {};
|
|
120
120
|
|
|
121
|
+
/** @type {string[]} */
|
|
122
|
+
const cookies = [];
|
|
123
|
+
|
|
121
124
|
/** @type {import('types').RequestEvent} */
|
|
122
125
|
const event = {
|
|
123
126
|
get clientAddress() {
|
|
@@ -141,16 +144,26 @@ export async function respond(request, options, state) {
|
|
|
141
144
|
setHeaders: (new_headers) => {
|
|
142
145
|
for (const key in new_headers) {
|
|
143
146
|
const lower = key.toLowerCase();
|
|
147
|
+
const value = new_headers[key];
|
|
144
148
|
|
|
145
|
-
if (lower
|
|
146
|
-
|
|
147
|
-
}
|
|
149
|
+
if (lower === 'set-cookie') {
|
|
150
|
+
const new_cookies = /** @type {string[]} */ (Array.isArray(value) ? value : [value]);
|
|
148
151
|
|
|
149
|
-
|
|
150
|
-
|
|
152
|
+
for (const cookie of new_cookies) {
|
|
153
|
+
if (cookies.includes(cookie)) {
|
|
154
|
+
throw new Error(`"${key}" header already has cookie with same value`);
|
|
155
|
+
}
|
|
151
156
|
|
|
152
|
-
|
|
153
|
-
|
|
157
|
+
cookies.push(cookie);
|
|
158
|
+
}
|
|
159
|
+
} else if (lower in headers) {
|
|
160
|
+
throw new Error(`"${key}" header is already set`);
|
|
161
|
+
} else {
|
|
162
|
+
headers[lower] = value;
|
|
163
|
+
|
|
164
|
+
if (state.prerendering && lower === 'cache-control') {
|
|
165
|
+
state.prerendering.cache = /** @type {string} */ (value);
|
|
166
|
+
}
|
|
154
167
|
}
|
|
155
168
|
}
|
|
156
169
|
},
|
|
@@ -254,6 +267,7 @@ export async function respond(request, options, state) {
|
|
|
254
267
|
return {
|
|
255
268
|
// TODO return `uses`, so we can reuse server data effectively
|
|
256
269
|
data: await load_server_data({
|
|
270
|
+
dev: options.dev,
|
|
257
271
|
event,
|
|
258
272
|
node,
|
|
259
273
|
parent: async () => {
|
|
@@ -312,19 +326,19 @@ export async function respond(request, options, state) {
|
|
|
312
326
|
: await render_page(event, route, options, state, resolve_opts);
|
|
313
327
|
}
|
|
314
328
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
321
|
-
} else if (!is_data_request) {
|
|
322
|
-
// we only want to set cookies on __data.json requests, we don't
|
|
323
|
-
// want to cache stuff erroneously etc
|
|
329
|
+
if (!is_data_request) {
|
|
330
|
+
// we only want to set cookies on __data.json requests, we don't
|
|
331
|
+
// want to cache stuff erroneously etc
|
|
332
|
+
for (const key in headers) {
|
|
333
|
+
const value = headers[key];
|
|
324
334
|
response.headers.set(key, /** @type {string} */ (value));
|
|
325
335
|
}
|
|
326
336
|
}
|
|
327
337
|
|
|
338
|
+
for (const cookie of cookies) {
|
|
339
|
+
response.headers.append('set-cookie', cookie);
|
|
340
|
+
}
|
|
341
|
+
|
|
328
342
|
// respond with 304 if etag matches
|
|
329
343
|
if (response.status === 200 && response.headers.has('etag')) {
|
|
330
344
|
let if_none_match_value = request.headers.get('if-none-match');
|
|
@@ -36,7 +36,11 @@ export async function render_page(event, route, options, state, resolve_opts) {
|
|
|
36
36
|
'application/json'
|
|
37
37
|
]);
|
|
38
38
|
|
|
39
|
-
if (
|
|
39
|
+
if (
|
|
40
|
+
accept === 'application/json' &&
|
|
41
|
+
event.request.method !== 'GET' &&
|
|
42
|
+
event.request.method !== 'HEAD'
|
|
43
|
+
) {
|
|
40
44
|
const node = await options.manifest._.nodes[route.leaf]();
|
|
41
45
|
if (node.server) {
|
|
42
46
|
return handle_json_request(event, options, node.server);
|
|
@@ -157,6 +161,7 @@ export async function render_page(event, route, options, state, resolve_opts) {
|
|
|
157
161
|
}
|
|
158
162
|
|
|
159
163
|
return await load_server_data({
|
|
164
|
+
dev: options.dev,
|
|
160
165
|
event,
|
|
161
166
|
node,
|
|
162
167
|
parent: async () => {
|
|
@@ -346,8 +351,8 @@ function get_page_config(leaf, options) {
|
|
|
346
351
|
* @param {import('types').SSRNode['server']} mod
|
|
347
352
|
*/
|
|
348
353
|
export async function handle_json_request(event, options, mod) {
|
|
349
|
-
const method = /** @type {
|
|
350
|
-
const handler = mod[method
|
|
354
|
+
const method = /** @type {'POST' | 'PUT' | 'PATCH' | 'DELETE'} */ (event.request.method);
|
|
355
|
+
const handler = mod[method];
|
|
351
356
|
|
|
352
357
|
if (!handler) {
|
|
353
358
|
return method_not_allowed(mod, method);
|
|
@@ -357,14 +362,6 @@ export async function handle_json_request(event, options, mod) {
|
|
|
357
362
|
// @ts-ignore
|
|
358
363
|
const result = await handler.call(null, event);
|
|
359
364
|
|
|
360
|
-
if (method === 'HEAD') {
|
|
361
|
-
return new Response();
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
if (method === 'GET') {
|
|
365
|
-
return json(result);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
365
|
if (result?.errors) {
|
|
369
366
|
// @ts-ignore
|
|
370
367
|
return json({ errors: result.errors }, { status: result.status || 400 });
|
|
@@ -3,12 +3,13 @@ import { LoadURL, PrerenderingURL } from '../../../utils/url.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* Calls the user's `load` function.
|
|
5
5
|
* @param {{
|
|
6
|
+
* dev: boolean;
|
|
6
7
|
* event: import('types').RequestEvent;
|
|
7
8
|
* node: import('types').SSRNode | undefined;
|
|
8
9
|
* parent: () => Promise<Record<string, any>>;
|
|
9
10
|
* }} opts
|
|
10
11
|
*/
|
|
11
|
-
export async function load_server_data({ event, node, parent }) {
|
|
12
|
+
export async function load_server_data({ dev, event, node, parent }) {
|
|
12
13
|
if (!node?.server) return null;
|
|
13
14
|
|
|
14
15
|
const server_data = await node.server.load?.call(null, {
|
|
@@ -27,7 +28,13 @@ export async function load_server_data({ event, node, parent }) {
|
|
|
27
28
|
url: event.url
|
|
28
29
|
});
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
const result = server_data ? await unwrap_promises(server_data) : null;
|
|
32
|
+
|
|
33
|
+
if (dev) {
|
|
34
|
+
check_serializability(result, /** @type {string} */ (node.server_id), 'data');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return result;
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
/**
|
|
@@ -79,3 +86,42 @@ async function unwrap_promises(object) {
|
|
|
79
86
|
|
|
80
87
|
return unwrapped;
|
|
81
88
|
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Check that the data can safely be serialized to JSON
|
|
92
|
+
* @param {any} value
|
|
93
|
+
* @param {string} id
|
|
94
|
+
* @param {string} path
|
|
95
|
+
*/
|
|
96
|
+
function check_serializability(value, id, path) {
|
|
97
|
+
const type = typeof value;
|
|
98
|
+
|
|
99
|
+
if (type === 'string' || type === 'boolean' || type === 'number' || type === 'undefined') {
|
|
100
|
+
// primitives are fine
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (type === 'object') {
|
|
105
|
+
// nulls are fine...
|
|
106
|
+
if (!value) return;
|
|
107
|
+
|
|
108
|
+
// ...so are plain arrays...
|
|
109
|
+
if (Array.isArray(value)) {
|
|
110
|
+
value.forEach((child, i) => {
|
|
111
|
+
check_serializability(child, id, `${path}[${i}]`);
|
|
112
|
+
});
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ...and objects
|
|
117
|
+
const tag = Object.prototype.toString.call(value);
|
|
118
|
+
if (tag === '[object Object]') {
|
|
119
|
+
for (const key in value) {
|
|
120
|
+
check_serializability(value[key], id, `${path}.${key}`);
|
|
121
|
+
}
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
throw new Error(`${path} returned from 'load' in ${id} cannot be serialized as JSON`);
|
|
127
|
+
}
|
|
@@ -83,18 +83,31 @@ export async function render_response({
|
|
|
83
83
|
navigating: writable(null),
|
|
84
84
|
updated
|
|
85
85
|
},
|
|
86
|
-
/** @type {import('types').Page} */
|
|
87
|
-
page: {
|
|
88
|
-
error,
|
|
89
|
-
params: /** @type {Record<string, any>} */ (event.params),
|
|
90
|
-
routeId: event.routeId,
|
|
91
|
-
status,
|
|
92
|
-
url: state.prerendering ? new PrerenderingURL(event.url) : event.url,
|
|
93
|
-
data: branch.reduce((acc, { data }) => (Object.assign(acc, data), acc), {})
|
|
94
|
-
},
|
|
95
86
|
components: await Promise.all(branch.map(({ node }) => node.component()))
|
|
96
87
|
};
|
|
97
88
|
|
|
89
|
+
let data = {};
|
|
90
|
+
|
|
91
|
+
// props_n (instead of props[n]) makes it easy to avoid
|
|
92
|
+
// unnecessary updates for layout components
|
|
93
|
+
for (let i = 0; i < branch.length; i += 1) {
|
|
94
|
+
data = { ...data, ...branch[i].data };
|
|
95
|
+
props[`data_${i}`] = data;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
props.page = {
|
|
99
|
+
error,
|
|
100
|
+
params: /** @type {Record<string, any>} */ (event.params),
|
|
101
|
+
routeId: event.routeId,
|
|
102
|
+
status,
|
|
103
|
+
url: state.prerendering ? new PrerenderingURL(event.url) : event.url,
|
|
104
|
+
data
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
if (validation_errors) {
|
|
108
|
+
props.errors = validation_errors;
|
|
109
|
+
}
|
|
110
|
+
|
|
98
111
|
// TODO remove this for 1.0
|
|
99
112
|
/**
|
|
100
113
|
* @param {string} property
|
|
@@ -112,16 +125,6 @@ export async function render_response({
|
|
|
112
125
|
print_error('path', 'pathname');
|
|
113
126
|
print_error('query', 'searchParams');
|
|
114
127
|
|
|
115
|
-
// props_n (instead of props[n]) makes it easy to avoid
|
|
116
|
-
// unnecessary updates for layout components
|
|
117
|
-
for (let i = 0; i < branch.length; i += 1) {
|
|
118
|
-
props[`data_${i}`] = branch[i].data;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (validation_errors) {
|
|
122
|
-
props.errors = validation_errors;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
128
|
rendered = options.root.render(props);
|
|
126
129
|
|
|
127
130
|
for (const { node } of branch) {
|
|
@@ -35,6 +35,7 @@ export async function respond_with_error({ event, options, state, status, error,
|
|
|
35
35
|
const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout
|
|
36
36
|
|
|
37
37
|
const server_data_promise = load_server_data({
|
|
38
|
+
dev: options.dev,
|
|
38
39
|
event,
|
|
39
40
|
node: default_layout,
|
|
40
41
|
parent: async () => ({})
|
package/src/vite/build/utils.js
CHANGED
package/src/vite/dev/index.js
CHANGED
|
@@ -119,6 +119,7 @@ export async function dev(vite, vite_config, svelte_config, illegal_imports) {
|
|
|
119
119
|
if (node.server) {
|
|
120
120
|
const { module } = await resolve(node.server);
|
|
121
121
|
result.server = module;
|
|
122
|
+
result.server_id = node.server;
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
// in dev we inline all styles to avoid FOUC. this gets populated lazily so that
|
package/src/vite/index.js
CHANGED
package/src/vite/utils.js
CHANGED
|
@@ -2,6 +2,7 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { loadConfigFromFile, loadEnv, normalizePath } from 'vite';
|
|
4
4
|
import { runtime_directory } from '../core/utils.js';
|
|
5
|
+
import { posixify } from '../utils/filesystem.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* @param {import('vite').ResolvedConfig} config
|
|
@@ -113,18 +114,22 @@ export function get_aliases(config) {
|
|
|
113
114
|
];
|
|
114
115
|
|
|
115
116
|
for (let [key, value] of Object.entries(config.alias)) {
|
|
117
|
+
value = posixify(value);
|
|
116
118
|
if (value.endsWith('/*')) {
|
|
117
119
|
value = value.slice(0, -2);
|
|
118
120
|
}
|
|
119
121
|
if (key.endsWith('/*')) {
|
|
120
122
|
// Doing just `{ find: key.slice(0, -2) ,..}` would mean `import .. from "key"` would also be matched, which we don't want
|
|
121
123
|
alias.push({
|
|
122
|
-
find: new RegExp(`^${key.slice(0, -2)}\\/(.+)$`),
|
|
124
|
+
find: new RegExp(`^${escape_for_regexp(key.slice(0, -2))}\\/(.+)$`),
|
|
123
125
|
replacement: `${path.resolve(value)}/$1`
|
|
124
126
|
});
|
|
125
127
|
} else if (key + '/*' in config.alias) {
|
|
126
128
|
// key and key/* both exist -> the replacement for key needs to happen _only_ on import .. from "key"
|
|
127
|
-
alias.push({
|
|
129
|
+
alias.push({
|
|
130
|
+
find: new RegExp(`^${escape_for_regexp(key)}$`),
|
|
131
|
+
replacement: path.resolve(value)
|
|
132
|
+
});
|
|
128
133
|
} else {
|
|
129
134
|
alias.push({ find: key, replacement: path.resolve(value) });
|
|
130
135
|
}
|
|
@@ -133,6 +138,13 @@ export function get_aliases(config) {
|
|
|
133
138
|
return alias;
|
|
134
139
|
}
|
|
135
140
|
|
|
141
|
+
/**
|
|
142
|
+
* @param {string} str
|
|
143
|
+
*/
|
|
144
|
+
function escape_for_regexp(str) {
|
|
145
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, (match) => '\\' + match);
|
|
146
|
+
}
|
|
147
|
+
|
|
136
148
|
/**
|
|
137
149
|
* Given an entry point like [cwd]/src/hooks, returns a filename like [cwd]/src/hooks.js or [cwd]/src/hooks/index.js
|
|
138
150
|
* @param {string} entry
|
package/types/index.d.ts
CHANGED
|
@@ -312,7 +312,7 @@ export interface Action<
|
|
|
312
312
|
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>
|
|
313
313
|
> {
|
|
314
314
|
(event: RequestEvent<Params>): MaybePromise<
|
|
315
|
-
| { status?: number; errors: Record<string,
|
|
315
|
+
| { status?: number; errors: Record<string, any>; location?: never }
|
|
316
316
|
| { status?: never; errors?: never; location: string }
|
|
317
317
|
| void
|
|
318
318
|
>;
|
package/types/internal.d.ts
CHANGED