-
Notifications
You must be signed in to change notification settings - Fork 47.4k
/
Copy pathReactDOMFizzInstructionSetInlineSource.js
141 lines (127 loc) · 4.64 KB
/
ReactDOMFizzInstructionSetInlineSource.js
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* 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,
} 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,
stylesheetDescriptors,
) {
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 and collect hoistable style tags
const nodes = thisDocument.querySelectorAll(
'link[data-precedence],style[data-precedence]',
);
const styleTagsToHoist = [];
for (let i = 0; (node = nodes[i++]); ) {
if (node.getAttribute('media') === 'not all') {
styleTagsToHoist.push(node);
} else {
if (node.tagName === 'LINK') {
resourceMap.set(node.getAttribute('href'), node);
}
precedences.set(node.dataset['precedence'], (lastResource = node));
}
}
let i = 0;
const dependencies = [];
let href, precedence, attr, loadingState, resourceEl, media;
// Sheets Mode
let sheetMode = true;
while (true) {
if (sheetMode) {
// Sheet Mode iterates over the stylesheet arguments and constructs them if new or checks them for
// dependency if they already existed
const stylesheetDescriptor = stylesheetDescriptors[i++];
if (!stylesheetDescriptor) {
// enter <style> Mode
sheetMode = false;
i = 0;
continue;
}
let avoidInsert = false;
let j = 0;
href = stylesheetDescriptor[j++];
if ((resourceEl = resourceMap.get(href))) {
// We have an already inserted stylesheet.
loadingState = resourceEl['_p'];
avoidInsert = true;
} else {
// We haven't already processed this href so we need to construct a stylesheet and hoist it
// We construct it here and attach a loadingState. We also check whether it matches
// media before we include it in the dependency array.
resourceEl = thisDocument.createElement('link');
resourceEl.href = href;
resourceEl.rel = 'stylesheet';
resourceEl.dataset['precedence'] = precedence =
stylesheetDescriptor[j++];
while ((attr = stylesheetDescriptor[j++])) {
resourceEl.setAttribute(attr, stylesheetDescriptor[j++]);
}
loadingState = resourceEl['_p'] = new Promise((resolve, reject) => {
resourceEl.onload = resolve;
resourceEl.onerror = reject;
});
// Save this resource element so we can bailout if it is used again
resourceMap.set(href, resourceEl);
}
media = resourceEl.getAttribute('media');
if (
loadingState &&
loadingState['s'] !== 'l' &&
(!media || window['matchMedia'](media).matches)
) {
dependencies.push(loadingState);
}
if (avoidInsert) {
// We have a link that is already in the document. We don't want to fall through to the insert path
continue;
}
} else {
// <style> mode iterates over not-yet-hoisted <style> tags with data-precedence and hoists them.
resourceEl = styleTagsToHoist[i++];
if (!resourceEl) {
// we are done with all style tags
break;
}
precedence = resourceEl.getAttribute('data-precedence');
resourceEl.removeAttribute('media');
}
// resourceEl is either a newly constructed <link rel="stylesheet" ...> or a <style> tag requiring hoisting
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',
),
);
}