forked from facebook/react
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathReactDOMFizzInstructionSetInlineSource.js
More file actions
116 lines (102 loc) · 3.63 KB
/
ReactDOMFizzInstructionSetInlineSource.js
File metadata and controls
116 lines (102 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/* eslint-disable dot-notation */
// Instruction set for Fizz inline scripts.
// DO NOT DIRECTLY IMPORT THIS FILE. This is the source for the compiled and
// minified code in ReactDOMFizzInstructionSetInlineCodeStrings.
import {
clientRenderBoundary,
completeBoundary,
completeSegment,
LOADED,
ERRORED,
} from './ReactDOMFizzInstructionSetShared';
export {clientRenderBoundary, completeBoundary, completeSegment};
// This function is almost identical to the version used by the external
// runtime (ReactDOMFizzInstructionSetExternalRuntime), with the exception of
// how we read completeBoundaryImpl and resourceMap
export function completeBoundaryWithStyles(
suspenseBoundaryID,
contentID,
styles,
) {
const completeBoundaryImpl = window['$RC'];
const resourceMap = window['$RM'];
const precedences = new Map();
const thisDocument = document;
let lastResource, node;
// Seed the precedence list with existing resources
const nodes = thisDocument.querySelectorAll(
'link[data-precedence],style[data-precedence]',
);
for (let i = 0; (node = nodes[i++]); ) {
precedences.set(node.dataset['precedence'], (lastResource = node));
}
let i = 0;
const dependencies = [];
let style, href, precedence, attr, loadingState, resourceEl;
function setStatus(s) {
this['s'] = s;
}
while ((style = styles[i++])) {
let j = 0;
href = style[j++];
// We check if this resource is already in our resourceMap and reuse it if so.
// If it is already loaded we don't return it as a depenendency since there is nothing
// to wait for
loadingState = resourceMap.get(href);
if (loadingState) {
if (loadingState['s'] !== 'l') {
dependencies.push(loadingState);
}
continue;
}
// We construct our new resource element, looping over remaining attributes if any
// setting them to the Element.
resourceEl = thisDocument.createElement('link');
resourceEl.href = href;
resourceEl.rel = 'stylesheet';
resourceEl.dataset['precedence'] = precedence = style[j++];
while ((attr = style[j++])) {
resourceEl.setAttribute(attr, style[j++]);
}
// We stash a pending promise in our map by href which will resolve or reject
// when the underlying resource loads or errors. We add it to the dependencies
// array to be returned.
loadingState = resourceEl['_p'] = new Promise((re, rj) => {
resourceEl.onload = re;
resourceEl.onerror = rj;
});
loadingState.then(
setStatus.bind(loadingState, LOADED),
setStatus.bind(loadingState, ERRORED),
);
resourceMap.set(href, loadingState);
dependencies.push(loadingState);
// The prior style resource is the last one placed at a given
// precedence or the last resource itself which may be null.
// We grab this value and then update the last resource for this
// precedence to be the inserted element, updating the lastResource
// pointer if needed.
const prior = precedences.get(precedence) || lastResource;
if (prior === lastResource) {
lastResource = resourceEl;
}
precedences.set(precedence, resourceEl);
// Finally, we insert the newly constructed instance at an appropriate location
// in the Document.
if (prior) {
prior.parentNode.insertBefore(resourceEl, prior.nextSibling);
} else {
const head = thisDocument.head;
head.insertBefore(resourceEl, head.firstChild);
}
}
Promise.all(dependencies).then(
completeBoundaryImpl.bind(null, suspenseBoundaryID, contentID, ''),
completeBoundaryImpl.bind(
null,
suspenseBoundaryID,
contentID,
'Resource failed to load',
),
);
}