svelte 5.56.9 → 5.57.0
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/compiler/index.js +1 -1
- package/elements.d.ts +3 -0
- package/package.json +3 -3
- package/src/compiler/migrate/index.js +6 -1
- package/src/compiler/phases/1-parse/acorn.js +1 -1
- package/src/compiler/phases/1-parse/read/style.js +16 -6
- package/src/compiler/phases/1-parse/utils/html.js +12 -7
- package/src/compiler/phases/2-analyze/css/css-prune.js +10 -0
- package/src/compiler/phases/2-analyze/index.js +45 -18
- package/src/compiler/phases/2-analyze/visitors/AwaitExpression.js +10 -4
- package/src/compiler/phases/2-analyze/visitors/CallExpression.js +1 -1
- package/src/compiler/phases/2-analyze/visitors/DeclarationTag.js +2 -1
- package/src/compiler/phases/2-analyze/visitors/ExportNamedDeclaration.js +10 -10
- package/src/compiler/phases/2-analyze/visitors/SvelteBody.js +4 -4
- package/src/compiler/phases/2-analyze/visitors/SvelteDocument.js +4 -4
- package/src/compiler/phases/2-analyze/visitors/SvelteWindow.js +4 -4
- package/src/compiler/phases/2-analyze/visitors/shared/a11y/index.js +14 -2
- package/src/compiler/phases/2-analyze/visitors/shared/element.js +2 -8
- package/src/compiler/phases/2-analyze/visitors/shared/utils.js +23 -1
- package/src/compiler/phases/3-transform/client/transform-client.js +2 -2
- package/src/compiler/phases/3-transform/client/transform-template/index.js +6 -0
- package/src/compiler/phases/3-transform/client/utils.js +35 -8
- package/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js +16 -3
- package/src/compiler/phases/3-transform/client/visitors/AwaitBlock.js +6 -6
- package/src/compiler/phases/3-transform/client/visitors/BindDirective.js +10 -13
- package/src/compiler/phases/3-transform/client/visitors/ConstTag.js +19 -8
- package/src/compiler/phases/3-transform/client/visitors/DeclarationTag.js +3 -2
- package/src/compiler/phases/3-transform/client/visitors/EachBlock.js +4 -1
- package/src/compiler/phases/3-transform/client/visitors/Fragment.js +2 -7
- package/src/compiler/phases/3-transform/client/visitors/HtmlTag.js +2 -1
- package/src/compiler/phases/3-transform/client/visitors/IfBlock.js +2 -1
- package/src/compiler/phases/3-transform/client/visitors/KeyBlock.js +2 -1
- package/src/compiler/phases/3-transform/client/visitors/RegularElement.js +119 -46
- package/src/compiler/phases/3-transform/client/visitors/SvelteElement.js +2 -1
- package/src/compiler/phases/3-transform/client/visitors/UpdateExpression.js +0 -1
- package/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +11 -4
- package/src/compiler/phases/3-transform/client/visitors/shared/element.js +6 -1
- package/src/compiler/phases/3-transform/client/visitors/shared/fragment.js +1 -6
- package/src/compiler/phases/3-transform/client/visitors/shared/utils.js +5 -5
- package/src/compiler/phases/3-transform/css/index.js +5 -1
- package/src/compiler/phases/3-transform/server/transform-server.js +20 -9
- package/src/compiler/phases/3-transform/server/visitors/AssignmentExpression.js +1 -1
- package/src/compiler/phases/3-transform/server/visitors/DeclarationTag.js +1 -1
- package/src/compiler/phases/3-transform/server/visitors/EachBlock.js +8 -2
- package/src/compiler/phases/3-transform/server/visitors/IfBlock.js +4 -4
- package/src/compiler/phases/3-transform/server/visitors/LabeledStatement.js +1 -0
- package/src/compiler/phases/3-transform/server/visitors/RegularElement.js +1 -1
- package/src/compiler/phases/3-transform/server/visitors/SvelteBoundary.js +9 -4
- package/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js +4 -2
- package/src/compiler/phases/3-transform/server/visitors/shared/element.js +53 -47
- package/src/compiler/phases/3-transform/server/visitors/shared/utils.js +31 -1
- package/src/compiler/phases/bindings.js +3 -1
- package/src/compiler/phases/nodes.js +4 -0
- package/src/compiler/print/index.js +95 -24
- package/src/easing/index.js +62 -0
- package/src/internal/client/constants.js +9 -0
- package/src/internal/client/context.js +33 -56
- package/src/internal/client/dev/hmr.js +15 -4
- package/src/internal/client/dom/blocks/boundary.js +21 -12
- package/src/internal/client/dom/blocks/css-props.js +3 -3
- package/src/internal/client/dom/blocks/slot.js +19 -0
- package/src/internal/client/dom/blocks/svelte-head.js +8 -0
- package/src/internal/client/dom/css.js +6 -1
- package/src/internal/client/dom/elements/attributes.js +37 -35
- package/src/internal/client/dom/elements/bindings/select.js +99 -9
- package/src/internal/client/dom/elements/bindings/this.js +7 -2
- package/src/internal/client/dom/elements/events.js +19 -1
- package/src/internal/client/dom/elements/transitions.js +81 -68
- package/src/internal/client/dom/operations.js +21 -1
- package/src/internal/client/error-handling.js +10 -2
- package/src/internal/client/index.js +9 -2
- package/src/internal/client/proxy.js +8 -3
- package/src/internal/client/reactivity/async.js +23 -3
- package/src/internal/client/reactivity/batch.js +1 -0
- package/src/internal/client/reactivity/effects.js +14 -1
- package/src/internal/client/reactivity/sources.js +7 -1
- package/src/internal/client/render.js +4 -8
- package/src/internal/client/runtime.js +45 -33
- package/src/internal/client/warnings.js +0 -11
- package/src/internal/server/abort-signal.js +8 -9
- package/src/internal/server/context.js +9 -48
- package/src/internal/server/index.js +1 -1
- package/src/internal/server/renderer.js +164 -52
- package/src/internal/shared/attributes.js +4 -2
- package/src/internal/shared/clone.js +2 -0
- package/src/internal/shared/context.js +53 -0
- package/src/internal/shared/errors.js +2 -2
- package/src/legacy/legacy-server.js +1 -1
- package/src/reactivity/map.js +22 -0
- package/src/reactivity/url.js +2 -0
- package/src/transition/index.js +18 -7
- package/src/version.js +1 -1
- package/types/index.d.ts +148 -46
- package/types/index.d.ts.map +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @import { SSRContext } from '#server' */
|
|
2
2
|
import { DEV } from 'esm-env';
|
|
3
|
-
import
|
|
3
|
+
import { create_context, get_or_init_context_map } from '../shared/context.js';
|
|
4
4
|
|
|
5
5
|
/** @type {SSRContext | null} */
|
|
6
6
|
export var ssr_context = null;
|
|
@@ -12,22 +12,13 @@ export function set_ssr_context(v) {
|
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @template T
|
|
15
|
-
* @returns {[() => T, (context: T) => T]}
|
|
15
|
+
* @returns {[() => T, (context: T) => T, () => boolean]}
|
|
16
16
|
* @since 5.40.0
|
|
17
17
|
*/
|
|
18
18
|
export function createContext() {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
() => {
|
|
23
|
-
if (!hasContext(key)) {
|
|
24
|
-
e.missing_context();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return getContext(key);
|
|
28
|
-
},
|
|
29
|
-
(context) => setContext(key, context)
|
|
30
|
-
];
|
|
19
|
+
return /** @type {[() => T, (context: T) => T, () => boolean]} */ (
|
|
20
|
+
create_context(getContext, setContext, hasContext)
|
|
21
|
+
);
|
|
31
22
|
}
|
|
32
23
|
|
|
33
24
|
/**
|
|
@@ -36,7 +27,7 @@ export function createContext() {
|
|
|
36
27
|
* @returns {T}
|
|
37
28
|
*/
|
|
38
29
|
export function getContext(key) {
|
|
39
|
-
const context_map = get_or_init_context_map('getContext');
|
|
30
|
+
const context_map = get_or_init_context_map(ssr_context, 'getContext');
|
|
40
31
|
const result = /** @type {T} */ (context_map.get(key));
|
|
41
32
|
|
|
42
33
|
return result;
|
|
@@ -49,7 +40,7 @@ export function getContext(key) {
|
|
|
49
40
|
* @returns {T}
|
|
50
41
|
*/
|
|
51
42
|
export function setContext(key, context) {
|
|
52
|
-
get_or_init_context_map('setContext').set(key, context);
|
|
43
|
+
get_or_init_context_map(ssr_context, 'setContext').set(key, context);
|
|
53
44
|
return context;
|
|
54
45
|
}
|
|
55
46
|
|
|
@@ -58,24 +49,12 @@ export function setContext(key, context) {
|
|
|
58
49
|
* @returns {boolean}
|
|
59
50
|
*/
|
|
60
51
|
export function hasContext(key) {
|
|
61
|
-
return get_or_init_context_map('hasContext').has(key);
|
|
52
|
+
return get_or_init_context_map(ssr_context, 'hasContext').has(key);
|
|
62
53
|
}
|
|
63
54
|
|
|
64
55
|
/** @returns {Map<any, any>} */
|
|
65
56
|
export function getAllContexts() {
|
|
66
|
-
return get_or_init_context_map('getAllContexts');
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* @param {string} name
|
|
71
|
-
* @returns {Map<unknown, unknown>}
|
|
72
|
-
*/
|
|
73
|
-
function get_or_init_context_map(name) {
|
|
74
|
-
if (ssr_context === null) {
|
|
75
|
-
e.lifecycle_outside_component(name);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return (ssr_context.c ??= new Map(get_parent_context(ssr_context) || undefined));
|
|
57
|
+
return get_or_init_context_map(ssr_context, 'getAllContexts');
|
|
79
58
|
}
|
|
80
59
|
|
|
81
60
|
/**
|
|
@@ -94,24 +73,6 @@ export function pop() {
|
|
|
94
73
|
ssr_context = /** @type {SSRContext} */ (ssr_context).p;
|
|
95
74
|
}
|
|
96
75
|
|
|
97
|
-
/**
|
|
98
|
-
* @param {SSRContext} ssr_context
|
|
99
|
-
* @returns {Map<unknown, unknown> | null}
|
|
100
|
-
*/
|
|
101
|
-
function get_parent_context(ssr_context) {
|
|
102
|
-
let parent = ssr_context.p;
|
|
103
|
-
|
|
104
|
-
while (parent !== null) {
|
|
105
|
-
const context_map = parent.c;
|
|
106
|
-
if (context_map !== null) {
|
|
107
|
-
return context_map;
|
|
108
|
-
}
|
|
109
|
-
parent = parent.p;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
76
|
/**
|
|
116
77
|
* Wraps an `await` expression in such a way that the component context that was
|
|
117
78
|
* active before the expression evaluated can be reapplied afterwards —
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** @import { ComponentType, SvelteComponent, Component } from 'svelte' */
|
|
2
|
-
/** @import { Csp, RenderOutput } from '
|
|
2
|
+
/** @import { Csp, RenderOutput } from '../../server/public.js' */
|
|
3
3
|
/** @import { Store } from '#shared' */
|
|
4
4
|
export { FILENAME, HMR } from '../../constants.js';
|
|
5
5
|
import { attr, clsx, to_class, to_style } from '../shared/attributes.js';
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/** @import { Component } from 'svelte' */
|
|
2
|
-
/** @import {
|
|
2
|
+
/** @import { HydratableContext, SSRContext } from './types.js' */
|
|
3
|
+
/** @import { Csp, RenderOutput, SyncRenderOutput, Sha256Source } from '../../server/public.js' */
|
|
3
4
|
/** @import { MaybePromise } from '#shared' */
|
|
4
5
|
import { async_mode_flag } from '../flags/index.js';
|
|
5
|
-
import {
|
|
6
|
+
import { STALE_REACTION } from '../client/constants.js';
|
|
6
7
|
import { pop, push, set_ssr_context, ssr_context } from './context.js';
|
|
7
8
|
import * as e from './errors.js';
|
|
8
9
|
import * as w from './warnings.js';
|
|
@@ -12,7 +13,7 @@ import { attributes } from './index.js';
|
|
|
12
13
|
import { get_render_context, with_render_context, init_render_context } from './render-context.js';
|
|
13
14
|
import { sha256 } from './crypto.js';
|
|
14
15
|
import * as devalue from 'devalue';
|
|
15
|
-
import { has_own_property, noop } from '../shared/utils.js';
|
|
16
|
+
import { has_own_property, is_array, noop } from '../shared/utils.js';
|
|
16
17
|
import { escape_html } from '../../escaping.js';
|
|
17
18
|
|
|
18
19
|
/** @typedef {'head' | 'body'} RendererType */
|
|
@@ -88,7 +89,7 @@ export class Renderer {
|
|
|
88
89
|
* State that is local to the branch it is declared in.
|
|
89
90
|
* It will be shallow-copied to all children.
|
|
90
91
|
*
|
|
91
|
-
* @type {{ select_value:
|
|
92
|
+
* @type {{ select_value: any, multiple: boolean }}
|
|
92
93
|
*/
|
|
93
94
|
local;
|
|
94
95
|
|
|
@@ -100,7 +101,7 @@ export class Renderer {
|
|
|
100
101
|
this.#parent = parent;
|
|
101
102
|
|
|
102
103
|
this.global = global;
|
|
103
|
-
this.local = parent ? { ...parent.local } : { select_value: undefined };
|
|
104
|
+
this.local = parent ? { ...parent.local } : { select_value: undefined, multiple: false };
|
|
104
105
|
this.type = parent ? parent.type : 'body';
|
|
105
106
|
}
|
|
106
107
|
|
|
@@ -179,7 +180,7 @@ export class Renderer {
|
|
|
179
180
|
// prevent unhandled rejections, and attach the promise to the renderer instance
|
|
180
181
|
// so that rejections correctly cause rendering to fail
|
|
181
182
|
promise.catch(noop);
|
|
182
|
-
this.promise = promise;
|
|
183
|
+
this.promise = this.global.track(promise);
|
|
183
184
|
|
|
184
185
|
return promises;
|
|
185
186
|
}
|
|
@@ -224,7 +225,7 @@ export class Renderer {
|
|
|
224
225
|
e.await_invalid();
|
|
225
226
|
}
|
|
226
227
|
|
|
227
|
-
child.promise = result;
|
|
228
|
+
child.promise = child.global.track(result);
|
|
228
229
|
}
|
|
229
230
|
|
|
230
231
|
return child;
|
|
@@ -272,7 +273,7 @@ export class Renderer {
|
|
|
272
273
|
e.await_invalid();
|
|
273
274
|
}
|
|
274
275
|
result.catch(noop);
|
|
275
|
-
child.promise = result;
|
|
276
|
+
child.promise = child.global.track(result);
|
|
276
277
|
}
|
|
277
278
|
} catch (error) {
|
|
278
279
|
// synchronous errors are handled here, async errors will be handled in #collect_content_async
|
|
@@ -292,12 +293,14 @@ export class Renderer {
|
|
|
292
293
|
e.await_invalid();
|
|
293
294
|
}
|
|
294
295
|
|
|
295
|
-
child.promise =
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
296
|
+
child.promise = child.global.track(
|
|
297
|
+
/** @type {Promise<unknown>} */ (result).then((transformed) => {
|
|
298
|
+
set_ssr_context(parent_context);
|
|
299
|
+
child.#out.push(Renderer.#serialize_failed_boundary(transformed));
|
|
300
|
+
failed_snippet(child, transformed, noop);
|
|
301
|
+
child.#out.push(BLOCK_CLOSE);
|
|
302
|
+
})
|
|
303
|
+
);
|
|
301
304
|
child.promise.catch(noop);
|
|
302
305
|
} else {
|
|
303
306
|
child.#out.push(Renderer.#serialize_failed_boundary(result));
|
|
@@ -316,8 +319,11 @@ export class Renderer {
|
|
|
316
319
|
*/
|
|
317
320
|
component(fn, component_fn) {
|
|
318
321
|
push(component_fn);
|
|
319
|
-
|
|
320
|
-
child
|
|
322
|
+
// mark before running so `onDestroy` callbacks are still collected if `fn` throws
|
|
323
|
+
this.child((renderer) => {
|
|
324
|
+
renderer.#is_component_body = true;
|
|
325
|
+
return fn(renderer);
|
|
326
|
+
});
|
|
321
327
|
pop();
|
|
322
328
|
}
|
|
323
329
|
|
|
@@ -332,11 +338,13 @@ export class Renderer {
|
|
|
332
338
|
* @returns {void}
|
|
333
339
|
*/
|
|
334
340
|
select(attrs, fn, css_hash, classes, styles, flags, is_rich) {
|
|
335
|
-
const { value, ...select_attrs } = attrs;
|
|
341
|
+
const { value, defaultValue, ...select_attrs } = attrs;
|
|
342
|
+
if (select_attrs.multiple === '') select_attrs.multiple = true;
|
|
336
343
|
|
|
337
344
|
this.push(`<select${attributes(select_attrs, css_hash, classes, styles, flags)}>`);
|
|
338
345
|
this.child((renderer) => {
|
|
339
|
-
renderer.local.select_value = value;
|
|
346
|
+
renderer.local.select_value = value === undefined ? defaultValue : value;
|
|
347
|
+
renderer.local.multiple = !!select_attrs.multiple;
|
|
340
348
|
fn(renderer);
|
|
341
349
|
});
|
|
342
350
|
this.push(`${is_rich ? '<!>' : ''}</select>`);
|
|
@@ -364,7 +372,15 @@ export class Renderer {
|
|
|
364
372
|
value = attrs.value;
|
|
365
373
|
}
|
|
366
374
|
|
|
367
|
-
|
|
375
|
+
var select_value = this.local.select_value;
|
|
376
|
+
|
|
377
|
+
if (
|
|
378
|
+
// Super edge-case, but theoretically someone could use arrays with non-multiple selects,
|
|
379
|
+
// so we gotta check for the multiple attribute presence, too.
|
|
380
|
+
this.local.multiple && is_array(select_value)
|
|
381
|
+
? select_value.includes(value)
|
|
382
|
+
: value === select_value
|
|
383
|
+
) {
|
|
368
384
|
renderer.#out.push(' selected=""');
|
|
369
385
|
}
|
|
370
386
|
|
|
@@ -451,6 +467,7 @@ export class Renderer {
|
|
|
451
467
|
*/
|
|
452
468
|
copy() {
|
|
453
469
|
const copy = new Renderer(this.global, this.#parent);
|
|
470
|
+
copy.type = this.type;
|
|
454
471
|
copy.#out = this.#out.map((item) => (item instanceof Renderer ? item.copy() : item));
|
|
455
472
|
copy.promise = this.promise;
|
|
456
473
|
return copy;
|
|
@@ -624,6 +641,49 @@ export class Renderer {
|
|
|
624
641
|
}
|
|
625
642
|
}
|
|
626
643
|
|
|
644
|
+
/**
|
|
645
|
+
* Runs every `onDestroy` callback in this renderer tree. On a failed render,
|
|
646
|
+
* cleanup errors are suppressed so they do not mask the render error.
|
|
647
|
+
* @param {boolean} suppress_errors
|
|
648
|
+
*/
|
|
649
|
+
#run_on_destroy(suppress_errors) {
|
|
650
|
+
let first_error;
|
|
651
|
+
let has_error = false;
|
|
652
|
+
|
|
653
|
+
for (const cleanup of this.#collect_on_destroy()) {
|
|
654
|
+
try {
|
|
655
|
+
cleanup();
|
|
656
|
+
} catch (error) {
|
|
657
|
+
if (!suppress_errors && !has_error) {
|
|
658
|
+
first_error = error;
|
|
659
|
+
has_error = true;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
if (has_error) throw first_error;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* @param {'sync' | 'async'} mode
|
|
669
|
+
* @param {{ idPrefix?: string; csp?: Csp; transformError?: (error: unknown) => unknown }} options
|
|
670
|
+
* @returns {Renderer}
|
|
671
|
+
*/
|
|
672
|
+
static #create(mode, options) {
|
|
673
|
+
if (options.idPrefix?.includes('--')) {
|
|
674
|
+
e.invalid_id_prefix();
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
return new Renderer(
|
|
678
|
+
new SSRState(
|
|
679
|
+
mode,
|
|
680
|
+
options.idPrefix ? options.idPrefix + '-' : '',
|
|
681
|
+
options.csp,
|
|
682
|
+
options.transformError
|
|
683
|
+
)
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
|
|
627
687
|
/**
|
|
628
688
|
* Render a component. Throws if any of the children are performing asynchronous work.
|
|
629
689
|
*
|
|
@@ -634,13 +694,27 @@ export class Renderer {
|
|
|
634
694
|
*/
|
|
635
695
|
static #render(component, options) {
|
|
636
696
|
var previous_context = ssr_context;
|
|
697
|
+
const renderer = Renderer.#create('sync', options);
|
|
698
|
+
/** @type {AccumulatedContent | undefined} */
|
|
699
|
+
let result;
|
|
700
|
+
let render_error;
|
|
701
|
+
let failed = false;
|
|
702
|
+
|
|
637
703
|
try {
|
|
638
|
-
|
|
704
|
+
try {
|
|
705
|
+
Renderer.#open_render(renderer, component, options);
|
|
706
|
+
result = Renderer.#close_render(renderer.#collect_content(), renderer);
|
|
707
|
+
} catch (error) {
|
|
708
|
+
render_error = error;
|
|
709
|
+
failed = true;
|
|
710
|
+
}
|
|
639
711
|
|
|
640
|
-
|
|
641
|
-
|
|
712
|
+
renderer.#run_on_destroy(failed);
|
|
713
|
+
if (failed) throw render_error;
|
|
714
|
+
|
|
715
|
+
return /** @type {AccumulatedContent} */ (result);
|
|
642
716
|
} finally {
|
|
643
|
-
abort();
|
|
717
|
+
renderer.global.abort();
|
|
644
718
|
set_ssr_context(previous_context);
|
|
645
719
|
}
|
|
646
720
|
}
|
|
@@ -655,18 +729,35 @@ export class Renderer {
|
|
|
655
729
|
*/
|
|
656
730
|
static async #render_async(component, options) {
|
|
657
731
|
const previous_context = ssr_context;
|
|
732
|
+
const renderer = Renderer.#create('async', options);
|
|
733
|
+
/** @type {(AccumulatedContent & { hashes: { script: Sha256Source[] } }) | undefined} */
|
|
734
|
+
let result;
|
|
735
|
+
let render_error;
|
|
736
|
+
let failed = false;
|
|
658
737
|
|
|
659
738
|
try {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
739
|
+
try {
|
|
740
|
+
Renderer.#open_render(renderer, component, options);
|
|
741
|
+
const content = await renderer.#collect_content_async();
|
|
742
|
+
const hydratables = await renderer.#collect_hydratables();
|
|
743
|
+
if (hydratables !== null) {
|
|
744
|
+
content.head = hydratables + content.head;
|
|
745
|
+
}
|
|
746
|
+
result = Renderer.#close_render(content, renderer);
|
|
747
|
+
} catch (error) {
|
|
748
|
+
render_error = error;
|
|
749
|
+
failed = true;
|
|
750
|
+
renderer.global.abort();
|
|
751
|
+
await renderer.global.settle();
|
|
665
752
|
}
|
|
666
|
-
|
|
753
|
+
|
|
754
|
+
renderer.#run_on_destroy(failed);
|
|
755
|
+
if (failed) throw render_error;
|
|
756
|
+
|
|
757
|
+
return /** @type {AccumulatedContent & { hashes: { script: Sha256Source[] } }} */ (result);
|
|
667
758
|
} finally {
|
|
668
759
|
set_ssr_context(previous_context);
|
|
669
|
-
abort();
|
|
760
|
+
renderer.global.abort();
|
|
670
761
|
}
|
|
671
762
|
}
|
|
672
763
|
|
|
@@ -758,28 +849,15 @@ export class Renderer {
|
|
|
758
849
|
|
|
759
850
|
/**
|
|
760
851
|
* @template {Record<string, any>} Props
|
|
761
|
-
* @param {
|
|
852
|
+
* @param {Renderer} renderer
|
|
762
853
|
* @param {import('svelte').Component<Props>} component
|
|
763
854
|
* @param {{ props?: Omit<Props, '$$slots' | '$$events'>; context?: Map<any, any>; idPrefix?: string; csp?: Csp; transformError?: (error: unknown) => unknown }} options
|
|
764
|
-
* @returns {
|
|
855
|
+
* @returns {void}
|
|
765
856
|
*/
|
|
766
|
-
static #open_render(
|
|
767
|
-
if (options.idPrefix?.includes('--')) {
|
|
768
|
-
e.invalid_id_prefix();
|
|
769
|
-
}
|
|
770
|
-
|
|
857
|
+
static #open_render(renderer, component, options) {
|
|
771
858
|
var previous_context = ssr_context;
|
|
772
859
|
|
|
773
860
|
try {
|
|
774
|
-
const renderer = new Renderer(
|
|
775
|
-
new SSRState(
|
|
776
|
-
mode,
|
|
777
|
-
options.idPrefix ? options.idPrefix + '-' : '',
|
|
778
|
-
options.csp,
|
|
779
|
-
options.transformError
|
|
780
|
-
)
|
|
781
|
-
);
|
|
782
|
-
|
|
783
861
|
/** @type {SSRContext} */
|
|
784
862
|
const context = { p: null, c: options.context ?? null, r: renderer };
|
|
785
863
|
set_ssr_context(context);
|
|
@@ -788,8 +866,6 @@ export class Renderer {
|
|
|
788
866
|
// @ts-expect-error
|
|
789
867
|
component(renderer, options.props ?? {});
|
|
790
868
|
renderer.push(BLOCK_CLOSE);
|
|
791
|
-
|
|
792
|
-
return renderer;
|
|
793
869
|
} finally {
|
|
794
870
|
set_ssr_context(previous_context);
|
|
795
871
|
}
|
|
@@ -801,10 +877,6 @@ export class Renderer {
|
|
|
801
877
|
* @returns {AccumulatedContent & { hashes: { script: Sha256Source[] } }}
|
|
802
878
|
*/
|
|
803
879
|
static #close_render(content, renderer) {
|
|
804
|
-
for (const cleanup of renderer.#collect_on_destroy()) {
|
|
805
|
-
cleanup();
|
|
806
|
-
}
|
|
807
|
-
|
|
808
880
|
let head = content.head + renderer.global.get_title();
|
|
809
881
|
let body = content.body;
|
|
810
882
|
|
|
@@ -888,6 +960,14 @@ export class SSRState {
|
|
|
888
960
|
/** @readonly @type {Set<{ hash: string; code: string }>} */
|
|
889
961
|
css = new Set();
|
|
890
962
|
|
|
963
|
+
/** @type {Set<Promise<unknown>>} */
|
|
964
|
+
#pending = new Set();
|
|
965
|
+
|
|
966
|
+
/** @type {AbortController | null} */
|
|
967
|
+
#controller = null;
|
|
968
|
+
|
|
969
|
+
#aborted = false;
|
|
970
|
+
|
|
891
971
|
/**
|
|
892
972
|
* `transformError` passed to `render`. Called when an error boundary catches an error.
|
|
893
973
|
* Throws by default if unset in `render`.
|
|
@@ -918,6 +998,38 @@ export class SSRState {
|
|
|
918
998
|
this.uid = () => `${id_prefix}s${uid++}`;
|
|
919
999
|
}
|
|
920
1000
|
|
|
1001
|
+
/**
|
|
1002
|
+
* @template T
|
|
1003
|
+
* @param {Promise<T>} promise
|
|
1004
|
+
* @returns {Promise<T>}
|
|
1005
|
+
*/
|
|
1006
|
+
track(promise) {
|
|
1007
|
+
this.#pending.add(promise);
|
|
1008
|
+
promise.then(
|
|
1009
|
+
() => this.#pending.delete(promise),
|
|
1010
|
+
() => this.#pending.delete(promise)
|
|
1011
|
+
);
|
|
1012
|
+
return promise;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
async settle() {
|
|
1016
|
+
while (this.#pending.size > 0) {
|
|
1017
|
+
await Promise.allSettled([...this.#pending]);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
abort() {
|
|
1022
|
+
if (this.#aborted) return;
|
|
1023
|
+
this.#aborted = true;
|
|
1024
|
+
this.#controller?.abort(STALE_REACTION);
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
get_abort_signal() {
|
|
1028
|
+
const controller = (this.#controller ??= new AbortController());
|
|
1029
|
+
if (this.#aborted) controller.abort(STALE_REACTION);
|
|
1030
|
+
return controller.signal;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
921
1033
|
get_title() {
|
|
922
1034
|
return this.#title.value;
|
|
923
1035
|
}
|
|
@@ -27,7 +27,8 @@ export function attr(name, value, is_boolean = false) {
|
|
|
27
27
|
if (name === 'hidden' && value !== 'until-found') {
|
|
28
28
|
is_boolean = true;
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
// `''` is a present boolean attribute, as it is in markup and on the client
|
|
31
|
+
if (value == null || (is_boolean && !value && value !== '')) return '';
|
|
31
32
|
const normalized =
|
|
32
33
|
(has_own_property.call(replacements, name) && replacements[name].get(value)) || value;
|
|
33
34
|
const assignment = is_boolean ? `=""` : `="${escape_html(normalized, true)}"`;
|
|
@@ -142,8 +143,9 @@ export function to_style(value, styles) {
|
|
|
142
143
|
}
|
|
143
144
|
|
|
144
145
|
if (value) {
|
|
146
|
+
// strip comments; surrounding whitespace is handled by the trims below (which is much faster than doing it through regex)
|
|
145
147
|
value = String(value)
|
|
146
|
-
.replaceAll(
|
|
148
|
+
.replaceAll(/\/\*.*?\*\//g, '')
|
|
147
149
|
.trim();
|
|
148
150
|
|
|
149
151
|
/** @type {boolean | '"' | "'"} */
|
|
@@ -105,6 +105,8 @@ function clone(value, cloned, path, paths, original = null, no_tojson = false) {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
if (value instanceof Date) {
|
|
108
|
+
// Ensure SvelteDate snapshots are tracked
|
|
109
|
+
value.getTime();
|
|
108
110
|
return /** @type {Snapshot<T>} */ (structuredClone(value));
|
|
109
111
|
}
|
|
110
112
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { lifecycle_outside_component, missing_context } from './errors.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @template T
|
|
5
|
+
* @param {(key: object) => T} get_context
|
|
6
|
+
* @param {(key: object, context: T) => T} set_context
|
|
7
|
+
* @param {(key: object) => boolean} has_context
|
|
8
|
+
* @returns {[() => T, (context: T) => T, () => boolean]}
|
|
9
|
+
*/
|
|
10
|
+
export function create_context(get_context, set_context, has_context) {
|
|
11
|
+
const key = {};
|
|
12
|
+
|
|
13
|
+
return [
|
|
14
|
+
() => {
|
|
15
|
+
if (!has_context(key)) {
|
|
16
|
+
missing_context();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return get_context(key);
|
|
20
|
+
},
|
|
21
|
+
(context) => set_context(key, context),
|
|
22
|
+
() => has_context(key)
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @typedef {{ p: Context | null, c: Map<unknown, unknown> | null }} Context
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {Context} context
|
|
32
|
+
* @returns {Map<unknown, unknown> | null}
|
|
33
|
+
*/
|
|
34
|
+
function get_parent_context(context) {
|
|
35
|
+
let parent = context.p;
|
|
36
|
+
while (parent !== null && parent.c === null) {
|
|
37
|
+
parent = parent.p;
|
|
38
|
+
}
|
|
39
|
+
return parent?.c ?? null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {Context | null} context
|
|
44
|
+
* @param {string} name
|
|
45
|
+
* @returns {Map<unknown, unknown>}
|
|
46
|
+
*/
|
|
47
|
+
export function get_or_init_context_map(context, name) {
|
|
48
|
+
if (context === null) {
|
|
49
|
+
lifecycle_outside_component(name);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return (context.c ??= new Map(get_parent_context(context) || undefined));
|
|
53
|
+
}
|
|
@@ -86,12 +86,12 @@ export function lifecycle_outside_component(name) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
/**
|
|
89
|
-
* Context was not set in
|
|
89
|
+
* Context was not set in the current component or any of its ancestors
|
|
90
90
|
* @returns {never}
|
|
91
91
|
*/
|
|
92
92
|
export function missing_context() {
|
|
93
93
|
if (DEV) {
|
|
94
|
-
const error = new Error(`missing_context\nContext was not set in
|
|
94
|
+
const error = new Error(`missing_context\nContext was not set in the current component or any of its ancestors\nhttps://svelte.dev/e/missing_context`);
|
|
95
95
|
|
|
96
96
|
error.name = 'Svelte error';
|
|
97
97
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** @import { SvelteComponent } from '../index.js' */
|
|
2
|
-
/** @import { Csp } from '
|
|
2
|
+
/** @import { Csp } from '../server/public.js' */
|
|
3
3
|
import { asClassComponent as as_class_component, createClassComponent } from './legacy-client.js';
|
|
4
4
|
import { render } from '../internal/server/index.js';
|
|
5
5
|
import { async_mode_flag } from '../internal/flags/index.js';
|
package/src/reactivity/map.js
CHANGED
|
@@ -153,6 +153,28 @@ export class SvelteMap extends Map {
|
|
|
153
153
|
return super.get(key);
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
/**
|
|
157
|
+
* @param {K} key
|
|
158
|
+
* @param {V} value
|
|
159
|
+
* */
|
|
160
|
+
getOrInsert(key, value) {
|
|
161
|
+
if (!super.has(key)) {
|
|
162
|
+
this.set(key, value);
|
|
163
|
+
}
|
|
164
|
+
return /** @type {V} */ (this.get(key));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @param {K} key
|
|
169
|
+
* @param {(key: K) => V} callbackFn
|
|
170
|
+
*/
|
|
171
|
+
getOrInsertComputed(key, callbackFn) {
|
|
172
|
+
if (!super.has(key)) {
|
|
173
|
+
this.set(key, callbackFn(key));
|
|
174
|
+
}
|
|
175
|
+
return /** @type {V} */ (this.get(key));
|
|
176
|
+
}
|
|
177
|
+
|
|
156
178
|
/**
|
|
157
179
|
* @param {K} key
|
|
158
180
|
* @param {V} value
|
package/src/reactivity/url.js
CHANGED
|
@@ -163,6 +163,8 @@ export class SvelteURL extends URL {
|
|
|
163
163
|
set protocol(value) {
|
|
164
164
|
super.protocol = value;
|
|
165
165
|
set(this.#protocol, super.protocol);
|
|
166
|
+
// changing the protocol can clear the port when it matches the new scheme's default
|
|
167
|
+
set(this.#port, super.port);
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
get search() {
|
package/src/transition/index.js
CHANGED
|
@@ -28,6 +28,17 @@ function split_css_unit(value) {
|
|
|
28
28
|
return split ? [parseFloat(split[1]), split[2] || 'px'] : [/** @type {number} */ (value), 'px'];
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Omits unresolved dimensions rather than passing invalid values to Web Animations.
|
|
33
|
+
*
|
|
34
|
+
* @param {string} property
|
|
35
|
+
* @param {number} value
|
|
36
|
+
* @param {number} t
|
|
37
|
+
*/
|
|
38
|
+
function css_dimension(property, value, t) {
|
|
39
|
+
return Number.isNaN(value) ? '' : `${property}: ${t * value}px;`;
|
|
40
|
+
}
|
|
41
|
+
|
|
31
42
|
/**
|
|
32
43
|
* Animates a `blur` filter alongside an element's opacity.
|
|
33
44
|
*
|
|
@@ -138,13 +149,13 @@ export function slide(node, { delay = 0, duration = 400, easing = cubic_out, axi
|
|
|
138
149
|
css: (t) =>
|
|
139
150
|
'overflow: hidden;' +
|
|
140
151
|
`opacity: ${Math.min(t * 20, 1) * opacity};` +
|
|
141
|
-
|
|
142
|
-
`padding-${secondary_properties[0]}
|
|
143
|
-
`padding-${secondary_properties[1]}
|
|
144
|
-
`margin-${secondary_properties[0]}
|
|
145
|
-
`margin-${secondary_properties[1]}
|
|
146
|
-
`border-${secondary_properties[0]}-width
|
|
147
|
-
`border-${secondary_properties[1]}-width
|
|
152
|
+
css_dimension(primary_property, primary_property_value, t) +
|
|
153
|
+
css_dimension(`padding-${secondary_properties[0]}`, padding_start_value, t) +
|
|
154
|
+
css_dimension(`padding-${secondary_properties[1]}`, padding_end_value, t) +
|
|
155
|
+
css_dimension(`margin-${secondary_properties[0]}`, margin_start_value, t) +
|
|
156
|
+
css_dimension(`margin-${secondary_properties[1]}`, margin_end_value, t) +
|
|
157
|
+
css_dimension(`border-${secondary_properties[0]}-width`, border_width_start_value, t) +
|
|
158
|
+
css_dimension(`border-${secondary_properties[1]}-width`, border_width_end_value, t) +
|
|
148
159
|
`min-${primary_property}: 0`
|
|
149
160
|
};
|
|
150
161
|
}
|
package/src/version.js
CHANGED