svelte 5.49.0 → 5.49.2
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 +0 -17
- package/package.json +3 -3
- package/src/compiler/phases/3-transform/client/visitors/EachBlock.js +9 -6
- package/src/compiler/phases/3-transform/client/visitors/HtmlTag.js +9 -5
- package/src/compiler/phases/3-transform/client/visitors/IfBlock.js +9 -5
- package/src/compiler/phases/3-transform/client/visitors/KeyBlock.js +19 -13
- package/src/compiler/phases/3-transform/client/visitors/SvelteElement.js +9 -5
- package/src/compiler/phases/3-transform/server/visitors/RegularElement.js +10 -10
- package/src/compiler/phases/3-transform/server/visitors/SvelteElement.js +1 -1
- package/src/compiler/phases/3-transform/server/visitors/shared/utils.js +2 -3
- package/src/compiler/print/index.js +14 -50
- package/src/internal/client/dom/blocks/branches.js +4 -4
- package/src/internal/client/dom/blocks/each.js +2 -2
- package/src/internal/client/dom/operations.js +53 -20
- package/src/internal/client/dom/template.js +5 -1
- package/src/internal/client/reactivity/batch.js +54 -11
- package/src/internal/server/crypto.js +2 -1
- package/src/internal/server/renderer.js +6 -0
- package/src/version.js +1 -1
- package/types/index.d.ts.map +1 -1
package/elements.d.ts
CHANGED
|
@@ -851,23 +851,6 @@ export interface HTMLAttributes<T extends EventTarget> extends AriaAttributes, D
|
|
|
851
851
|
readonly 'bind:offsetWidth'?: number | undefined | null;
|
|
852
852
|
readonly 'bind:offsetHeight'?: number | undefined | null;
|
|
853
853
|
|
|
854
|
-
// SvelteKit
|
|
855
|
-
'data-sveltekit-keepfocus'?: true | '' | 'off' | undefined | null;
|
|
856
|
-
'data-sveltekit-noscroll'?: true | '' | 'off' | undefined | null;
|
|
857
|
-
'data-sveltekit-preload-code'?:
|
|
858
|
-
| true
|
|
859
|
-
| ''
|
|
860
|
-
| 'eager'
|
|
861
|
-
| 'viewport'
|
|
862
|
-
| 'hover'
|
|
863
|
-
| 'tap'
|
|
864
|
-
| 'off'
|
|
865
|
-
| undefined
|
|
866
|
-
| null;
|
|
867
|
-
'data-sveltekit-preload-data'?: true | '' | 'hover' | 'tap' | 'off' | undefined | null;
|
|
868
|
-
'data-sveltekit-reload'?: true | '' | 'off' | undefined | null;
|
|
869
|
-
'data-sveltekit-replacestate'?: true | '' | 'off' | undefined | null;
|
|
870
|
-
|
|
871
854
|
// allow any data- attribute
|
|
872
855
|
[key: `data-${string}`]: any;
|
|
873
856
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "svelte",
|
|
3
3
|
"description": "Cybernetically enhanced web apps",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "5.49.
|
|
5
|
+
"version": "5.49.2",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"types": "./types/index.d.ts",
|
|
8
8
|
"engines": {
|
|
@@ -139,7 +139,7 @@
|
|
|
139
139
|
],
|
|
140
140
|
"devDependencies": {
|
|
141
141
|
"@jridgewell/trace-mapping": "^0.3.25",
|
|
142
|
-
"@playwright/test": "^1.
|
|
142
|
+
"@playwright/test": "^1.58.0",
|
|
143
143
|
"@rollup/plugin-commonjs": "^28.0.1",
|
|
144
144
|
"@rollup/plugin-node-resolve": "^15.3.0",
|
|
145
145
|
"@rollup/plugin-terser": "^0.4.4",
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
"clsx": "^2.1.1",
|
|
166
166
|
"devalue": "^5.6.2",
|
|
167
167
|
"esm-env": "^1.2.1",
|
|
168
|
-
"esrap": "^2.2.
|
|
168
|
+
"esrap": "^2.2.2",
|
|
169
169
|
"is-reference": "^3.0.3",
|
|
170
170
|
"locate-character": "^3.0.0",
|
|
171
171
|
"magic-string": "^0.30.11",
|
|
@@ -312,10 +312,10 @@ export function EachBlock(node, context) {
|
|
|
312
312
|
declarations.push(b.let(node.index, index));
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
-
const
|
|
315
|
+
const has_await = node.metadata.expression.has_await;
|
|
316
316
|
|
|
317
|
-
const get_collection = b.thunk(collection,
|
|
318
|
-
const thunk =
|
|
317
|
+
const get_collection = b.thunk(collection, has_await);
|
|
318
|
+
const thunk = has_await ? b.thunk(b.call('$.get', b.id('$$collection'))) : get_collection;
|
|
319
319
|
|
|
320
320
|
const render_args = [b.id('$$anchor'), item];
|
|
321
321
|
if (uses_index || collection_id) render_args.push(index);
|
|
@@ -342,15 +342,18 @@ export function EachBlock(node, context) {
|
|
|
342
342
|
statements.unshift(b.stmt(b.call('$.validate_each_keys', thunk, key_function)));
|
|
343
343
|
}
|
|
344
344
|
|
|
345
|
-
if (is_async) {
|
|
345
|
+
if (node.metadata.expression.is_async()) {
|
|
346
346
|
context.state.init.push(
|
|
347
347
|
b.stmt(
|
|
348
348
|
b.call(
|
|
349
349
|
'$.async',
|
|
350
350
|
context.state.node,
|
|
351
351
|
node.metadata.expression.blockers(),
|
|
352
|
-
b.array([get_collection]),
|
|
353
|
-
b.arrow(
|
|
352
|
+
has_await ? b.array([get_collection]) : b.void0,
|
|
353
|
+
b.arrow(
|
|
354
|
+
has_await ? [context.state.node, b.id('$$collection')] : [context.state.node],
|
|
355
|
+
b.block(statements)
|
|
356
|
+
)
|
|
354
357
|
)
|
|
355
358
|
)
|
|
356
359
|
);
|
|
@@ -11,10 +11,11 @@ import { build_expression } from './shared/utils.js';
|
|
|
11
11
|
export function HtmlTag(node, context) {
|
|
12
12
|
context.state.template.push_comment();
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const has_await = node.metadata.expression.has_await;
|
|
15
|
+
const has_blockers = node.metadata.expression.has_blockers();
|
|
15
16
|
|
|
16
17
|
const expression = build_expression(context, node.expression, node.metadata.expression);
|
|
17
|
-
const html =
|
|
18
|
+
const html = has_await ? b.call('$.get', b.id('$$html')) : expression;
|
|
18
19
|
|
|
19
20
|
const is_svg = context.state.metadata.namespace === 'svg';
|
|
20
21
|
const is_mathml = context.state.metadata.namespace === 'mathml';
|
|
@@ -31,15 +32,18 @@ export function HtmlTag(node, context) {
|
|
|
31
32
|
);
|
|
32
33
|
|
|
33
34
|
// push into init, so that bindings run afterwards, which might trigger another run and override hydration
|
|
34
|
-
if (
|
|
35
|
+
if (has_await || has_blockers) {
|
|
35
36
|
context.state.init.push(
|
|
36
37
|
b.stmt(
|
|
37
38
|
b.call(
|
|
38
39
|
'$.async',
|
|
39
40
|
context.state.node,
|
|
40
41
|
node.metadata.expression.blockers(),
|
|
41
|
-
b.array([b.thunk(expression,
|
|
42
|
-
b.arrow(
|
|
42
|
+
has_await ? b.array([b.thunk(expression, true)]) : b.void0,
|
|
43
|
+
b.arrow(
|
|
44
|
+
has_await ? [context.state.node, b.id('$$html')] : [context.state.node],
|
|
45
|
+
b.block([statement])
|
|
46
|
+
)
|
|
43
47
|
)
|
|
44
48
|
)
|
|
45
49
|
);
|
|
@@ -25,10 +25,11 @@ export function IfBlock(node, context) {
|
|
|
25
25
|
statements.push(b.var(alternate_id, b.arrow([b.id('$$anchor')], alternate)));
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
const
|
|
28
|
+
const has_await = node.metadata.expression.has_await;
|
|
29
|
+
const has_blockers = node.metadata.expression.has_blockers();
|
|
29
30
|
|
|
30
31
|
const expression = build_expression(context, node.test, node.metadata.expression);
|
|
31
|
-
const test =
|
|
32
|
+
const test = has_await ? b.call('$.get', b.id('$$condition')) : expression;
|
|
32
33
|
|
|
33
34
|
/** @type {Expression[]} */
|
|
34
35
|
const args = [
|
|
@@ -72,15 +73,18 @@ export function IfBlock(node, context) {
|
|
|
72
73
|
|
|
73
74
|
statements.push(add_svelte_meta(b.call('$.if', ...args), node, 'if'));
|
|
74
75
|
|
|
75
|
-
if (
|
|
76
|
+
if (has_await || has_blockers) {
|
|
76
77
|
context.state.init.push(
|
|
77
78
|
b.stmt(
|
|
78
79
|
b.call(
|
|
79
80
|
'$.async',
|
|
80
81
|
context.state.node,
|
|
81
82
|
node.metadata.expression.blockers(),
|
|
82
|
-
b.array([b.thunk(expression,
|
|
83
|
-
b.arrow(
|
|
83
|
+
has_await ? b.array([b.thunk(expression, true)]) : b.void0,
|
|
84
|
+
b.arrow(
|
|
85
|
+
has_await ? [context.state.node, b.id('$$condition')] : [context.state.node],
|
|
86
|
+
b.block(statements)
|
|
87
|
+
)
|
|
84
88
|
)
|
|
85
89
|
)
|
|
86
90
|
);
|
|
@@ -11,29 +11,35 @@ import { build_expression, add_svelte_meta } from './shared/utils.js';
|
|
|
11
11
|
export function KeyBlock(node, context) {
|
|
12
12
|
context.state.template.push_comment();
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const has_await = node.metadata.expression.has_await;
|
|
15
|
+
const has_blockers = node.metadata.expression.has_blockers();
|
|
15
16
|
|
|
16
17
|
const expression = build_expression(context, node.expression, node.metadata.expression);
|
|
17
|
-
const key = b.thunk(
|
|
18
|
+
const key = b.thunk(has_await ? b.call('$.get', b.id('$$key')) : expression);
|
|
18
19
|
const body = /** @type {Expression} */ (context.visit(node.fragment));
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
const statement = add_svelte_meta(
|
|
21
22
|
b.call('$.key', context.state.node, key, b.arrow([b.id('$$anchor')], body)),
|
|
22
23
|
node,
|
|
23
24
|
'key'
|
|
24
25
|
);
|
|
25
26
|
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
b.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
if (has_await || has_blockers) {
|
|
28
|
+
context.state.init.push(
|
|
29
|
+
b.stmt(
|
|
30
|
+
b.call(
|
|
31
|
+
'$.async',
|
|
32
|
+
context.state.node,
|
|
33
|
+
node.metadata.expression.blockers(),
|
|
34
|
+
has_await ? b.array([b.thunk(expression, true)]) : b.void0,
|
|
35
|
+
b.arrow(
|
|
36
|
+
has_await ? [context.state.node, b.id('$$key')] : [context.state.node],
|
|
37
|
+
b.block([statement])
|
|
38
|
+
)
|
|
39
|
+
)
|
|
34
40
|
)
|
|
35
41
|
);
|
|
42
|
+
} else {
|
|
43
|
+
context.state.init.push(statement);
|
|
36
44
|
}
|
|
37
|
-
|
|
38
|
-
context.state.init.push(statement);
|
|
39
45
|
}
|
|
@@ -93,10 +93,11 @@ export function SvelteElement(node, context) {
|
|
|
93
93
|
);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
const
|
|
96
|
+
const has_await = node.metadata.expression.has_await;
|
|
97
|
+
const has_blockers = node.metadata.expression.has_blockers();
|
|
97
98
|
|
|
98
99
|
const expression = /** @type {Expression} */ (context.visit(node.tag));
|
|
99
|
-
const get_tag = b.thunk(
|
|
100
|
+
const get_tag = b.thunk(has_await ? b.call('$.get', b.id('$$tag')) : expression);
|
|
100
101
|
|
|
101
102
|
/** @type {Statement[]} */
|
|
102
103
|
const inner = inner_context.state.init;
|
|
@@ -139,15 +140,18 @@ export function SvelteElement(node, context) {
|
|
|
139
140
|
)
|
|
140
141
|
);
|
|
141
142
|
|
|
142
|
-
if (
|
|
143
|
+
if (has_await || has_blockers) {
|
|
143
144
|
context.state.init.push(
|
|
144
145
|
b.stmt(
|
|
145
146
|
b.call(
|
|
146
147
|
'$.async',
|
|
147
148
|
context.state.node,
|
|
148
149
|
node.metadata.expression.blockers(),
|
|
149
|
-
b.array([b.thunk(expression,
|
|
150
|
-
b.arrow(
|
|
150
|
+
has_await ? b.array([b.thunk(expression, true)]) : b.void0,
|
|
151
|
+
b.arrow(
|
|
152
|
+
has_await ? [context.state.node, b.id('$$tag')] : [context.state.node],
|
|
153
|
+
b.block(statements)
|
|
154
|
+
)
|
|
151
155
|
)
|
|
152
156
|
)
|
|
153
157
|
);
|
|
@@ -70,8 +70,7 @@ export function RegularElement(node, context) {
|
|
|
70
70
|
if (optimiser.expressions.length > 0) {
|
|
71
71
|
context.state.template.push(
|
|
72
72
|
create_child_block(
|
|
73
|
-
b.block([optimiser.apply(), ...state.init, ...build_template(state.template)])
|
|
74
|
-
true
|
|
73
|
+
b.block([optimiser.apply(), ...state.init, ...build_template(state.template)])
|
|
75
74
|
)
|
|
76
75
|
);
|
|
77
76
|
} else {
|
|
@@ -133,7 +132,7 @@ export function RegularElement(node, context) {
|
|
|
133
132
|
|
|
134
133
|
if (optimiser.expressions.length > 0) {
|
|
135
134
|
context.state.template.push(
|
|
136
|
-
create_child_block(b.block([optimiser.apply(), ...state.init, statement])
|
|
135
|
+
create_child_block(b.block([optimiser.apply(), ...state.init, statement]))
|
|
137
136
|
);
|
|
138
137
|
} else {
|
|
139
138
|
context.state.template.push(...state.init, statement);
|
|
@@ -186,7 +185,7 @@ export function RegularElement(node, context) {
|
|
|
186
185
|
|
|
187
186
|
if (optimiser.expressions.length > 0) {
|
|
188
187
|
context.state.template.push(
|
|
189
|
-
create_child_block(b.block([optimiser.apply(), ...state.init, statement])
|
|
188
|
+
create_child_block(b.block([optimiser.apply(), ...state.init, statement]))
|
|
190
189
|
);
|
|
191
190
|
} else {
|
|
192
191
|
context.state.template.push(...state.init, statement);
|
|
@@ -236,18 +235,19 @@ export function RegularElement(node, context) {
|
|
|
236
235
|
}
|
|
237
236
|
|
|
238
237
|
if (optimiser.is_async()) {
|
|
239
|
-
let
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
238
|
+
let statements = [...state.init, ...build_template(state.template)];
|
|
239
|
+
|
|
240
|
+
if (optimiser.has_await) {
|
|
241
|
+
statements = [create_child_block(b.block([optimiser.apply(), ...statements]))];
|
|
242
|
+
}
|
|
243
243
|
|
|
244
244
|
const blockers = optimiser.blockers();
|
|
245
245
|
|
|
246
246
|
if (blockers.elements.length > 0) {
|
|
247
|
-
|
|
247
|
+
statements = [create_async_block(b.block(statements), blockers, false, false)];
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
-
context.state.template.push(
|
|
250
|
+
context.state.template.push(...statements);
|
|
251
251
|
} else {
|
|
252
252
|
context.state.init.push(...state.init);
|
|
253
253
|
context.state.template.push(...state.template);
|
|
@@ -79,7 +79,7 @@ export function SvelteElement(node, context) {
|
|
|
79
79
|
);
|
|
80
80
|
|
|
81
81
|
if (optimiser.expressions.length > 0) {
|
|
82
|
-
statement = create_child_block(b.block([optimiser.apply(), statement])
|
|
82
|
+
statement = create_child_block(b.block([optimiser.apply(), statement]));
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
statements.push(statement);
|
|
@@ -264,11 +264,10 @@ export function build_getter(node, state) {
|
|
|
264
264
|
/**
|
|
265
265
|
* Creates a `$$renderer.child(...)` expression statement
|
|
266
266
|
* @param {BlockStatement | Expression} body
|
|
267
|
-
* @param {boolean} async
|
|
268
267
|
* @returns {Statement}
|
|
269
268
|
*/
|
|
270
|
-
export function create_child_block(body
|
|
271
|
-
return b.stmt(b.call('$$renderer.child', b.arrow([b.id('$$renderer')], body,
|
|
269
|
+
export function create_child_block(body) {
|
|
270
|
+
return b.stmt(b.call('$$renderer.child', b.arrow([b.id('$$renderer')], body, true)));
|
|
272
271
|
}
|
|
273
272
|
|
|
274
273
|
/**
|
|
@@ -115,57 +115,17 @@ function base_element(node, context) {
|
|
|
115
115
|
const is_doctype_node = node.name.toLowerCase() === '!doctype';
|
|
116
116
|
const is_self_closing =
|
|
117
117
|
is_void(node.name) || (node.type === 'Component' && node.fragment.nodes.length === 0);
|
|
118
|
-
let multiline_content = false;
|
|
119
118
|
|
|
120
119
|
if (is_doctype_node) child_context.write(`>`);
|
|
121
120
|
else if (is_self_closing) {
|
|
122
121
|
child_context.write(`${multiline_attributes ? '' : ' '}/>`);
|
|
123
122
|
} else {
|
|
124
123
|
child_context.write('>');
|
|
125
|
-
|
|
126
|
-
// Process the element's content in a separate context for measurement
|
|
127
|
-
const content_context = child_context.new();
|
|
128
|
-
const allow_inline_content = child_context.measure() < LINE_BREAK_THRESHOLD;
|
|
129
|
-
block(content_context, node.fragment, allow_inline_content);
|
|
130
|
-
|
|
131
|
-
// Determine if content should be formatted on multiple lines
|
|
132
|
-
multiline_content = content_context.measure() > LINE_BREAK_THRESHOLD;
|
|
133
|
-
|
|
134
|
-
if (multiline_content) {
|
|
135
|
-
child_context.newline();
|
|
136
|
-
|
|
137
|
-
// Only indent if attributes are inline and content itself isn't already multiline
|
|
138
|
-
const should_indent = !multiline_attributes && !content_context.multiline;
|
|
139
|
-
if (should_indent) {
|
|
140
|
-
child_context.indent();
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
child_context.append(content_context);
|
|
144
|
-
|
|
145
|
-
if (should_indent) {
|
|
146
|
-
child_context.dedent();
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
child_context.newline();
|
|
150
|
-
} else {
|
|
151
|
-
child_context.append(content_context);
|
|
152
|
-
}
|
|
153
|
-
|
|
124
|
+
block(child_context, node.fragment, true);
|
|
154
125
|
child_context.write(`</${node.name}>`);
|
|
155
126
|
}
|
|
156
127
|
|
|
157
|
-
const break_line_after = child_context.measure() > LINE_BREAK_THRESHOLD;
|
|
158
|
-
|
|
159
|
-
if ((multiline_content || multiline_attributes) && !context.empty()) {
|
|
160
|
-
context.newline();
|
|
161
|
-
}
|
|
162
|
-
|
|
163
128
|
context.append(child_context);
|
|
164
|
-
|
|
165
|
-
if (is_self_closing) return;
|
|
166
|
-
if (multiline_content || multiline_attributes || break_line_after) {
|
|
167
|
-
context.newline();
|
|
168
|
-
}
|
|
169
129
|
}
|
|
170
130
|
|
|
171
131
|
/** @type {Visitors<AST.SvelteNode>} */
|
|
@@ -412,6 +372,8 @@ const svelte_visitors = {
|
|
|
412
372
|
}
|
|
413
373
|
} else {
|
|
414
374
|
sequence.push(child_node);
|
|
375
|
+
|
|
376
|
+
if (child_node.type === 'RegularElement') flush();
|
|
415
377
|
}
|
|
416
378
|
}
|
|
417
379
|
|
|
@@ -420,18 +382,20 @@ const svelte_visitors = {
|
|
|
420
382
|
let multiline = false;
|
|
421
383
|
let width = 0;
|
|
422
384
|
|
|
423
|
-
const child_contexts = items
|
|
424
|
-
|
|
385
|
+
const child_contexts = items
|
|
386
|
+
.filter((x) => x.length > 0)
|
|
387
|
+
.map((sequence) => {
|
|
388
|
+
const child_context = context.new();
|
|
425
389
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
390
|
+
for (const node of sequence) {
|
|
391
|
+
child_context.visit(node);
|
|
392
|
+
multiline ||= child_context.multiline;
|
|
393
|
+
}
|
|
430
394
|
|
|
431
|
-
|
|
395
|
+
width += child_context.measure();
|
|
432
396
|
|
|
433
|
-
|
|
434
|
-
|
|
397
|
+
return child_context;
|
|
398
|
+
});
|
|
435
399
|
|
|
436
400
|
multiline ||= width > LINE_BREAK_THRESHOLD;
|
|
437
401
|
|
|
@@ -200,17 +200,17 @@ export class BranchManager {
|
|
|
200
200
|
if (defer) {
|
|
201
201
|
for (const [k, effect] of this.#onscreen) {
|
|
202
202
|
if (k === key) {
|
|
203
|
-
batch.
|
|
203
|
+
batch.unskip_effect(effect);
|
|
204
204
|
} else {
|
|
205
|
-
batch.
|
|
205
|
+
batch.skip_effect(effect);
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
for (const [k, branch] of this.#offscreen) {
|
|
210
210
|
if (k === key) {
|
|
211
|
-
batch.
|
|
211
|
+
batch.unskip_effect(branch.effect);
|
|
212
212
|
} else {
|
|
213
|
-
batch.
|
|
213
|
+
batch.skip_effect(branch.effect);
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
|
|
@@ -257,7 +257,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
|
|
|
257
257
|
if (item.i) internal_set(item.i, index);
|
|
258
258
|
|
|
259
259
|
if (defer) {
|
|
260
|
-
batch.
|
|
260
|
+
batch.unskip_effect(item.e);
|
|
261
261
|
}
|
|
262
262
|
} else {
|
|
263
263
|
item = create_item(
|
|
@@ -299,7 +299,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
|
|
|
299
299
|
if (defer) {
|
|
300
300
|
for (const [key, item] of items) {
|
|
301
301
|
if (!keys.has(key)) {
|
|
302
|
-
batch.
|
|
302
|
+
batch.skip_effect(item.e);
|
|
303
303
|
}
|
|
304
304
|
}
|
|
305
305
|
|
|
@@ -122,6 +122,10 @@ export function child(node, is_text) {
|
|
|
122
122
|
return text;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
if (is_text) {
|
|
126
|
+
merge_text_nodes(/** @type {Text} */ (child));
|
|
127
|
+
}
|
|
128
|
+
|
|
125
129
|
set_hydrate_node(child);
|
|
126
130
|
return child;
|
|
127
131
|
}
|
|
@@ -142,14 +146,18 @@ export function first_child(node, is_text = false) {
|
|
|
142
146
|
return first;
|
|
143
147
|
}
|
|
144
148
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
+
if (is_text) {
|
|
150
|
+
// if an {expression} is empty during SSR, there might be no
|
|
151
|
+
// text node to hydrate — we must therefore create one
|
|
152
|
+
if (hydrate_node?.nodeType !== TEXT_NODE) {
|
|
153
|
+
var text = create_text();
|
|
149
154
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
155
|
+
hydrate_node?.before(text);
|
|
156
|
+
set_hydrate_node(text);
|
|
157
|
+
return text;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
merge_text_nodes(/** @type {Text} */ (hydrate_node));
|
|
153
161
|
}
|
|
154
162
|
|
|
155
163
|
return hydrate_node;
|
|
@@ -175,20 +183,24 @@ export function sibling(node, count = 1, is_text = false) {
|
|
|
175
183
|
return next_sibling;
|
|
176
184
|
}
|
|
177
185
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
if (is_text) {
|
|
187
|
+
// if a sibling {expression} is empty during SSR, there might be no
|
|
188
|
+
// text node to hydrate — we must therefore create one
|
|
189
|
+
if (next_sibling?.nodeType !== TEXT_NODE) {
|
|
190
|
+
var text = create_text();
|
|
191
|
+
// If the next sibling is `null` and we're handling text then it's because
|
|
192
|
+
// the SSR content was empty for the text, so we need to generate a new text
|
|
193
|
+
// node and insert it after the last sibling
|
|
194
|
+
if (next_sibling === null) {
|
|
195
|
+
last_sibling?.after(text);
|
|
196
|
+
} else {
|
|
197
|
+
next_sibling.before(text);
|
|
198
|
+
}
|
|
199
|
+
set_hydrate_node(text);
|
|
200
|
+
return text;
|
|
189
201
|
}
|
|
190
|
-
|
|
191
|
-
|
|
202
|
+
|
|
203
|
+
merge_text_nodes(/** @type {Text} */ (next_sibling));
|
|
192
204
|
}
|
|
193
205
|
|
|
194
206
|
set_hydrate_node(next_sibling);
|
|
@@ -258,3 +270,24 @@ export function set_attribute(element, key, value = '') {
|
|
|
258
270
|
}
|
|
259
271
|
return element.setAttribute(key, value);
|
|
260
272
|
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Browsers split text nodes larger than 65536 bytes when parsing.
|
|
276
|
+
* For hydration to succeed, we need to stitch them back together
|
|
277
|
+
* @param {Text} text
|
|
278
|
+
*/
|
|
279
|
+
export function merge_text_nodes(text) {
|
|
280
|
+
if (/** @type {string} */ (text.nodeValue).length < 65536) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
let next = text.nextSibling;
|
|
285
|
+
|
|
286
|
+
while (next !== null && next.nodeType === TEXT_NODE) {
|
|
287
|
+
next.remove();
|
|
288
|
+
|
|
289
|
+
/** @type {string} */ (text.nodeValue) += /** @type {string} */ (next.nodeValue);
|
|
290
|
+
|
|
291
|
+
next = text.nextSibling;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
@@ -4,11 +4,13 @@ import { hydrate_next, hydrate_node, hydrating, set_hydrate_node } from './hydra
|
|
|
4
4
|
import {
|
|
5
5
|
create_text,
|
|
6
6
|
get_first_child,
|
|
7
|
+
get_next_sibling,
|
|
7
8
|
is_firefox,
|
|
8
9
|
create_element,
|
|
9
10
|
create_fragment,
|
|
10
11
|
create_comment,
|
|
11
|
-
set_attribute
|
|
12
|
+
set_attribute,
|
|
13
|
+
merge_text_nodes
|
|
12
14
|
} from './operations.js';
|
|
13
15
|
import { create_fragment_from_html } from './reconciler.js';
|
|
14
16
|
import { active_effect } from '../runtime.js';
|
|
@@ -310,6 +312,8 @@ export function text(value = '') {
|
|
|
310
312
|
// if an {expression} is empty during SSR, we need to insert an empty text node
|
|
311
313
|
node.before((node = create_text()));
|
|
312
314
|
set_hydrate_node(node);
|
|
315
|
+
} else {
|
|
316
|
+
merge_text_nodes(/** @type {Text} */ (node));
|
|
313
317
|
}
|
|
314
318
|
|
|
315
319
|
assign_nodes(node, node);
|