svelte 5.42.2 → 5.43.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/package.json +1 -1
- package/src/compiler/phases/2-analyze/index.js +201 -2
- package/src/compiler/phases/2-analyze/visitors/AwaitExpression.js +6 -6
- package/src/compiler/phases/2-analyze/visitors/BindDirective.js +1 -0
- package/src/compiler/phases/2-analyze/visitors/SnippetBlock.js +6 -1
- package/src/compiler/phases/3-transform/client/transform-client.js +13 -34
- package/src/compiler/phases/3-transform/client/visitors/BindDirective.js +18 -7
- package/src/compiler/phases/3-transform/client/visitors/CallExpression.js +2 -2
- package/src/compiler/phases/3-transform/client/visitors/EachBlock.js +6 -4
- package/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js +1 -1
- package/src/compiler/phases/3-transform/client/visitors/HtmlTag.js +6 -4
- package/src/compiler/phases/3-transform/client/visitors/IfBlock.js +6 -4
- package/src/compiler/phases/3-transform/client/visitors/KeyBlock.js +5 -4
- package/src/compiler/phases/3-transform/client/visitors/Program.js +15 -3
- package/src/compiler/phases/3-transform/client/visitors/RenderTag.js +6 -4
- package/src/compiler/phases/3-transform/client/visitors/SlotElement.js +3 -1
- package/src/compiler/phases/3-transform/client/visitors/SvelteElement.js +5 -4
- package/src/compiler/phases/3-transform/client/visitors/SvelteHead.js +3 -0
- package/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +13 -2
- package/src/compiler/phases/3-transform/client/visitors/shared/component.js +20 -16
- package/src/compiler/phases/3-transform/client/visitors/shared/element.js +1 -0
- package/src/compiler/phases/3-transform/client/visitors/shared/utils.js +15 -1
- package/src/compiler/phases/3-transform/server/transform-server.js +9 -9
- package/src/compiler/phases/3-transform/server/visitors/AwaitBlock.js +6 -2
- package/src/compiler/phases/3-transform/server/visitors/CallExpression.js +8 -1
- package/src/compiler/phases/3-transform/server/visitors/EachBlock.js +14 -3
- package/src/compiler/phases/3-transform/server/visitors/HtmlTag.js +3 -5
- package/src/compiler/phases/3-transform/server/visitors/IfBlock.js +12 -4
- package/src/compiler/phases/3-transform/server/visitors/KeyBlock.js +7 -1
- package/src/compiler/phases/3-transform/server/visitors/Program.js +25 -0
- package/src/compiler/phases/3-transform/server/visitors/RegularElement.js +14 -7
- package/src/compiler/phases/3-transform/server/visitors/RenderTag.js +27 -11
- package/src/compiler/phases/3-transform/server/visitors/SlotElement.js +7 -4
- package/src/compiler/phases/3-transform/server/visitors/SvelteElement.js +24 -4
- package/src/compiler/phases/3-transform/server/visitors/SvelteHead.js +10 -1
- package/src/compiler/phases/3-transform/server/visitors/shared/component.js +10 -4
- package/src/compiler/phases/3-transform/server/visitors/shared/utils.js +79 -8
- package/src/compiler/phases/3-transform/shared/transform-async.js +102 -0
- package/src/compiler/phases/nodes.js +24 -0
- package/src/compiler/phases/scope.js +27 -8
- package/src/compiler/utils/ast.js +1 -1
- package/src/compiler/utils/builders.js +15 -4
- package/src/internal/client/dom/blocks/async.js +7 -6
- package/src/internal/client/dom/blocks/await.js +6 -2
- package/src/internal/client/dom/blocks/boundary.js +5 -8
- package/src/internal/client/dom/blocks/svelte-head.js +10 -19
- package/src/internal/client/dom/elements/attributes.js +3 -1
- package/src/internal/client/index.js +1 -0
- package/src/internal/client/proxy.js +1 -1
- package/src/internal/client/reactivity/async.js +107 -49
- package/src/internal/client/reactivity/batch.js +2 -15
- package/src/internal/client/reactivity/effects.js +3 -2
- package/src/internal/client/render.js +1 -9
- package/src/internal/client/runtime.js +12 -11
- package/src/internal/server/index.js +4 -3
- package/src/internal/server/renderer.js +58 -3
- package/src/version.js +1 -1
- package/types/index.d.ts.map +1 -1
- package/src/compiler/phases/3-transform/client/visitors/ImportDeclaration.js +0 -16
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
/** @import { AST } from '#compiler' */
|
|
3
3
|
/** @import { ComponentContext } from '../types' */
|
|
4
4
|
import * as b from '#compiler/builders';
|
|
5
|
+
import { hash } from '../../../../../utils.js';
|
|
6
|
+
import { filename } from '../../../../state.js';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* @param {AST.SvelteHead} node
|
|
@@ -13,6 +15,7 @@ export function SvelteHead(node, context) {
|
|
|
13
15
|
b.stmt(
|
|
14
16
|
b.call(
|
|
15
17
|
'$.head',
|
|
18
|
+
b.literal(hash(filename)),
|
|
16
19
|
b.arrow([b.id('$$anchor')], /** @type {BlockStatement} */ (context.visit(node.fragment)))
|
|
17
20
|
)
|
|
18
21
|
)
|
|
@@ -193,18 +193,25 @@ export function VariableDeclaration(node, context) {
|
|
|
193
193
|
/** @type {CallExpression} */ (init)
|
|
194
194
|
);
|
|
195
195
|
|
|
196
|
+
// for now, only wrap async derived in $.save if it's not
|
|
197
|
+
// a top-level instance derived. TODO in future maybe we
|
|
198
|
+
// can dewaterfall all of them?
|
|
199
|
+
const should_save = context.state.is_instance && context.state.scope.function_depth > 1;
|
|
200
|
+
|
|
196
201
|
if (declarator.id.type === 'Identifier') {
|
|
197
202
|
let expression = /** @type {Expression} */ (context.visit(value));
|
|
198
203
|
|
|
199
204
|
if (is_async) {
|
|
200
205
|
const location = dev && !is_ignored(init, 'await_waterfall') && locate_node(init);
|
|
206
|
+
|
|
207
|
+
/** @type {Expression} */
|
|
201
208
|
let call = b.call(
|
|
202
209
|
'$.async_derived',
|
|
203
210
|
b.thunk(expression, true),
|
|
204
211
|
location ? b.literal(location) : undefined
|
|
205
212
|
);
|
|
206
213
|
|
|
207
|
-
call = save(call);
|
|
214
|
+
call = should_save ? save(call) : b.await(call);
|
|
208
215
|
if (dev) call = b.call('$.tag', call, b.literal(declarator.id.name));
|
|
209
216
|
|
|
210
217
|
declarations.push(b.declarator(declarator.id, call));
|
|
@@ -224,18 +231,22 @@ export function VariableDeclaration(node, context) {
|
|
|
224
231
|
|
|
225
232
|
if (rune !== '$derived' || init.arguments[0].type !== 'Identifier') {
|
|
226
233
|
const id = b.id(context.state.scope.generate('$$d'));
|
|
234
|
+
|
|
235
|
+
/** @type {Expression} */
|
|
227
236
|
let call = b.call('$.derived', rune === '$derived' ? b.thunk(expression) : expression);
|
|
228
237
|
|
|
229
238
|
rhs = b.call('$.get', id);
|
|
230
239
|
|
|
231
240
|
if (is_async) {
|
|
232
241
|
const location = dev && !is_ignored(init, 'await_waterfall') && locate_node(init);
|
|
242
|
+
|
|
233
243
|
call = b.call(
|
|
234
244
|
'$.async_derived',
|
|
235
245
|
b.thunk(expression, true),
|
|
236
246
|
location ? b.literal(location) : undefined
|
|
237
247
|
);
|
|
238
|
-
|
|
248
|
+
|
|
249
|
+
call = should_save ? save(call) : b.await(call);
|
|
239
250
|
}
|
|
240
251
|
|
|
241
252
|
if (dev) {
|
|
@@ -16,12 +16,12 @@ import { determine_slot } from '../../../../../utils/slot.js';
|
|
|
16
16
|
* @returns {Statement}
|
|
17
17
|
*/
|
|
18
18
|
export function build_component(node, component_name, context) {
|
|
19
|
-
/**
|
|
20
|
-
* @type {Expression}
|
|
21
|
-
*/
|
|
19
|
+
/** @type {Expression} */
|
|
22
20
|
const anchor = context.state.node;
|
|
21
|
+
|
|
23
22
|
/** @type {Array<Property[] | Expression>} */
|
|
24
23
|
const props_and_spreads = [];
|
|
24
|
+
|
|
25
25
|
/** @type {Array<() => void>} */
|
|
26
26
|
const delayed_props = [];
|
|
27
27
|
|
|
@@ -129,14 +129,16 @@ export function build_component(node, component_name, context) {
|
|
|
129
129
|
(events[attribute.name] ||= []).push(handler);
|
|
130
130
|
} else if (attribute.type === 'SpreadAttribute') {
|
|
131
131
|
const expression = /** @type {Expression} */ (context.visit(attribute));
|
|
132
|
+
const memoized_expression = memoizer.add(expression, attribute.metadata.expression);
|
|
133
|
+
const is_memoized = expression !== memoized_expression;
|
|
132
134
|
|
|
133
|
-
if (
|
|
135
|
+
if (
|
|
136
|
+
is_memoized ||
|
|
137
|
+
attribute.metadata.expression.has_state ||
|
|
138
|
+
attribute.metadata.expression.has_await
|
|
139
|
+
) {
|
|
134
140
|
props_and_spreads.push(
|
|
135
|
-
b.thunk(
|
|
136
|
-
attribute.metadata.expression.has_await || attribute.metadata.expression.has_call
|
|
137
|
-
? b.call('$.get', memoizer.add(expression, attribute.metadata.expression))
|
|
138
|
-
: expression
|
|
139
|
-
)
|
|
141
|
+
b.thunk(is_memoized ? b.call('$.get', memoized_expression) : expression)
|
|
140
142
|
);
|
|
141
143
|
} else {
|
|
142
144
|
props_and_spreads.push(expression);
|
|
@@ -147,10 +149,10 @@ export function build_component(node, component_name, context) {
|
|
|
147
149
|
b.init(
|
|
148
150
|
attribute.name,
|
|
149
151
|
build_attribute_value(attribute.value, context, (value, metadata) => {
|
|
152
|
+
const memoized = memoizer.add(value, metadata);
|
|
153
|
+
|
|
150
154
|
// TODO put the derived in the local block
|
|
151
|
-
return
|
|
152
|
-
? b.call('$.get', memoizer.add(value, metadata))
|
|
153
|
-
: value;
|
|
155
|
+
return value !== memoized ? b.call('$.get', memoized) : value;
|
|
154
156
|
}).value
|
|
155
157
|
)
|
|
156
158
|
);
|
|
@@ -184,9 +186,9 @@ export function build_component(node, component_name, context) {
|
|
|
184
186
|
);
|
|
185
187
|
});
|
|
186
188
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
189
|
+
const memoized = memoizer.add(value, metadata, should_wrap_in_derived);
|
|
190
|
+
|
|
191
|
+
return value !== memoized ? b.call('$.get', memoized) : value;
|
|
190
192
|
}
|
|
191
193
|
);
|
|
192
194
|
|
|
@@ -497,12 +499,14 @@ export function build_component(node, component_name, context) {
|
|
|
497
499
|
memoizer.apply();
|
|
498
500
|
|
|
499
501
|
const async_values = memoizer.async_values();
|
|
502
|
+
const blockers = memoizer.blockers();
|
|
500
503
|
|
|
501
|
-
if (async_values) {
|
|
504
|
+
if (async_values || blockers) {
|
|
502
505
|
return b.stmt(
|
|
503
506
|
b.call(
|
|
504
507
|
'$.async',
|
|
505
508
|
anchor,
|
|
509
|
+
blockers,
|
|
506
510
|
async_values,
|
|
507
511
|
b.arrow([b.id('$$anchor'), ...memoizer.async_ids()], b.block(statements))
|
|
508
512
|
)
|
|
@@ -89,6 +89,7 @@ export function build_attribute_effect(
|
|
|
89
89
|
b.arrow(ids, b.object(values)),
|
|
90
90
|
memoizer.sync_values(),
|
|
91
91
|
memoizer.async_values(),
|
|
92
|
+
memoizer.blockers(),
|
|
92
93
|
element.metadata.scoped &&
|
|
93
94
|
context.state.analysis.css.hash !== '' &&
|
|
94
95
|
b.literal(context.state.analysis.css.hash),
|
|
@@ -22,12 +22,21 @@ export class Memoizer {
|
|
|
22
22
|
/** @type {Array<{ id: Identifier, expression: Expression }>} */
|
|
23
23
|
#async = [];
|
|
24
24
|
|
|
25
|
+
/** @type {Set<Expression>} */
|
|
26
|
+
#blockers = new Set();
|
|
27
|
+
|
|
25
28
|
/**
|
|
26
29
|
* @param {Expression} expression
|
|
27
30
|
* @param {ExpressionMetadata} metadata
|
|
28
31
|
* @param {boolean} memoize_if_state
|
|
29
32
|
*/
|
|
30
33
|
add(expression, metadata, memoize_if_state = false) {
|
|
34
|
+
for (const binding of metadata.dependencies) {
|
|
35
|
+
if (binding.blocker) {
|
|
36
|
+
this.#blockers.add(binding.blocker);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
31
40
|
const should_memoize =
|
|
32
41
|
metadata.has_call || metadata.has_await || (memoize_if_state && metadata.has_state);
|
|
33
42
|
|
|
@@ -50,6 +59,10 @@ export class Memoizer {
|
|
|
50
59
|
});
|
|
51
60
|
}
|
|
52
61
|
|
|
62
|
+
blockers() {
|
|
63
|
+
return this.#blockers.size > 0 ? b.array([...this.#blockers]) : undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
53
66
|
deriveds(runes = true) {
|
|
54
67
|
return this.#sync.map((memo) =>
|
|
55
68
|
b.let(memo.id, b.call(runes ? '$.derived' : '$.derived_safe_equal', b.thunk(memo.expression)))
|
|
@@ -185,7 +198,8 @@ export function build_render_statement(state) {
|
|
|
185
198
|
: b.block(state.update)
|
|
186
199
|
),
|
|
187
200
|
memoizer.sync_values(),
|
|
188
|
-
memoizer.async_values()
|
|
201
|
+
memoizer.async_values(),
|
|
202
|
+
memoizer.blockers()
|
|
189
203
|
)
|
|
190
204
|
);
|
|
191
205
|
}
|
|
@@ -25,6 +25,7 @@ import { IfBlock } from './visitors/IfBlock.js';
|
|
|
25
25
|
import { KeyBlock } from './visitors/KeyBlock.js';
|
|
26
26
|
import { LabeledStatement } from './visitors/LabeledStatement.js';
|
|
27
27
|
import { MemberExpression } from './visitors/MemberExpression.js';
|
|
28
|
+
import { Program } from './visitors/Program.js';
|
|
28
29
|
import { PropertyDefinition } from './visitors/PropertyDefinition.js';
|
|
29
30
|
import { RegularElement } from './visitors/RegularElement.js';
|
|
30
31
|
import { RenderTag } from './visitors/RenderTag.js';
|
|
@@ -40,7 +41,7 @@ import { TitleElement } from './visitors/TitleElement.js';
|
|
|
40
41
|
import { UpdateExpression } from './visitors/UpdateExpression.js';
|
|
41
42
|
import { VariableDeclaration } from './visitors/VariableDeclaration.js';
|
|
42
43
|
import { SvelteBoundary } from './visitors/SvelteBoundary.js';
|
|
43
|
-
import { call_component_renderer
|
|
44
|
+
import { call_component_renderer } from './visitors/shared/utils.js';
|
|
44
45
|
|
|
45
46
|
/** @type {Visitors} */
|
|
46
47
|
const global_visitors = {
|
|
@@ -53,6 +54,7 @@ const global_visitors = {
|
|
|
53
54
|
Identifier,
|
|
54
55
|
LabeledStatement,
|
|
55
56
|
MemberExpression,
|
|
57
|
+
Program,
|
|
56
58
|
PropertyDefinition,
|
|
57
59
|
UpdateExpression,
|
|
58
60
|
VariableDeclaration
|
|
@@ -95,7 +97,7 @@ export function server_component(analysis, options) {
|
|
|
95
97
|
options,
|
|
96
98
|
scope: analysis.module.scope,
|
|
97
99
|
scopes: analysis.module.scopes,
|
|
98
|
-
hoisted: [b.import_all('$', 'svelte/internal/server')],
|
|
100
|
+
hoisted: [b.import_all('$', 'svelte/internal/server'), ...analysis.instance_body.hoisted],
|
|
99
101
|
legacy_reactive_statements: new Map(),
|
|
100
102
|
// these are set inside the `Fragment` visitor, and cannot be used until then
|
|
101
103
|
init: /** @type {any} */ (null),
|
|
@@ -103,7 +105,8 @@ export function server_component(analysis, options) {
|
|
|
103
105
|
namespace: options.namespace,
|
|
104
106
|
preserve_whitespace: options.preserveWhitespace,
|
|
105
107
|
state_fields: new Map(),
|
|
106
|
-
skip_hydration_boundaries: false
|
|
108
|
+
skip_hydration_boundaries: false,
|
|
109
|
+
is_instance: false
|
|
107
110
|
};
|
|
108
111
|
|
|
109
112
|
const module = /** @type {ESTree.Program} */ (
|
|
@@ -113,7 +116,7 @@ export function server_component(analysis, options) {
|
|
|
113
116
|
const instance = /** @type {ESTree.Program} */ (
|
|
114
117
|
walk(
|
|
115
118
|
/** @type {AST.SvelteNode} */ (analysis.instance.ast),
|
|
116
|
-
{ ...state, scopes: analysis.instance.scopes },
|
|
119
|
+
{ ...state, scopes: analysis.instance.scopes, is_instance: true },
|
|
117
120
|
{
|
|
118
121
|
...global_visitors,
|
|
119
122
|
ImportDeclaration(node) {
|
|
@@ -243,10 +246,6 @@ export function server_component(analysis, options) {
|
|
|
243
246
|
.../** @type {ESTree.Statement[]} */ (template.body)
|
|
244
247
|
]);
|
|
245
248
|
|
|
246
|
-
if (analysis.instance.has_await) {
|
|
247
|
-
component_block = b.block([create_async_block(component_block)]);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
249
|
// trick esrap into including comments
|
|
251
250
|
component_block.loc = instance.loc;
|
|
252
251
|
|
|
@@ -408,7 +407,8 @@ export function server_module(analysis, options) {
|
|
|
408
407
|
// to be present for `javascript_visitors_legacy` and so is included in module
|
|
409
408
|
// transform state as well as component transform state
|
|
410
409
|
legacy_reactive_statements: new Map(),
|
|
411
|
-
state_fields: new Map()
|
|
410
|
+
state_fields: new Map(),
|
|
411
|
+
is_instance: false
|
|
412
412
|
};
|
|
413
413
|
|
|
414
414
|
const module = /** @type {ESTree.Program} */ (
|
|
@@ -25,8 +25,12 @@ export function AwaitBlock(node, context) {
|
|
|
25
25
|
)
|
|
26
26
|
);
|
|
27
27
|
|
|
28
|
-
if (node.metadata.expression.
|
|
29
|
-
statement = create_async_block(
|
|
28
|
+
if (node.metadata.expression.is_async()) {
|
|
29
|
+
statement = create_async_block(
|
|
30
|
+
b.block([statement]),
|
|
31
|
+
node.metadata.expression.blockers(),
|
|
32
|
+
node.metadata.expression.has_await
|
|
33
|
+
);
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
context.state.template.push(statement, block_close);
|
|
@@ -12,7 +12,14 @@ import { get_inspect_args } from '../../utils.js';
|
|
|
12
12
|
export function CallExpression(node, context) {
|
|
13
13
|
const rune = get_rune(node, context.state.scope);
|
|
14
14
|
|
|
15
|
-
if (
|
|
15
|
+
if (
|
|
16
|
+
rune === '$host' ||
|
|
17
|
+
rune === '$effect' ||
|
|
18
|
+
rune === '$effect.pre' ||
|
|
19
|
+
rune === '$inspect.trace'
|
|
20
|
+
) {
|
|
21
|
+
// we will only encounter `$effect` etc if they are top-level statements in the <script>
|
|
22
|
+
// following an `await`, otherwise they are removed by the ExpressionStatement visitor
|
|
16
23
|
return b.void0;
|
|
17
24
|
}
|
|
18
25
|
|
|
@@ -34,7 +34,11 @@ export function EachBlock(node, context) {
|
|
|
34
34
|
|
|
35
35
|
const new_body = /** @type {BlockStatement} */ (context.visit(node.body)).body;
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
if (node.body)
|
|
38
|
+
each.push(
|
|
39
|
+
// TODO get rid of fragment.has_await
|
|
40
|
+
...(node.body.metadata.has_await ? [create_async_block(b.block(new_body))] : new_body)
|
|
41
|
+
);
|
|
38
42
|
|
|
39
43
|
const for_loop = b.for(
|
|
40
44
|
b.declaration('let', [
|
|
@@ -65,8 +69,15 @@ export function EachBlock(node, context) {
|
|
|
65
69
|
block.body.push(for_loop);
|
|
66
70
|
}
|
|
67
71
|
|
|
68
|
-
if (node.metadata.expression.
|
|
69
|
-
state.template.push(
|
|
72
|
+
if (node.metadata.expression.is_async()) {
|
|
73
|
+
state.template.push(
|
|
74
|
+
create_async_block(
|
|
75
|
+
block,
|
|
76
|
+
node.metadata.expression.blockers(),
|
|
77
|
+
node.metadata.expression.has_await
|
|
78
|
+
),
|
|
79
|
+
block_close
|
|
80
|
+
);
|
|
70
81
|
} else {
|
|
71
82
|
state.template.push(...block.body, block_close);
|
|
72
83
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
/** @import { AST } from '#compiler' */
|
|
3
3
|
/** @import { ComponentContext } from '../types.js' */
|
|
4
4
|
import * as b from '#compiler/builders';
|
|
5
|
+
import { create_push } from './shared/utils.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* @param {AST.HtmlTag} node
|
|
@@ -10,9 +11,6 @@ import * as b from '#compiler/builders';
|
|
|
10
11
|
export function HtmlTag(node, context) {
|
|
11
12
|
const expression = /** @type {Expression} */ (context.visit(node.expression));
|
|
12
13
|
const call = b.call('$.html', expression);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
? b.stmt(b.call('$$renderer.push', b.thunk(call, true)))
|
|
16
|
-
: call
|
|
17
|
-
);
|
|
14
|
+
|
|
15
|
+
context.state.template.push(create_push(call, node.metadata.expression, true));
|
|
18
16
|
}
|
|
@@ -23,12 +23,20 @@ export function IfBlock(node, context) {
|
|
|
23
23
|
/** @type {Statement} */
|
|
24
24
|
let statement = b.if(test, consequent, alternate);
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
const is_async = node.metadata.expression.is_async();
|
|
27
|
+
|
|
28
|
+
const has_await =
|
|
27
29
|
node.metadata.expression.has_await ||
|
|
30
|
+
// TODO get rid of this stuff
|
|
28
31
|
node.consequent.metadata.has_await ||
|
|
29
|
-
node.alternate?.metadata.has_await
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
node.alternate?.metadata.has_await;
|
|
33
|
+
|
|
34
|
+
if (is_async || has_await) {
|
|
35
|
+
statement = create_async_block(
|
|
36
|
+
b.block([statement]),
|
|
37
|
+
node.metadata.expression.blockers(),
|
|
38
|
+
!!has_await
|
|
39
|
+
);
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
context.state.template.push(statement, block_close);
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
/** @import { BlockStatement } from 'estree' */
|
|
2
2
|
/** @import { AST } from '#compiler' */
|
|
3
3
|
/** @import { ComponentContext } from '../types.js' */
|
|
4
|
-
import { empty_comment } from './shared/utils.js';
|
|
4
|
+
import { block_close, block_open, empty_comment } from './shared/utils.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @param {AST.KeyBlock} node
|
|
8
8
|
* @param {ComponentContext} context
|
|
9
9
|
*/
|
|
10
10
|
export function KeyBlock(node, context) {
|
|
11
|
+
const is_async = node.metadata.expression.is_async();
|
|
12
|
+
|
|
13
|
+
if (is_async) context.state.template.push(block_open);
|
|
14
|
+
|
|
11
15
|
context.state.template.push(
|
|
12
16
|
empty_comment,
|
|
13
17
|
/** @type {BlockStatement} */ (context.visit(node.fragment)),
|
|
14
18
|
empty_comment
|
|
15
19
|
);
|
|
20
|
+
|
|
21
|
+
if (is_async) context.state.template.push(block_close);
|
|
16
22
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** @import { Node, Program } from 'estree' */
|
|
2
|
+
/** @import { Context, ComponentServerTransformState } from '../types' */
|
|
3
|
+
import * as b from '#compiler/builders';
|
|
4
|
+
import { transform_body } from '../../shared/transform-async.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {Program} node
|
|
8
|
+
* @param {Context} context
|
|
9
|
+
*/
|
|
10
|
+
export function Program(node, context) {
|
|
11
|
+
if (context.state.is_instance) {
|
|
12
|
+
const state = /** @type {ComponentServerTransformState} */ (context.state);
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
...node,
|
|
16
|
+
body: transform_body(
|
|
17
|
+
state.analysis.instance_body,
|
|
18
|
+
b.id('$$renderer.run'),
|
|
19
|
+
(node) => /** @type {Node} */ (context.visit(node))
|
|
20
|
+
)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
context.next();
|
|
25
|
+
}
|
|
@@ -12,7 +12,8 @@ import {
|
|
|
12
12
|
process_children,
|
|
13
13
|
build_template,
|
|
14
14
|
create_child_block,
|
|
15
|
-
PromiseOptimiser
|
|
15
|
+
PromiseOptimiser,
|
|
16
|
+
create_async_block
|
|
16
17
|
} from './shared/utils.js';
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -202,13 +203,19 @@ export function RegularElement(node, context) {
|
|
|
202
203
|
state.template.push(b.stmt(b.call('$.pop_element')));
|
|
203
204
|
}
|
|
204
205
|
|
|
205
|
-
if (optimiser.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
true
|
|
210
|
-
)
|
|
206
|
+
if (optimiser.is_async()) {
|
|
207
|
+
let statement = create_child_block(
|
|
208
|
+
b.block([optimiser.apply(), ...state.init, ...build_template(state.template)]),
|
|
209
|
+
true
|
|
211
210
|
);
|
|
211
|
+
|
|
212
|
+
const blockers = optimiser.blockers();
|
|
213
|
+
|
|
214
|
+
if (blockers.elements.length > 0) {
|
|
215
|
+
statement = create_async_block(b.block([statement]), blockers, false, false);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
context.state.template.push(statement);
|
|
212
219
|
} else {
|
|
213
220
|
context.state.init.push(...state.init);
|
|
214
221
|
context.state.template.push(...state.template);
|
|
@@ -3,32 +3,48 @@
|
|
|
3
3
|
/** @import { ComponentContext } from '../types.js' */
|
|
4
4
|
import { unwrap_optional } from '../../../../utils/ast.js';
|
|
5
5
|
import * as b from '#compiler/builders';
|
|
6
|
-
import { empty_comment } from './shared/utils.js';
|
|
6
|
+
import { create_async_block, empty_comment, PromiseOptimiser } from './shared/utils.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @param {AST.RenderTag} node
|
|
10
10
|
* @param {ComponentContext} context
|
|
11
11
|
*/
|
|
12
12
|
export function RenderTag(node, context) {
|
|
13
|
+
const optimiser = new PromiseOptimiser();
|
|
14
|
+
|
|
13
15
|
const callee = unwrap_optional(node.expression).callee;
|
|
14
16
|
const raw_args = unwrap_optional(node.expression).arguments;
|
|
15
17
|
|
|
16
|
-
const snippet_function =
|
|
18
|
+
const snippet_function = optimiser.transform(
|
|
19
|
+
/** @type {Expression} */ (context.visit(callee)),
|
|
20
|
+
node.metadata.expression
|
|
21
|
+
);
|
|
17
22
|
|
|
18
|
-
const snippet_args = raw_args.map((arg) => {
|
|
19
|
-
return
|
|
23
|
+
const snippet_args = raw_args.map((arg, i) => {
|
|
24
|
+
return optimiser.transform(
|
|
25
|
+
/** @type {Expression} */ (context.visit(arg)),
|
|
26
|
+
node.metadata.arguments[i]
|
|
27
|
+
);
|
|
20
28
|
});
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
b.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
...snippet_args
|
|
28
|
-
)
|
|
30
|
+
let statement = b.stmt(
|
|
31
|
+
(node.expression.type === 'CallExpression' ? b.call : b.maybe_call)(
|
|
32
|
+
snippet_function,
|
|
33
|
+
b.id('$$renderer'),
|
|
34
|
+
...snippet_args
|
|
29
35
|
)
|
|
30
36
|
);
|
|
31
37
|
|
|
38
|
+
if (optimiser.is_async()) {
|
|
39
|
+
statement = create_async_block(
|
|
40
|
+
b.block([optimiser.apply(), statement]),
|
|
41
|
+
optimiser.blockers(),
|
|
42
|
+
optimiser.has_await
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
context.state.template.push(statement);
|
|
47
|
+
|
|
32
48
|
if (!context.state.skip_hydration_boundaries) {
|
|
33
49
|
context.state.template.push(empty_comment);
|
|
34
50
|
}
|
|
@@ -65,10 +65,13 @@ export function SlotElement(node, context) {
|
|
|
65
65
|
fallback
|
|
66
66
|
);
|
|
67
67
|
|
|
68
|
-
const statement =
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
const statement = optimiser.is_async()
|
|
69
|
+
? create_async_block(
|
|
70
|
+
b.block([optimiser.apply(), b.stmt(slot)]),
|
|
71
|
+
optimiser.blockers(),
|
|
72
|
+
optimiser.has_await
|
|
73
|
+
)
|
|
74
|
+
: b.stmt(slot);
|
|
72
75
|
|
|
73
76
|
context.state.template.push(block_open, statement, block_close);
|
|
74
77
|
}
|
|
@@ -6,7 +6,12 @@ import { dev, locator } from '../../../../state.js';
|
|
|
6
6
|
import * as b from '#compiler/builders';
|
|
7
7
|
import { determine_namespace_for_children } from '../../utils.js';
|
|
8
8
|
import { build_element_attributes } from './shared/element.js';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
build_template,
|
|
11
|
+
create_async_block,
|
|
12
|
+
create_child_block,
|
|
13
|
+
PromiseOptimiser
|
|
14
|
+
} from './shared/utils.js';
|
|
10
15
|
|
|
11
16
|
/**
|
|
12
17
|
* @param {AST.SvelteElement} node
|
|
@@ -39,11 +44,14 @@ export function SvelteElement(node, context) {
|
|
|
39
44
|
|
|
40
45
|
const optimiser = new PromiseOptimiser();
|
|
41
46
|
|
|
47
|
+
/** @type {Statement[]} */
|
|
48
|
+
let statements = [];
|
|
49
|
+
|
|
42
50
|
build_element_attributes(node, { ...context, state }, optimiser.transform);
|
|
43
51
|
|
|
44
52
|
if (dev) {
|
|
45
53
|
const location = /** @type {Location} */ (locator(node.start));
|
|
46
|
-
|
|
54
|
+
statements.push(
|
|
47
55
|
b.stmt(
|
|
48
56
|
b.call(
|
|
49
57
|
'$.push_element',
|
|
@@ -74,9 +82,21 @@ export function SvelteElement(node, context) {
|
|
|
74
82
|
statement = create_child_block(b.block([optimiser.apply(), statement]), true);
|
|
75
83
|
}
|
|
76
84
|
|
|
77
|
-
|
|
85
|
+
statements.push(statement);
|
|
78
86
|
|
|
79
87
|
if (dev) {
|
|
80
|
-
|
|
88
|
+
statements.push(b.stmt(b.call('$.pop_element')));
|
|
81
89
|
}
|
|
90
|
+
|
|
91
|
+
if (node.metadata.expression.is_async()) {
|
|
92
|
+
statements = [
|
|
93
|
+
create_async_block(
|
|
94
|
+
b.block(statements),
|
|
95
|
+
node.metadata.expression.blockers(),
|
|
96
|
+
node.metadata.expression.has_await
|
|
97
|
+
)
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
context.state.template.push(...statements);
|
|
82
102
|
}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
/** @import { AST } from '#compiler' */
|
|
3
3
|
/** @import { ComponentContext } from '../types.js' */
|
|
4
4
|
import * as b from '#compiler/builders';
|
|
5
|
+
import { hash } from '../../../../../utils.js';
|
|
6
|
+
import { filename } from '../../../../state.js';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* @param {AST.SvelteHead} node
|
|
@@ -11,6 +13,13 @@ export function SvelteHead(node, context) {
|
|
|
11
13
|
const block = /** @type {BlockStatement} */ (context.visit(node.fragment));
|
|
12
14
|
|
|
13
15
|
context.state.template.push(
|
|
14
|
-
b.stmt(
|
|
16
|
+
b.stmt(
|
|
17
|
+
b.call(
|
|
18
|
+
'$.head',
|
|
19
|
+
b.literal(hash(filename)),
|
|
20
|
+
b.id('$$renderer'),
|
|
21
|
+
b.arrow([b.id('$$renderer')], block)
|
|
22
|
+
)
|
|
23
|
+
)
|
|
15
24
|
);
|
|
16
25
|
}
|
|
@@ -5,8 +5,7 @@ import {
|
|
|
5
5
|
empty_comment,
|
|
6
6
|
build_attribute_value,
|
|
7
7
|
create_async_block,
|
|
8
|
-
PromiseOptimiser
|
|
9
|
-
build_template
|
|
8
|
+
PromiseOptimiser
|
|
10
9
|
} from './utils.js';
|
|
11
10
|
import * as b from '#compiler/builders';
|
|
12
11
|
import { is_element_node } from '../../../../nodes.js';
|
|
@@ -323,8 +322,14 @@ export function build_inline_component(node, expression, context) {
|
|
|
323
322
|
);
|
|
324
323
|
}
|
|
325
324
|
|
|
326
|
-
|
|
327
|
-
|
|
325
|
+
const is_async = optimiser.is_async();
|
|
326
|
+
|
|
327
|
+
if (is_async) {
|
|
328
|
+
statement = create_async_block(
|
|
329
|
+
b.block([optimiser.apply(), statement]),
|
|
330
|
+
optimiser.blockers(),
|
|
331
|
+
optimiser.has_await
|
|
332
|
+
);
|
|
328
333
|
}
|
|
329
334
|
|
|
330
335
|
if (dynamic && custom_css_props.length === 0) {
|
|
@@ -334,6 +339,7 @@ export function build_inline_component(node, expression, context) {
|
|
|
334
339
|
context.state.template.push(statement);
|
|
335
340
|
|
|
336
341
|
if (
|
|
342
|
+
!is_async &&
|
|
337
343
|
!context.state.skip_hydration_boundaries &&
|
|
338
344
|
custom_css_props.length === 0 &&
|
|
339
345
|
optimiser.expressions.length === 0
|