ripple 0.3.128 → 0.4.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/CHANGELOG.md +267 -0
- package/package.json +10 -4
- package/src/runtime/element.js +23 -6
- package/src/runtime/index-client.js +81 -41
- package/src/runtime/index-server.js +1 -0
- package/src/runtime/internal/client/blocks.js +173 -91
- package/src/runtime/internal/client/component.js +4 -30
- package/src/runtime/internal/client/composite.js +12 -13
- package/src/runtime/internal/client/constants.js +9 -0
- package/src/runtime/internal/client/context.js +12 -19
- package/src/runtime/internal/client/css.js +7 -9
- package/src/runtime/internal/client/events.js +178 -90
- package/src/runtime/internal/client/expression.js +45 -25
- package/src/runtime/internal/client/for.js +409 -129
- package/src/runtime/internal/client/head.js +10 -5
- package/src/runtime/internal/client/html.js +1 -0
- package/src/runtime/internal/client/hydration.js +152 -10
- package/src/runtime/internal/client/if.js +239 -50
- package/src/runtime/internal/client/index.js +4 -12
- package/src/runtime/internal/client/operations.js +40 -61
- package/src/runtime/internal/client/portal.js +163 -85
- package/src/runtime/internal/client/render.js +39 -39
- package/src/runtime/internal/client/rpc.js +3 -3
- package/src/runtime/internal/client/runtime.js +592 -433
- package/src/runtime/internal/client/selector.js +5 -2
- package/src/runtime/internal/client/template.js +133 -158
- package/src/runtime/internal/client/transport.js +38 -0
- package/src/runtime/internal/client/try.js +465 -426
- package/src/runtime/internal/client/types.d.ts +56 -23
- package/src/runtime/internal/client/utils.js +1 -3
- package/src/runtime/internal/server/dynamic.js +20 -21
- package/src/runtime/internal/server/index.js +325 -275
- package/src/runtime/internal/server/rpc.js +3 -2
- package/src/runtime/internal/server/transport.js +16 -0
- package/src/runtime/transport.js +21 -0
- package/tests/client/__snapshots__/for.test.tsrx.snap +0 -5
- package/tests/client/array/array.copy-within.test.tsrx +12 -12
- package/tests/client/array/array.derived.test.tsrx +46 -46
- package/tests/client/array/array.iteration.test.tsrx +10 -10
- package/tests/client/array/array.mutations.test.tsrx +20 -20
- package/tests/client/array/array.static.test.tsrx +11 -11
- package/tests/client/array/array.to-methods.test.tsrx +6 -6
- package/tests/client/async-suspend.test.tsrx +74 -75
- package/tests/client/basic/basic.attributes.test.tsrx +86 -83
- package/tests/client/basic/basic.collections.test.tsrx +12 -12
- package/tests/client/basic/basic.components.test.tsrx +99 -25
- package/tests/client/basic/basic.errors.test.tsrx +18 -18
- package/tests/client/basic/basic.events.test.tsrx +42 -42
- package/tests/client/basic/basic.get-set.test.tsrx +8 -8
- package/tests/client/basic/basic.reactivity.test.tsrx +73 -38
- package/tests/client/basic/basic.rendering.test.tsrx +25 -25
- package/tests/client/basic/basic.utilities.test.tsrx +3 -3
- package/tests/client/boundaries.test.tsrx +8 -8
- package/tests/client/boxed-locals.test.tsrx +452 -0
- package/tests/client/compiler/__snapshots__/compiler.assignments.test.tsrx.snap +6 -6
- package/tests/client/compiler/compiler.assignments.test.tsrx +9 -73
- package/tests/client/compiler/compiler.attributes.test.tsrx +23 -23
- package/tests/client/compiler/compiler.basic.test.tsrx +15 -60
- package/tests/client/compiler/compiler.tracked-access.test.tsrx +18 -43
- package/tests/client/compiler/compiler.try-in-function.test.tsrx +2 -2
- package/tests/client/composite/__snapshots__/composite.render.test.tsrx.snap +0 -1
- package/tests/client/composite/composite.dynamic-components.test.tsrx +77 -6
- package/tests/client/composite/composite.props.test.tsrx +149 -12
- package/tests/client/composite/composite.reactivity.test.tsrx +51 -52
- package/tests/client/composite/composite.render.test.tsrx +26 -9
- package/tests/client/css/scoped-styles.test.tsrx +8 -8
- package/tests/client/date.test.tsrx +42 -42
- package/tests/client/derived-release.test.tsrx +370 -0
- package/tests/client/dynamic-elements.test.tsrx +45 -45
- package/tests/client/events.test.tsrx +97 -71
- package/tests/client/for-selector.test.tsrx +14 -14
- package/tests/client/for-single-root-items.test.tsrx +118 -3
- package/tests/client/for.test.tsrx +332 -31
- package/tests/client/head.test.tsrx +19 -19
- package/tests/client/html.test.tsrx +11 -9
- package/tests/client/if-block.test.tsrx +80 -0
- package/tests/client/map.test.tsrx +16 -16
- package/tests/client/media-query.test.tsrx +7 -7
- package/tests/client/portal.test.tsrx +224 -26
- package/tests/client/primitive-text.test.tsrx +50 -0
- package/tests/client/prop-kind-switch.test.tsrx +141 -0
- package/tests/client/ref.test.tsrx +17 -17
- package/tests/client/return.test.tsrx +26 -3
- package/tests/client/root-boundary.test.tsrx +42 -0
- package/tests/client/scoped-flush.test.tsrx +8 -8
- package/tests/client/set.test.tsrx +6 -6
- package/tests/client/svg.test.tsrx +11 -11
- package/tests/client/switch.test.tsrx +44 -44
- package/tests/client/track-async-hydration.test.tsrx +4 -4
- package/tests/client/try.test.tsrx +151 -83
- package/tests/client/tsx.test.tsrx +43 -40
- package/tests/client/url/url.derived.test.tsrx +6 -6
- package/tests/client/url-search-params/url-search-params.derived.test.tsrx +8 -8
- package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +10 -10
- package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +10 -10
- package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +18 -18
- package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +2 -2
- package/tests/hydration/basic.test.js +74 -1
- package/tests/hydration/build-components.js +22 -1
- package/tests/hydration/compiled/client/basic.js +1142 -713
- package/tests/hydration/compiled/client/composite.js +151 -100
- package/tests/hydration/compiled/client/events.js +184 -171
- package/tests/hydration/compiled/client/for.js +1472 -1132
- package/tests/hydration/compiled/client/fragment-cursor.js +2341 -0
- package/tests/hydration/compiled/client/head.js +254 -201
- package/tests/hydration/compiled/client/hmr.js +54 -41
- package/tests/hydration/compiled/client/html-in-template.js +54 -39
- package/tests/hydration/compiled/client/html.js +1633 -1263
- package/tests/hydration/compiled/client/if-children.js +420 -270
- package/tests/hydration/compiled/client/if-fragment-controlflow.js +363 -317
- package/tests/hydration/compiled/client/if.js +229 -219
- package/tests/hydration/compiled/client/mixed-control-flow.js +420 -404
- package/tests/hydration/compiled/client/nested-control-flow.js +1326 -1277
- package/tests/hydration/compiled/client/portal.js +87 -95
- package/tests/hydration/compiled/client/reactivity.js +135 -101
- package/tests/hydration/compiled/client/return.js +28 -19
- package/tests/hydration/compiled/client/streaming.js +390 -306
- package/tests/hydration/compiled/client/switch.js +258 -266
- package/tests/hydration/compiled/client/track-async-serialization.js +448 -280
- package/tests/hydration/compiled/client/try.js +173 -129
- package/tests/hydration/compiled/client/typed-text.js +71 -0
- package/tests/hydration/compiled/fixtures/money.js +10 -0
- package/tests/hydration/compiled/server/basic.js +123 -6
- package/tests/hydration/compiled/server/composite.js +16 -30
- package/tests/hydration/compiled/server/events.js +66 -18
- package/tests/hydration/compiled/server/for.js +117 -41
- package/tests/hydration/compiled/server/fragment-cursor.js +1687 -0
- package/tests/hydration/compiled/server/head.js +20 -20
- package/tests/hydration/compiled/server/hmr.js +2 -2
- package/tests/hydration/compiled/server/html.js +70 -238
- package/tests/hydration/compiled/server/if-children.js +107 -15
- package/tests/hydration/compiled/server/if.js +11 -15
- package/tests/hydration/compiled/server/mixed-control-flow.js +8 -8
- package/tests/hydration/compiled/server/portal.js +14 -22
- package/tests/hydration/compiled/server/reactivity.js +14 -14
- package/tests/hydration/compiled/server/streaming.js +19 -19
- package/tests/hydration/compiled/server/switch.js +8 -8
- package/tests/hydration/compiled/server/track-async-serialization.js +150 -23
- package/tests/hydration/compiled/server/try.js +8 -8
- package/tests/hydration/compiled/server/typed-text.js +17 -0
- package/tests/hydration/components/basic.tsrx +44 -8
- package/tests/hydration/components/composite.tsrx +2 -2
- package/tests/hydration/components/events.tsrx +25 -25
- package/tests/hydration/components/for.tsrx +115 -67
- package/tests/hydration/components/fragment-cursor.tsrx +650 -0
- package/tests/hydration/components/head.tsrx +16 -16
- package/tests/hydration/components/hmr.tsrx +2 -2
- package/tests/hydration/components/html.tsrx +7 -7
- package/tests/hydration/components/if-children.tsrx +72 -25
- package/tests/hydration/components/if.tsrx +18 -18
- package/tests/hydration/components/mixed-control-flow.tsrx +11 -11
- package/tests/hydration/components/portal.tsrx +3 -3
- package/tests/hydration/components/reactivity.tsrx +16 -16
- package/tests/hydration/components/streaming.tsrx +20 -20
- package/tests/hydration/components/switch.tsrx +20 -20
- package/tests/hydration/components/text-types.ts +4 -0
- package/tests/hydration/components/track-async-serialization.tsrx +80 -26
- package/tests/hydration/components/try.tsrx +8 -8
- package/tests/hydration/components/typed-text.tsrx +22 -0
- package/tests/hydration/fixtures/money.js +10 -0
- package/tests/hydration/for.test.js +36 -0
- package/tests/hydration/fragment-cursor.test.js +111 -0
- package/tests/hydration/if-children.test.js +24 -0
- package/tests/hydration/streaming.test.js +19 -0
- package/tests/hydration/track-async-serialization.test.js +87 -2
- package/tests/hydration/tsconfig.text-types.json +10 -0
- package/tests/hydration/typed-text.test.js +34 -0
- package/tests/server/await.test.tsrx +3 -3
- package/tests/server/basic.attributes.test.tsrx +42 -42
- package/tests/server/basic.components.test.tsrx +64 -8
- package/tests/server/basic.test.tsrx +34 -32
- package/tests/server/compiler.test.tsrx +1 -70
- package/tests/server/composite.props.test.tsrx +6 -6
- package/tests/server/dynamic-elements.test.tsrx +31 -8
- package/tests/server/for.test.tsrx +94 -0
- package/tests/server/head.test.tsrx +11 -11
- package/tests/server/scoped-styles.test.tsrx +2 -2
- package/tests/server/streaming-ssr.test.tsrx +48 -43
- package/tests/server/track-async-serialization.test.tsrx +204 -21
- package/tests/server/try.test.tsrx +48 -48
- package/tests/types/transport.ts +40 -0
- package/tests/utils/vite-plugin-config.test.js +23 -0
- package/types/index.d.ts +48 -7
- package/types/server.d.ts +3 -0
- package/types/transport.d.ts +15 -0
- package/src/runtime/internal/client/switch.js +0 -113
- package/src/utils/errors.js +0 -13
- package/tests/client/lazy-array.test.tsrx +0 -31
- package/tests/client/lazy-destructuring.test.tsrx +0 -438
- package/tests/client/tracked-index-access.test.tsrx +0 -113
- package/tests/server/lazy-destructuring.test.tsrx +0 -595
- package/tests/server/tracked-index-access.test.tsrx +0 -76
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DynamicProps, PropsWithExtras, TSRXElement } from 'ripple';
|
|
1
|
+
import type { Component, DynamicProps, PropsWithExtras, TSRXElement } from 'ripple';
|
|
2
2
|
import { createRefKey, track } from 'ripple';
|
|
3
3
|
|
|
4
4
|
describe('server dynamic DOM elements', () => {
|
|
@@ -13,6 +13,26 @@ describe('server dynamic DOM elements', () => {
|
|
|
13
13
|
expect(body).toBeHtml('<div>Hello World</div>');
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
+
it('renders a component held in a plain tracked assigned after creation', async () => {
|
|
17
|
+
function Child() @{
|
|
18
|
+
<p>{'I am the child'}</p>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function App() @{
|
|
22
|
+
// track(Child) would make a derived that calls the component, so an
|
|
23
|
+
// empty tracked receives the component through `.value` instead.
|
|
24
|
+
const Body = track<Component>();
|
|
25
|
+
Body.value = Child;
|
|
26
|
+
<div>
|
|
27
|
+
<{Body.value} />
|
|
28
|
+
</div>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const { body } = await render(App);
|
|
32
|
+
|
|
33
|
+
expect(body).toBeHtml('<div><p>I am the child</p></div>');
|
|
34
|
+
});
|
|
35
|
+
|
|
16
36
|
it('renders static dynamic element from a plain object with a tracked property', async () => {
|
|
17
37
|
function App() @{
|
|
18
38
|
let obj = { tag: track('div') };
|
|
@@ -85,8 +105,8 @@ describe('server dynamic DOM elements', () => {
|
|
|
85
105
|
it('handles dynamic element with attributes', async () => {
|
|
86
106
|
function App() @{
|
|
87
107
|
let tag = track('div');
|
|
88
|
-
|
|
89
|
-
<{tag} class={className} id="test" data-testid="dynamic-element">{'Content'}</{tag}>
|
|
108
|
+
const className = track('test-class');
|
|
109
|
+
<{tag} class={className.value} id="test" data-testid="dynamic-element">{'Content'}</{tag}>
|
|
90
110
|
}
|
|
91
111
|
const { body } = await render(App);
|
|
92
112
|
const { document } = parseHtml(body);
|
|
@@ -122,9 +142,9 @@ describe('server dynamic DOM elements', () => {
|
|
|
122
142
|
it('handles dynamic element with class object', async () => {
|
|
123
143
|
function App() @{
|
|
124
144
|
let tag = track('div');
|
|
125
|
-
|
|
145
|
+
const active = track(true);
|
|
126
146
|
<{tag}
|
|
127
|
-
class={{ active: active, 'dynamic-element': true }}
|
|
147
|
+
class={{ active: active.value, 'dynamic-element': true }}
|
|
128
148
|
>{'Element with class object'}</{tag}>
|
|
129
149
|
}
|
|
130
150
|
|
|
@@ -259,7 +279,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
259
279
|
});
|
|
260
280
|
|
|
261
281
|
it('handles spread attributes with class and CSS scoping', async () => {
|
|
262
|
-
function DynamicButton(
|
|
282
|
+
function DynamicButton({ ...rest }: PropsWithExtras<{
|
|
263
283
|
class: string;
|
|
264
284
|
id: string;
|
|
265
285
|
}>) @{
|
|
@@ -278,8 +298,11 @@ describe('server dynamic DOM elements', () => {
|
|
|
278
298
|
}
|
|
279
299
|
|
|
280
300
|
function App() @{
|
|
281
|
-
|
|
282
|
-
<DynamicButton
|
|
301
|
+
const count = track(0);
|
|
302
|
+
<DynamicButton
|
|
303
|
+
class={count.value % 2 ? 'even' : 'odd'}
|
|
304
|
+
id={count.value % 2 ? 'even' : 'odd'}
|
|
305
|
+
/>
|
|
283
306
|
}
|
|
284
307
|
|
|
285
308
|
const { body } = await render(App);
|
|
@@ -202,4 +202,98 @@ describe('for statements in SSR', () => {
|
|
|
202
202
|
),
|
|
203
203
|
).toThrow('Continue statements are not allowed inside TSRX template for...of loops');
|
|
204
204
|
});
|
|
205
|
+
|
|
206
|
+
it('renders the loop from a function that returns its template', async () => {
|
|
207
|
+
function Plain({ items }) {
|
|
208
|
+
return <ul>
|
|
209
|
+
@for (const item of items) {
|
|
210
|
+
<li>{item.text}</li>
|
|
211
|
+
}
|
|
212
|
+
</ul>;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function Indexed({ items }) {
|
|
216
|
+
return <ul>
|
|
217
|
+
@for (const item of items; index i) {
|
|
218
|
+
<li>{i + ': ' + item.text}</li>
|
|
219
|
+
}
|
|
220
|
+
</ul>;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function Keyed({ items }) {
|
|
224
|
+
return <ul>
|
|
225
|
+
@for (const item of items; key item.id) {
|
|
226
|
+
<li>{item.text}</li>
|
|
227
|
+
}
|
|
228
|
+
</ul>;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const Arrow = ({ items }) => <ul>
|
|
232
|
+
@for (const item of items; index i) {
|
|
233
|
+
<li>{i + ': ' + item.text}</li>
|
|
234
|
+
}
|
|
235
|
+
</ul>;
|
|
236
|
+
|
|
237
|
+
function App() @{
|
|
238
|
+
const items = [
|
|
239
|
+
{ id: 1, text: 'a' },
|
|
240
|
+
{ id: 2, text: 'b' },
|
|
241
|
+
];
|
|
242
|
+
<>
|
|
243
|
+
<Plain {items} />
|
|
244
|
+
<Indexed {items} />
|
|
245
|
+
<Keyed {items} />
|
|
246
|
+
<Arrow {items} />
|
|
247
|
+
</>
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const { body } = await render(App);
|
|
251
|
+
expect(body).toBeHtml(
|
|
252
|
+
'<ul><li>a</li><li>b</li></ul>' + '<ul><li>0: a</li><li>1: b</li></ul>' +
|
|
253
|
+
'<ul><li>a</li><li>b</li></ul>' +
|
|
254
|
+
'<ul><li>0: a</li><li>1: b</li></ul>',
|
|
255
|
+
);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('renders the loop from a template held in a variable', async () => {
|
|
259
|
+
function Indexed({ items }) {
|
|
260
|
+
const list = <ul>
|
|
261
|
+
@for (const item of items; index i) {
|
|
262
|
+
<li>{i + ': ' + item.text}</li>
|
|
263
|
+
}
|
|
264
|
+
</ul>;
|
|
265
|
+
return list;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function App() @{
|
|
269
|
+
const items = [
|
|
270
|
+
{ id: 1, text: 'a' },
|
|
271
|
+
{ id: 2, text: 'b' },
|
|
272
|
+
];
|
|
273
|
+
<Indexed {items} />
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const { body } = await render(App);
|
|
277
|
+
expect(body).toBeHtml('<ul><li>0: a</li><li>1: b</li></ul>');
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('renders a bare `@for` held in a variable through an expression', async () => {
|
|
281
|
+
function Returned({ items }) {
|
|
282
|
+
const yo = @for (const item of items; index i; key item.id) {
|
|
283
|
+
<li>{i + ': ' + item.text}</li>
|
|
284
|
+
};
|
|
285
|
+
return <ul>{yo}</ul>;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function App() @{
|
|
289
|
+
const items = [
|
|
290
|
+
{ id: 1, text: 'a' },
|
|
291
|
+
{ id: 2, text: 'b' },
|
|
292
|
+
];
|
|
293
|
+
<Returned {items} />
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const { body } = await render(App);
|
|
297
|
+
expect(body).toBeHtml('<ul><li>0: a</li><li>1: b</li></ul>');
|
|
298
|
+
});
|
|
205
299
|
});
|
|
@@ -20,13 +20,13 @@ describe('head elements', () => {
|
|
|
20
20
|
|
|
21
21
|
it('renders reactive title element', async () => {
|
|
22
22
|
function App() @{
|
|
23
|
-
|
|
23
|
+
const title = track('Initial Title');
|
|
24
24
|
<>
|
|
25
25
|
<head>
|
|
26
|
-
<title>{title}</title>
|
|
26
|
+
<title>{title.value}</title>
|
|
27
27
|
</head>
|
|
28
28
|
<div>
|
|
29
|
-
<span>{title}</span>
|
|
29
|
+
<span>{title.value}</span>
|
|
30
30
|
</div>
|
|
31
31
|
</>
|
|
32
32
|
}
|
|
@@ -40,9 +40,9 @@ describe('head elements', () => {
|
|
|
40
40
|
|
|
41
41
|
it('renders title with template literal', async () => {
|
|
42
42
|
function App() @{
|
|
43
|
-
|
|
43
|
+
const name = track('World');
|
|
44
44
|
<head>
|
|
45
|
-
<title>{`Hello ${name}!`}</title>
|
|
45
|
+
<title>{`Hello ${name.value}!`}</title>
|
|
46
46
|
</head>
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -54,14 +54,14 @@ describe('head elements', () => {
|
|
|
54
54
|
|
|
55
55
|
it('renders title with computed value', async () => {
|
|
56
56
|
function App() @{
|
|
57
|
-
|
|
57
|
+
const count = track(0);
|
|
58
58
|
let prefix = 'Count: ';
|
|
59
59
|
<>
|
|
60
60
|
<head>
|
|
61
|
-
<title>{prefix + count}</title>
|
|
61
|
+
<title>{prefix + count.value}</title>
|
|
62
62
|
</head>
|
|
63
63
|
<div>
|
|
64
|
-
<span>{count}</span>
|
|
64
|
+
<span>{count.value}</span>
|
|
65
65
|
</div>
|
|
66
66
|
</>
|
|
67
67
|
}
|
|
@@ -130,11 +130,11 @@ describe('head elements', () => {
|
|
|
130
130
|
|
|
131
131
|
it('renders title with conditional content', async () => {
|
|
132
132
|
function App() @{
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
const showPrefix = track(true);
|
|
134
|
+
const title = track('Main Page');
|
|
135
135
|
<head>
|
|
136
136
|
<title>
|
|
137
|
-
{showPrefix ? 'App - ' + title : title}
|
|
137
|
+
{showPrefix.value ? 'App - ' + title.value : title.value}
|
|
138
138
|
</title>
|
|
139
139
|
</head>
|
|
140
140
|
}
|
|
@@ -144,7 +144,7 @@ describe('sibling-scoped style blocks (server)', () => {
|
|
|
144
144
|
});
|
|
145
145
|
|
|
146
146
|
it('merges the scope classes into a spread', async () => {
|
|
147
|
-
function Button(
|
|
147
|
+
function Button({ ...rest }: { id: string; class?: string }) @{
|
|
148
148
|
<>
|
|
149
149
|
<style>
|
|
150
150
|
button {
|
|
@@ -177,7 +177,7 @@ describe('sibling-scoped style blocks (server)', () => {
|
|
|
177
177
|
|
|
178
178
|
describe('spreads with an imported theme (server)', () => {
|
|
179
179
|
it('merges the scope classes of a static class into the spread once', async () => {
|
|
180
|
-
function Card(
|
|
180
|
+
function Card({ ...rest }: { class?: string }) @{
|
|
181
181
|
<>
|
|
182
182
|
<style apply={importedTheme}>
|
|
183
183
|
.box {
|
|
@@ -37,6 +37,17 @@ function recordingSink() {
|
|
|
37
37
|
|
|
38
38
|
const SLOT_OPEN_RE = /<!--\[\?(\d+)-->/;
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Settled units stream once the current task's microtasks have drained, so
|
|
42
|
+
* units settling together share one chunk: wait a macrotask for the flush.
|
|
43
|
+
*/
|
|
44
|
+
async function flushed(): Promise<void> {
|
|
45
|
+
// the first macrotask lets the settle microtasks schedule the flush, the
|
|
46
|
+
// second lets that flush run
|
|
47
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
48
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
/**
|
|
41
52
|
* Applies streamed chunks the way the inline swap runtime would: collects
|
|
42
53
|
* chunk templates, then repeatedly replaces `<!--[?N-->…<!--]-->` slots
|
|
@@ -160,8 +171,8 @@ describe('streaming try/pending boundaries', () => {
|
|
|
160
171
|
const d = deferred<string>();
|
|
161
172
|
|
|
162
173
|
function Content() @{
|
|
163
|
-
|
|
164
|
-
<p>{data}</p>
|
|
174
|
+
const data = trackAsync(() => d.promise);
|
|
175
|
+
<p>{data.value}</p>
|
|
165
176
|
}
|
|
166
177
|
|
|
167
178
|
function App() @{
|
|
@@ -218,8 +229,8 @@ describe('streaming try/pending boundaries', () => {
|
|
|
218
229
|
const d = deferred<string>();
|
|
219
230
|
|
|
220
231
|
function Content() @{
|
|
221
|
-
|
|
222
|
-
<p>{data}</p>
|
|
232
|
+
const data = trackAsync(() => d.promise);
|
|
233
|
+
<p>{data.value}</p>
|
|
223
234
|
}
|
|
224
235
|
|
|
225
236
|
function App() @{
|
|
@@ -250,8 +261,8 @@ describe('streaming try/pending boundaries', () => {
|
|
|
250
261
|
const d = deferred<string>();
|
|
251
262
|
|
|
252
263
|
function Content() @{
|
|
253
|
-
|
|
254
|
-
<p>{data}</p>
|
|
264
|
+
const data = trackAsync(() => d.promise);
|
|
265
|
+
<p>{data.value}</p>
|
|
255
266
|
}
|
|
256
267
|
|
|
257
268
|
function App() @{
|
|
@@ -286,8 +297,8 @@ describe('streaming try/pending boundaries', () => {
|
|
|
286
297
|
const d = deferred<string>();
|
|
287
298
|
|
|
288
299
|
function Content() @{
|
|
289
|
-
|
|
290
|
-
<p>{data}</p>
|
|
300
|
+
const data = trackAsync(() => d.promise);
|
|
301
|
+
<p>{data.value}</p>
|
|
291
302
|
}
|
|
292
303
|
|
|
293
304
|
function App() @{
|
|
@@ -329,13 +340,13 @@ describe('streaming try/pending boundaries', () => {
|
|
|
329
340
|
describe('streaming nested and sibling boundaries', () => {
|
|
330
341
|
function makeNestedApp(d_outer: Deferred<string>, d_inner: Deferred<string>) {
|
|
331
342
|
function OuterData() @{
|
|
332
|
-
|
|
333
|
-
<p class="outer">{data}</p>
|
|
343
|
+
const data = trackAsync(() => d_outer.promise);
|
|
344
|
+
<p class="outer">{data.value}</p>
|
|
334
345
|
}
|
|
335
346
|
|
|
336
347
|
function InnerData() @{
|
|
337
|
-
|
|
338
|
-
<p class="inner">{data}</p>
|
|
348
|
+
const data = trackAsync(() => d_inner.promise);
|
|
349
|
+
<p class="inner">{data.value}</p>
|
|
339
350
|
}
|
|
340
351
|
|
|
341
352
|
function App() @{
|
|
@@ -396,9 +407,7 @@ describe('streaming nested and sibling boundaries', () => {
|
|
|
396
407
|
const result = render(App, { stream: sink });
|
|
397
408
|
|
|
398
409
|
d_outer.resolve('outer-done');
|
|
399
|
-
await
|
|
400
|
-
await Promise.resolve();
|
|
401
|
-
await Promise.resolve();
|
|
410
|
+
await flushed();
|
|
402
411
|
|
|
403
412
|
expect(chunks).toHaveLength(2);
|
|
404
413
|
const parent_chunk = chunks[1];
|
|
@@ -420,13 +429,13 @@ describe('streaming nested and sibling boundaries', () => {
|
|
|
420
429
|
const d_second = deferred<string>();
|
|
421
430
|
|
|
422
431
|
function First() @{
|
|
423
|
-
|
|
424
|
-
<p>{'first: ' + data}</p>
|
|
432
|
+
const data = trackAsync(() => d_first.promise);
|
|
433
|
+
<p>{'first: ' + data.value}</p>
|
|
425
434
|
}
|
|
426
435
|
|
|
427
436
|
function Second() @{
|
|
428
|
-
|
|
429
|
-
<p>{'second: ' + data}</p>
|
|
437
|
+
const data = trackAsync(() => d_second.promise);
|
|
438
|
+
<p>{'second: ' + data.value}</p>
|
|
430
439
|
}
|
|
431
440
|
|
|
432
441
|
function App() @{
|
|
@@ -448,9 +457,7 @@ describe('streaming nested and sibling boundaries', () => {
|
|
|
448
457
|
const result = render(App, { stream: sink });
|
|
449
458
|
|
|
450
459
|
d_second.resolve('B');
|
|
451
|
-
await
|
|
452
|
-
await Promise.resolve();
|
|
453
|
-
await Promise.resolve();
|
|
460
|
+
await flushed();
|
|
454
461
|
|
|
455
462
|
expect(chunks).toHaveLength(2);
|
|
456
463
|
expect(chunks[1]).toContain('second: B');
|
|
@@ -468,16 +475,16 @@ describe('streaming nested and sibling boundaries', () => {
|
|
|
468
475
|
async () => {
|
|
469
476
|
function makeApp(ds: Deferred<string>[]) {
|
|
470
477
|
function A() @{
|
|
471
|
-
|
|
472
|
-
<p>{'A:' + data}</p>
|
|
478
|
+
const data = trackAsync(() => ds[0].promise);
|
|
479
|
+
<p>{'A:' + data.value}</p>
|
|
473
480
|
}
|
|
474
481
|
function B() @{
|
|
475
|
-
|
|
476
|
-
<p>{'B:' + data}</p>
|
|
482
|
+
const data = trackAsync(() => ds[1].promise);
|
|
483
|
+
<p>{'B:' + data.value}</p>
|
|
477
484
|
}
|
|
478
485
|
function C() @{
|
|
479
|
-
|
|
480
|
-
<p>{'C:' + data}</p>
|
|
486
|
+
const data = trackAsync(() => ds[2].promise);
|
|
487
|
+
<p>{'C:' + data.value}</p>
|
|
481
488
|
}
|
|
482
489
|
|
|
483
490
|
function App() @{
|
|
@@ -540,8 +547,8 @@ describe('streaming root boundary', () => {
|
|
|
540
547
|
const d = deferred<string>();
|
|
541
548
|
|
|
542
549
|
function App() @{
|
|
543
|
-
|
|
544
|
-
<p>{'app: ' + data}</p>
|
|
550
|
+
const data = trackAsync(() => d.promise);
|
|
551
|
+
<p>{'app: ' + data.value}</p>
|
|
545
552
|
}
|
|
546
553
|
|
|
547
554
|
function RootPending() @{
|
|
@@ -568,8 +575,8 @@ describe('streaming with a document template', () => {
|
|
|
568
575
|
const d = deferred<string>();
|
|
569
576
|
|
|
570
577
|
function Content() @{
|
|
571
|
-
|
|
572
|
-
<p>{data}</p>
|
|
578
|
+
const data = trackAsync(() => d.promise);
|
|
579
|
+
<p>{data.value}</p>
|
|
573
580
|
}
|
|
574
581
|
|
|
575
582
|
function App() @{
|
|
@@ -612,14 +619,14 @@ describe('streaming head content', () => {
|
|
|
612
619
|
const d = deferred<string>();
|
|
613
620
|
|
|
614
621
|
function LateHead() @{
|
|
615
|
-
|
|
622
|
+
const data = trackAsync(() => d.promise);
|
|
616
623
|
<>
|
|
617
|
-
@if (data) {
|
|
624
|
+
@if (data.value) {
|
|
618
625
|
<>
|
|
619
626
|
<head>
|
|
620
|
-
<title>{'title:' + data}</title>
|
|
627
|
+
<title>{'title:' + data.value}</title>
|
|
621
628
|
</head>
|
|
622
|
-
<p class="has-head">{data}</p>
|
|
629
|
+
<p class="has-head">{data.value}</p>
|
|
623
630
|
</>
|
|
624
631
|
}
|
|
625
632
|
</>
|
|
@@ -670,18 +677,18 @@ describe('streaming CSS', () => {
|
|
|
670
677
|
}
|
|
671
678
|
|
|
672
679
|
function GateOne() @{
|
|
673
|
-
|
|
680
|
+
const ready = trackAsync(() => d_gate.promise);
|
|
674
681
|
<>
|
|
675
|
-
@if (ready) {
|
|
682
|
+
@if (ready.value) {
|
|
676
683
|
<LateStyled />
|
|
677
684
|
}
|
|
678
685
|
</>
|
|
679
686
|
}
|
|
680
687
|
|
|
681
688
|
function GateTwo() @{
|
|
682
|
-
|
|
689
|
+
const ready = trackAsync(() => d_gate2.promise);
|
|
683
690
|
<>
|
|
684
|
-
@if (ready) {
|
|
691
|
+
@if (ready.value) {
|
|
685
692
|
<LateStyled />
|
|
686
693
|
}
|
|
687
694
|
</>
|
|
@@ -716,9 +723,7 @@ describe('streaming CSS', () => {
|
|
|
716
723
|
expect(chunks[0]).not.toContain('.late-styled');
|
|
717
724
|
|
|
718
725
|
d_gate.resolve(true);
|
|
719
|
-
await
|
|
720
|
-
await Promise.resolve();
|
|
721
|
-
await Promise.resolve();
|
|
726
|
+
await flushed();
|
|
722
727
|
|
|
723
728
|
expect(chunks).toHaveLength(2);
|
|
724
729
|
// the chunk carries the style it needs, ahead of its template
|