@remix-run/ui 0.7.0 → 0.9.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/README.md +90 -14
- package/dist/animation/demos/drag-release.js +5 -7
- package/dist/animation/demos/drag-release.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/component.d.ts +9 -4
- package/dist/runtime/component.js +38 -9
- package/dist/runtime/component.js.map +1 -1
- package/dist/runtime/core/mix.d.ts +21 -0
- package/dist/runtime/core/mix.js +128 -0
- package/dist/runtime/core/mix.js.map +1 -0
- package/dist/runtime/diff-dom.js +15 -16
- package/dist/runtime/diff-dom.js.map +1 -1
- package/dist/runtime/document-reload.d.ts +2 -0
- package/dist/runtime/document-reload.js +14 -0
- package/dist/runtime/document-reload.js.map +1 -0
- package/dist/runtime/dom.d.ts +21 -11
- package/dist/runtime/event-types.d.ts +14 -0
- package/dist/runtime/event-types.js +2 -0
- package/dist/runtime/event-types.js.map +1 -0
- package/dist/runtime/frame-resolution.js +8 -0
- package/dist/runtime/frame-resolution.js.map +1 -1
- package/dist/runtime/frame.d.ts +24 -6
- package/dist/runtime/frame.js +187 -60
- package/dist/runtime/frame.js.map +1 -1
- package/dist/runtime/import-map-manager.d.ts +8 -0
- package/dist/runtime/import-map-manager.js +295 -0
- package/dist/runtime/import-map-manager.js.map +1 -0
- package/dist/runtime/mixins/link-mixin.js +4 -4
- package/dist/runtime/mixins/link-mixin.js.map +1 -1
- package/dist/runtime/mixins/mixin.d.ts +9 -4
- package/dist/runtime/mixins/mixin.js +18 -132
- package/dist/runtime/mixins/mixin.js.map +1 -1
- package/dist/runtime/mixins/on-mixin.d.ts +1 -1
- package/dist/runtime/module-preloader.d.ts +2 -1
- package/dist/runtime/module-preloader.js +6 -5
- package/dist/runtime/module-preloader.js.map +1 -1
- package/dist/runtime/navigation.js +211 -34
- package/dist/runtime/navigation.js.map +1 -1
- package/dist/runtime/reconcile.js +18 -3
- package/dist/runtime/reconcile.js.map +1 -1
- package/dist/runtime/run.d.ts +3 -0
- package/dist/runtime/run.js +8 -4
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/scheduler.js +37 -11
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/spa-response.d.ts +30 -0
- package/dist/runtime/spa-response.js +47 -0
- package/dist/runtime/spa-response.js.map +1 -0
- package/dist/runtime/to-vnode.js +1 -1
- package/dist/runtime/to-vnode.js.map +1 -1
- package/dist/runtime/typed-event-target.d.ts +0 -4
- package/dist/runtime/typed-event-target.js.map +1 -1
- package/dist/server/stream.d.ts +25 -2
- package/dist/server/stream.js +382 -171
- package/dist/server/stream.js.map +1 -1
- package/dist/style/stylesheet.js +2 -2
- package/dist/style/stylesheet.js.map +1 -1
- package/package.json +1 -1
- package/src/animation/demos/drag-release.ts +5 -7
- package/src/index.ts +2 -2
- package/src/runtime/component.ts +52 -14
- package/src/runtime/core/mix.ts +157 -0
- package/src/runtime/demos/readme.demo.tsx +7 -17
- package/src/runtime/diff-dom.ts +13 -15
- package/src/runtime/document-reload.ts +14 -0
- package/src/runtime/dom.ts +21 -11
- package/src/runtime/event-types.ts +27 -0
- package/src/runtime/frame-resolution.ts +9 -0
- package/src/runtime/frame.ts +216 -65
- package/src/runtime/import-map-manager.ts +369 -0
- package/src/runtime/mixins/link-mixin.ts +4 -4
- package/src/runtime/mixins/mixin.ts +44 -149
- package/src/runtime/mixins/on-mixin.ts +1 -1
- package/src/runtime/module-preloader.ts +9 -6
- package/src/runtime/navigation.ts +257 -42
- package/src/runtime/reconcile.ts +20 -4
- package/src/runtime/run.ts +13 -4
- package/src/runtime/scheduler.ts +53 -13
- package/src/runtime/spa-response.ts +56 -0
- package/src/runtime/to-vnode.ts +1 -1
- package/src/runtime/typed-event-target.ts +1 -6
- package/src/server/README.md +25 -5
- package/src/server/stream.ts +506 -202
- package/src/style/stylesheet.ts +3 -3
- package/src/test/utils.ts +1 -6
- package/dist/runtime/event-listeners.d.ts +0 -50
- package/dist/runtime/event-listeners.js +0 -31
- package/dist/runtime/event-listeners.js.map +0 -1
- package/src/runtime/event-listeners.ts +0 -171
package/dist/runtime/frame.js
CHANGED
|
@@ -9,6 +9,8 @@ import { findFlushMarker } from './stream-protocol.js';
|
|
|
9
9
|
import { getDocumentModulePreloader } from './module-preloader.js';
|
|
10
10
|
import { unwrapFrameResolution } from './frame-resolution.js';
|
|
11
11
|
import { disposeClientEntryBoundary, getClientEntryBoundaryOwner, setClientEntryBoundaryOwner, } from './client-entry-boundary.js';
|
|
12
|
+
import { getDocumentImportMapManager } from './import-map-manager.js';
|
|
13
|
+
import { reloadDocument } from './document-reload.js';
|
|
12
14
|
const bufferedFrameTemplates = new Map();
|
|
13
15
|
const frameTemplateListeners = new Map();
|
|
14
16
|
const DOCTYPE_PATTERN = /<!doctype(?:\s[^>]*)?>/gi;
|
|
@@ -76,6 +78,7 @@ export function createFrame(root, init) {
|
|
|
76
78
|
let reloadKind;
|
|
77
79
|
let styleManager = init.styleManager ?? createStyleManager();
|
|
78
80
|
let modulePreloader = getDocumentModulePreloader(container.doc);
|
|
81
|
+
let importMapManager = getDocumentImportMapManager(container.doc);
|
|
79
82
|
let currentMarker = init.marker;
|
|
80
83
|
let displayedContentStatus = init.marker?.status ?? 'resolved';
|
|
81
84
|
let pendingTemplateMarkerId;
|
|
@@ -85,15 +88,35 @@ export function createFrame(root, init) {
|
|
|
85
88
|
let inheritedReloadAbortUnsubscribe;
|
|
86
89
|
let disposed = false;
|
|
87
90
|
let lifecycleController = new AbortController();
|
|
91
|
+
async function consumeClientEntryResources(source, documentHref) {
|
|
92
|
+
let importMapStatus = importMapManager.consumeImportMaps(source);
|
|
93
|
+
if (importMapStatus !== 'ready') {
|
|
94
|
+
lifecycleController.abort();
|
|
95
|
+
if (importMapStatus === 'conflict')
|
|
96
|
+
reloadDocument(container.doc, documentHref);
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
await modulePreloader.consumePreloadLinks(source, init.processClientEntryPreloads);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
let initialClientEntryResources;
|
|
103
|
+
function shouldPreserveManagedHeadNode(node) {
|
|
104
|
+
return (importMapManager.shouldPreserveHeadNode(node) ||
|
|
105
|
+
(modulePreloader.hasActivePreloads() && modulePreloader.isActivePreload(node)));
|
|
106
|
+
}
|
|
88
107
|
if (isDocumentNode(container.root)) {
|
|
89
108
|
modulePreloader.adoptInitialPreloadLinks(container.root);
|
|
90
109
|
}
|
|
91
110
|
else {
|
|
92
|
-
|
|
111
|
+
initialClientEntryResources = consumeClientEntryResources(container.root);
|
|
93
112
|
}
|
|
94
113
|
// Merge any rmx-data found in the current document once at startup.
|
|
95
114
|
mergeRmxDataFromDocument(init.data, container.doc);
|
|
96
|
-
let runtime = createFrameRuntime({
|
|
115
|
+
let runtime = createFrameRuntime({
|
|
116
|
+
...init,
|
|
117
|
+
styleManager,
|
|
118
|
+
reloadForNavigation: startReloadTransition,
|
|
119
|
+
});
|
|
97
120
|
let frame = createFrameHandle({
|
|
98
121
|
src: init.src,
|
|
99
122
|
$runtime: runtime,
|
|
@@ -121,6 +144,7 @@ export function createFrame(root, init) {
|
|
|
121
144
|
moduleLoads: init.moduleLoads,
|
|
122
145
|
frameInstances: init.frameInstances,
|
|
123
146
|
namedFrames: init.namedFrames,
|
|
147
|
+
processClientEntryPreloads: init.processClientEntryPreloads,
|
|
124
148
|
lifecycleSignal: lifecycleController.signal,
|
|
125
149
|
regionTailRef: container.regionTailRef,
|
|
126
150
|
regionParent: container.regionParent,
|
|
@@ -168,7 +192,24 @@ export function createFrame(root, init) {
|
|
|
168
192
|
}
|
|
169
193
|
if (isRenderAborted(options.signal))
|
|
170
194
|
return;
|
|
171
|
-
|
|
195
|
+
let previousServerFrameReload = runtime.serverFrameReload;
|
|
196
|
+
if (options.signal) {
|
|
197
|
+
runtime.serverFrameReload = {
|
|
198
|
+
signal: options.signal,
|
|
199
|
+
reconciliationTracker: options.reconciliationTracker,
|
|
200
|
+
blockingFrameTracker: options.blockingFrameTracker,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
contentRoot.render(content);
|
|
205
|
+
await new Promise((resolve) => context.scheduler.enqueueCommitPhase([resolve]));
|
|
206
|
+
options.onCommit?.();
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
runtime.serverFrameReload = previousServerFrameReload;
|
|
210
|
+
}
|
|
211
|
+
if (isRenderAborted(options.signal))
|
|
212
|
+
return;
|
|
172
213
|
displayedContentStatus = options.contentStatus ?? 'resolved';
|
|
173
214
|
return;
|
|
174
215
|
}
|
|
@@ -193,10 +234,18 @@ export function createFrame(root, init) {
|
|
|
193
234
|
options.flushKind === 'document';
|
|
194
235
|
if (isFullDocumentReload && htmlContent !== undefined) {
|
|
195
236
|
let parsed = new DOMParser().parseFromString(htmlContent, 'text/html');
|
|
196
|
-
|
|
237
|
+
if (!(await consumeClientEntryResources(parsed, options.documentHref)))
|
|
238
|
+
return;
|
|
239
|
+
if (isRenderAborted(options.signal))
|
|
240
|
+
return;
|
|
197
241
|
let responseData = options.data;
|
|
198
242
|
mergeRmxDataFromDocument(responseData, parsed);
|
|
199
|
-
let responseContext = {
|
|
243
|
+
let responseContext = {
|
|
244
|
+
...context,
|
|
245
|
+
data: responseData,
|
|
246
|
+
reconciliationTracker: options.reconciliationTracker,
|
|
247
|
+
blockingFrameTracker: options.blockingFrameTracker,
|
|
248
|
+
};
|
|
200
249
|
context.styleManager.adoptServerStyles(collectFrameServerStyleTags(createElementContainer(parsed)));
|
|
201
250
|
syncElementAttributes(container.doc.documentElement, parsed.documentElement);
|
|
202
251
|
diffNodes([container.doc.head], [parsed.head], {
|
|
@@ -204,9 +253,7 @@ export function createFrame(root, init) {
|
|
|
204
253
|
regionParent: container.doc.documentElement,
|
|
205
254
|
regionTailRef: null,
|
|
206
255
|
signal: options.signal,
|
|
207
|
-
|
|
208
|
-
? modulePreloader.isActivePreload
|
|
209
|
-
: undefined,
|
|
256
|
+
shouldPreserveHeadNode: shouldPreserveManagedHeadNode,
|
|
210
257
|
});
|
|
211
258
|
diffNodes([container.doc.body], [parsed.body], {
|
|
212
259
|
...responseContext,
|
|
@@ -217,20 +264,30 @@ export function createFrame(root, init) {
|
|
|
217
264
|
let bodyContainer = createElementContainer(container.doc.body);
|
|
218
265
|
if (isRenderAborted(options.signal))
|
|
219
266
|
return;
|
|
220
|
-
scheduleHydrationInContainer(bodyContainer, responseContext, options.
|
|
221
|
-
|
|
267
|
+
scheduleHydrationInContainer(bodyContainer, responseContext, options.reconciliationTracker, options.signal);
|
|
268
|
+
let subFramesReady = createSubFrames(bodyContainer.childNodes, responseContext, options);
|
|
269
|
+
options.onCommit?.();
|
|
270
|
+
await subFramesReady;
|
|
222
271
|
if (isRenderAborted(options.signal))
|
|
223
272
|
return;
|
|
224
273
|
displayedContentStatus = options.contentStatus ?? 'resolved';
|
|
225
274
|
return;
|
|
226
275
|
}
|
|
227
276
|
let fragment = htmlContent !== undefined ? createFragmentFromString(container.doc, htmlContent) : content;
|
|
228
|
-
|
|
277
|
+
if (!(await consumeClientEntryResources(fragment, options.documentHref)))
|
|
278
|
+
return;
|
|
279
|
+
if (isRenderAborted(options.signal))
|
|
280
|
+
return;
|
|
229
281
|
context.styleManager.adoptServerStyles(collectFrameServerStyleTags(createElementContainer(fragment)));
|
|
230
282
|
removeEmptyHeads(fragment);
|
|
231
283
|
let responseData = options.data;
|
|
232
284
|
mergeRmxDataFromFragment(responseData, fragment);
|
|
233
|
-
let responseContext = {
|
|
285
|
+
let responseContext = {
|
|
286
|
+
...context,
|
|
287
|
+
data: responseData,
|
|
288
|
+
reconciliationTracker: options.reconciliationTracker,
|
|
289
|
+
blockingFrameTracker: options.blockingFrameTracker,
|
|
290
|
+
};
|
|
234
291
|
let nextContainer = createContainer(fragment);
|
|
235
292
|
if (isRenderAborted(options.signal))
|
|
236
293
|
return;
|
|
@@ -240,10 +297,10 @@ export function createFrame(root, init) {
|
|
|
240
297
|
regionParent: container.regionParent,
|
|
241
298
|
signal: options.signal,
|
|
242
299
|
});
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
await
|
|
300
|
+
scheduleHydrationInContainer(container, responseContext, options.reconciliationTracker, options.signal);
|
|
301
|
+
let subFramesReady = createSubFrames(container.childNodes, responseContext, options);
|
|
302
|
+
options.onCommit?.();
|
|
303
|
+
await subFramesReady;
|
|
247
304
|
if (isRenderAborted(options.signal))
|
|
248
305
|
return;
|
|
249
306
|
displayedContentStatus = options.contentStatus ?? 'resolved';
|
|
@@ -286,19 +343,23 @@ export function createFrame(root, init) {
|
|
|
286
343
|
}
|
|
287
344
|
}
|
|
288
345
|
async function hydrateInitial() {
|
|
289
|
-
let
|
|
346
|
+
let reconciliationTracker = createReconciliationTracker();
|
|
347
|
+
if ((await initialClientEntryResources) === false)
|
|
348
|
+
return;
|
|
349
|
+
if (disposed || context.lifecycleSignal.aborted)
|
|
350
|
+
return;
|
|
290
351
|
context.styleManager.adoptServerStyles(collectFrameServerStyleTags(container));
|
|
291
352
|
let subFramesReady = createSubFrames(container.childNodes, context);
|
|
292
|
-
scheduleHydrationInContainer(container, context,
|
|
353
|
+
scheduleHydrationInContainer(container, context, reconciliationTracker);
|
|
293
354
|
try {
|
|
294
355
|
await subFramesReady;
|
|
295
356
|
if (disposed || context.lifecycleSignal.aborted)
|
|
296
357
|
return;
|
|
297
358
|
if (currentMarker?.status === 'pending') {
|
|
298
|
-
await watchPendingFrameTemplate(currentMarker,
|
|
359
|
+
await watchPendingFrameTemplate(currentMarker, reconciliationTracker);
|
|
299
360
|
}
|
|
300
|
-
|
|
301
|
-
await
|
|
361
|
+
reconciliationTracker.finalize();
|
|
362
|
+
await reconciliationTracker.ready();
|
|
302
363
|
}
|
|
303
364
|
finally {
|
|
304
365
|
clearRmxData(context.data);
|
|
@@ -357,7 +418,7 @@ export function createFrame(root, init) {
|
|
|
357
418
|
startInheritedReload(options?.signal);
|
|
358
419
|
}
|
|
359
420
|
if (marker.status === 'pending') {
|
|
360
|
-
await watchPendingFrameTemplate(marker, options?.
|
|
421
|
+
await watchPendingFrameTemplate(marker, options?.reconciliationTracker, options?.signal, isInheritedReload
|
|
361
422
|
? () => {
|
|
362
423
|
completeInheritedReload();
|
|
363
424
|
}
|
|
@@ -389,8 +450,23 @@ export function createFrame(root, init) {
|
|
|
389
450
|
}
|
|
390
451
|
}
|
|
391
452
|
async function reload(options) {
|
|
453
|
+
let transition = startReloadTransition(options);
|
|
454
|
+
void transition.committed.catch(() => { });
|
|
455
|
+
return await transition.finished;
|
|
456
|
+
}
|
|
457
|
+
function startReloadTransition(options) {
|
|
392
458
|
let controller = startReload(options?.signal);
|
|
393
|
-
|
|
459
|
+
let committed = Promise.withResolvers();
|
|
460
|
+
let commitStarted = false;
|
|
461
|
+
let finished = resolveAndRenderReload(controller, options, (ready) => {
|
|
462
|
+
if (commitStarted)
|
|
463
|
+
return;
|
|
464
|
+
commitStarted = true;
|
|
465
|
+
void ready.then(committed.resolve, committed.reject);
|
|
466
|
+
});
|
|
467
|
+
// Settle committed when a reload is aborted or fails before rendering any content.
|
|
468
|
+
void finished.then(() => committed.resolve(), committed.reject);
|
|
469
|
+
return { signal: controller.signal, committed: committed.promise, finished };
|
|
394
470
|
}
|
|
395
471
|
function startReload(signal) {
|
|
396
472
|
let controller = replaceReloadController(signal);
|
|
@@ -438,7 +514,7 @@ export function createFrame(root, init) {
|
|
|
438
514
|
}
|
|
439
515
|
return controller;
|
|
440
516
|
}
|
|
441
|
-
async function resolveAndRenderReload(controller, options) {
|
|
517
|
+
async function resolveAndRenderReload(controller, options, resolveCommit) {
|
|
442
518
|
try {
|
|
443
519
|
let resolution = await init.resolveFrame(frame.src, {
|
|
444
520
|
...options,
|
|
@@ -452,7 +528,24 @@ export function createFrame(root, init) {
|
|
|
452
528
|
if (reloadController !== controller || controller.signal.aborted) {
|
|
453
529
|
return { signal: controller.signal };
|
|
454
530
|
}
|
|
455
|
-
|
|
531
|
+
let reconciliationTracker = createReconciliationTracker();
|
|
532
|
+
let blockingFrameTracker = createReconciliationTracker();
|
|
533
|
+
let commitStarted = false;
|
|
534
|
+
await render(content, {
|
|
535
|
+
documentHref: isDocumentNode(container.root) ? (redirectedTo ?? frame.src) : undefined,
|
|
536
|
+
signal: controller.signal,
|
|
537
|
+
reconciliationTracker,
|
|
538
|
+
blockingFrameTracker,
|
|
539
|
+
onCommit() {
|
|
540
|
+
if (commitStarted)
|
|
541
|
+
return;
|
|
542
|
+
commitStarted = true;
|
|
543
|
+
blockingFrameTracker.finalize();
|
|
544
|
+
resolveCommit?.(blockingFrameTracker.ready());
|
|
545
|
+
},
|
|
546
|
+
});
|
|
547
|
+
reconciliationTracker.finalize();
|
|
548
|
+
await reconciliationTracker.ready();
|
|
456
549
|
return {
|
|
457
550
|
signal: controller.signal,
|
|
458
551
|
redirectedTo: reloadController === controller && !controller.signal.aborted ? redirectedTo : undefined,
|
|
@@ -534,7 +627,7 @@ export function createFrame(root, init) {
|
|
|
534
627
|
pendingTemplateObserver = undefined;
|
|
535
628
|
pendingTemplateMarkerId = undefined;
|
|
536
629
|
}
|
|
537
|
-
async function watchPendingFrameTemplate(marker,
|
|
630
|
+
async function watchPendingFrameTemplate(marker, reconciliationTracker, signal, onResolved) {
|
|
538
631
|
if (disposed || context.lifecycleSignal.aborted || signal?.aborted)
|
|
539
632
|
return;
|
|
540
633
|
if (pendingTemplateMarkerId === marker.id)
|
|
@@ -544,7 +637,7 @@ export function createFrame(root, init) {
|
|
|
544
637
|
let early = consumeFrameTemplate(marker.id) ?? getEarlyFrameContent(marker.id);
|
|
545
638
|
if (early) {
|
|
546
639
|
clearPendingFrameTemplateWatch();
|
|
547
|
-
await render(early, {
|
|
640
|
+
await render(early, { reconciliationTracker, signal, contentStatus: 'resolved' });
|
|
548
641
|
if (!disposed && !context.lifecycleSignal.aborted && !signal?.aborted)
|
|
549
642
|
onResolved?.();
|
|
550
643
|
return;
|
|
@@ -574,7 +667,7 @@ export function createFrame(root, init) {
|
|
|
574
667
|
let buffered = consumeFrameTemplate(marker.id);
|
|
575
668
|
if (buffered) {
|
|
576
669
|
clearPendingFrameTemplateWatch();
|
|
577
|
-
await render(buffered, {
|
|
670
|
+
await render(buffered, { reconciliationTracker, signal, contentStatus: 'resolved' });
|
|
578
671
|
if (!disposed && !context.lifecycleSignal.aborted && !signal?.aborted)
|
|
579
672
|
onResolved?.();
|
|
580
673
|
}
|
|
@@ -594,38 +687,58 @@ export function createFrameRuntime(init) {
|
|
|
594
687
|
moduleLoads: init.moduleLoads,
|
|
595
688
|
frameInstances: init.frameInstances,
|
|
596
689
|
namedFrames: init.namedFrames,
|
|
690
|
+
processClientEntryPreloads: init.processClientEntryPreloads,
|
|
597
691
|
serverFrameReload: undefined,
|
|
598
692
|
reloadForNavigation: init.reloadForNavigation,
|
|
599
693
|
};
|
|
600
694
|
}
|
|
601
|
-
function
|
|
695
|
+
function createReconciliationTracker() {
|
|
602
696
|
let pending = 0;
|
|
603
697
|
let finalized = false;
|
|
698
|
+
let failed = false;
|
|
699
|
+
let failure;
|
|
604
700
|
let resolveReady;
|
|
605
|
-
let
|
|
701
|
+
let rejectReady;
|
|
702
|
+
let readyPromise = new Promise((resolve, reject) => {
|
|
606
703
|
resolveReady = resolve;
|
|
704
|
+
rejectReady = reject;
|
|
607
705
|
});
|
|
608
|
-
function
|
|
609
|
-
if (finalized
|
|
706
|
+
function maybeSettle() {
|
|
707
|
+
if (!finalized || pending !== 0)
|
|
708
|
+
return;
|
|
709
|
+
if (failed)
|
|
710
|
+
rejectReady?.(failure);
|
|
711
|
+
else
|
|
610
712
|
resolveReady?.();
|
|
611
|
-
|
|
612
|
-
|
|
713
|
+
resolveReady = undefined;
|
|
714
|
+
rejectReady = undefined;
|
|
715
|
+
}
|
|
716
|
+
function track() {
|
|
717
|
+
pending++;
|
|
718
|
+
let completed = false;
|
|
719
|
+
return () => {
|
|
720
|
+
if (completed)
|
|
721
|
+
return;
|
|
722
|
+
completed = true;
|
|
723
|
+
pending--;
|
|
724
|
+
maybeSettle();
|
|
725
|
+
};
|
|
613
726
|
}
|
|
614
727
|
return {
|
|
615
|
-
track
|
|
616
|
-
|
|
617
|
-
let
|
|
618
|
-
|
|
619
|
-
if (
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
};
|
|
728
|
+
track,
|
|
729
|
+
waitFor(task) {
|
|
730
|
+
let complete = track();
|
|
731
|
+
void task.then(complete, (error) => {
|
|
732
|
+
if (!failed) {
|
|
733
|
+
failed = true;
|
|
734
|
+
failure = error;
|
|
735
|
+
}
|
|
736
|
+
complete();
|
|
737
|
+
});
|
|
625
738
|
},
|
|
626
739
|
finalize() {
|
|
627
740
|
finalized = true;
|
|
628
|
-
|
|
741
|
+
maybeSettle();
|
|
629
742
|
},
|
|
630
743
|
ready() {
|
|
631
744
|
return readyPromise;
|
|
@@ -678,7 +791,7 @@ function collectOwnedServerStyleTags(nodes, styles) {
|
|
|
678
791
|
i = findMarkerRangeEndIndex(nodes, end, i);
|
|
679
792
|
continue;
|
|
680
793
|
}
|
|
681
|
-
if (node instanceof HTMLStyleElement && node.matches('style[data-rmx]')) {
|
|
794
|
+
if (node instanceof HTMLStyleElement && node.matches('style[data-rmx-style]')) {
|
|
682
795
|
styles.push(node);
|
|
683
796
|
continue;
|
|
684
797
|
}
|
|
@@ -717,7 +830,7 @@ function copyOwnRmxEntries(target, source) {
|
|
|
717
830
|
target[key] = source[key];
|
|
718
831
|
}
|
|
719
832
|
}
|
|
720
|
-
function scheduleHydrationInContainer(container, context,
|
|
833
|
+
function scheduleHydrationInContainer(container, context, reconciliationTracker, signal) {
|
|
721
834
|
let hydrationMarkers = findHydrationMarkers(container);
|
|
722
835
|
if (hydrationMarkers.length === 0)
|
|
723
836
|
return;
|
|
@@ -728,13 +841,13 @@ function scheduleHydrationInContainer(container, context, initialHydrationTracke
|
|
|
728
841
|
let entry = hydrationData[marker.id];
|
|
729
842
|
if (!entry)
|
|
730
843
|
continue;
|
|
731
|
-
scheduleHydrationMarker(marker, entry, context,
|
|
844
|
+
scheduleHydrationMarker(marker, entry, context, reconciliationTracker, signal);
|
|
732
845
|
}
|
|
733
846
|
}
|
|
734
|
-
function scheduleHydrationMarker(marker, entry, context,
|
|
847
|
+
function scheduleHydrationMarker(marker, entry, context, reconciliationTracker, signal) {
|
|
735
848
|
if (signal?.aborted || context.lifecycleSignal.aborted)
|
|
736
849
|
return;
|
|
737
|
-
let done =
|
|
850
|
+
let done = reconciliationTracker?.track();
|
|
738
851
|
let key = `${entry.moduleUrl}#${entry.exportName}`;
|
|
739
852
|
let identity = {
|
|
740
853
|
moduleUrl: entry.moduleUrl,
|
|
@@ -854,25 +967,35 @@ function hydrateRegion(vElement, start, end, identity, context, signal) {
|
|
|
854
967
|
if (signal?.aborted)
|
|
855
968
|
return;
|
|
856
969
|
context.pendingClientEntries.delete(start);
|
|
857
|
-
//
|
|
858
|
-
//
|
|
859
|
-
//
|
|
860
|
-
let
|
|
861
|
-
if (owner) {
|
|
970
|
+
// During a server frame reload, expose the reload signal and reconciliation
|
|
971
|
+
// tracker to client frames created while this entry renders so blocking
|
|
972
|
+
// frames keep the reload pending until their content arrives.
|
|
973
|
+
let renderEntry = (root) => {
|
|
862
974
|
if (!signal) {
|
|
863
|
-
|
|
975
|
+
root.render(vElement);
|
|
864
976
|
return;
|
|
865
977
|
}
|
|
866
978
|
let frameRuntime = context.frame.$runtime;
|
|
867
|
-
invariant(isFrameRuntime(frameRuntime), 'Expected frame runtime while rendering a
|
|
979
|
+
invariant(isFrameRuntime(frameRuntime), 'Expected frame runtime while rendering a client entry during a reload');
|
|
868
980
|
let previousServerFrameReload = frameRuntime.serverFrameReload;
|
|
869
|
-
frameRuntime.serverFrameReload = {
|
|
981
|
+
frameRuntime.serverFrameReload = {
|
|
982
|
+
signal,
|
|
983
|
+
reconciliationTracker: context.reconciliationTracker,
|
|
984
|
+
blockingFrameTracker: context.blockingFrameTracker,
|
|
985
|
+
};
|
|
870
986
|
try {
|
|
871
|
-
|
|
987
|
+
root.render(vElement);
|
|
872
988
|
}
|
|
873
989
|
finally {
|
|
874
990
|
frameRuntime.serverFrameReload = previousServerFrameReload;
|
|
875
991
|
}
|
|
992
|
+
};
|
|
993
|
+
// The same marker can be discovered by overlapping hydration passes
|
|
994
|
+
// (for example, document root + nested frame root). Reuse the existing
|
|
995
|
+
// virtual root instead of redefining the marker property.
|
|
996
|
+
let owner = getClientEntryBoundaryOwner(start);
|
|
997
|
+
if (owner) {
|
|
998
|
+
renderEntry(owner.root);
|
|
876
999
|
return;
|
|
877
1000
|
}
|
|
878
1001
|
let root = createRangeRoot([start, end], {
|
|
@@ -886,7 +1009,7 @@ function hydrateRegion(vElement, start, end, identity, context, signal) {
|
|
|
886
1009
|
context.errorTarget.dispatchEvent(createComponentErrorEvent(getComponentError(event)));
|
|
887
1010
|
});
|
|
888
1011
|
setClientEntryBoundaryOwner(start, identity, root);
|
|
889
|
-
root
|
|
1012
|
+
renderEntry(root);
|
|
890
1013
|
}
|
|
891
1014
|
async function createSubFrames(nodes, context, options) {
|
|
892
1015
|
let tasks = [];
|
|
@@ -926,8 +1049,12 @@ async function createSubFrames(nodes, context, options) {
|
|
|
926
1049
|
moduleLoads: context.moduleLoads,
|
|
927
1050
|
frameInstances: context.frameInstances,
|
|
928
1051
|
namedFrames: context.namedFrames,
|
|
1052
|
+
processClientEntryPreloads: context.processClientEntryPreloads,
|
|
929
1053
|
});
|
|
930
1054
|
context.frameInstances.set(node, subFrame);
|
|
1055
|
+
if (frameMarker.status === 'resolved') {
|
|
1056
|
+
tasks.push(subFrame.ready());
|
|
1057
|
+
}
|
|
931
1058
|
}
|
|
932
1059
|
}
|
|
933
1060
|
i = findMarkerRangeEndIndex(nodes, end, i);
|