|
5 | 5 | import {
|
6 | 6 | clientRenderBoundary,
|
7 | 7 | completeBoundary,
|
| 8 | + completeBoundaryWithStyles, |
8 | 9 | completeSegment,
|
9 | 10 | listenToFormSubmissionsForReplaying,
|
10 | 11 | } from './ReactDOMFizzInstructionSetShared';
|
11 | 12 |
|
12 |
| -export {clientRenderBoundary, completeBoundary, completeSegment}; |
13 |
| - |
14 |
| -const resourceMap = new Map(); |
15 |
| - |
16 |
| -// This function is almost identical to the version used by inline scripts |
17 |
| -// (ReactDOMFizzInstructionSetInlineSource), with the exception of how we read |
18 |
| -// completeBoundary and resourceMap |
19 |
| -export function completeBoundaryWithStyles( |
20 |
| - suspenseBoundaryID, |
21 |
| - contentID, |
22 |
| - stylesheetDescriptors, |
23 |
| -) { |
24 |
| - const precedences = new Map(); |
25 |
| - const thisDocument = document; |
26 |
| - let lastResource, node; |
27 |
| - |
28 |
| - // Seed the precedence list with existing resources and collect hoistable style tags |
29 |
| - const nodes = thisDocument.querySelectorAll( |
30 |
| - 'link[data-precedence],style[data-precedence]', |
31 |
| - ); |
32 |
| - const styleTagsToHoist = []; |
33 |
| - for (let i = 0; (node = nodes[i++]); ) { |
34 |
| - if (node.getAttribute('media') === 'not all') { |
35 |
| - styleTagsToHoist.push(node); |
36 |
| - } else { |
37 |
| - if (node.tagName === 'LINK') { |
38 |
| - resourceMap.set(node.getAttribute('href'), node); |
39 |
| - } |
40 |
| - precedences.set(node.dataset['precedence'], (lastResource = node)); |
41 |
| - } |
42 |
| - } |
43 |
| - |
44 |
| - let i = 0; |
45 |
| - const dependencies = []; |
46 |
| - let href, precedence, attr, loadingState, resourceEl, media; |
47 |
| - |
48 |
| - function cleanupWith(cb) { |
49 |
| - this['_p'] = null; |
50 |
| - cb(); |
51 |
| - } |
52 |
| - |
53 |
| - // Sheets Mode |
54 |
| - let sheetMode = true; |
55 |
| - while (true) { |
56 |
| - if (sheetMode) { |
57 |
| - // Sheet Mode iterates over the stylesheet arguments and constructs them if new or checks them for |
58 |
| - // dependency if they already existed |
59 |
| - const stylesheetDescriptor = stylesheetDescriptors[i++]; |
60 |
| - if (!stylesheetDescriptor) { |
61 |
| - // enter <style> Mode |
62 |
| - sheetMode = false; |
63 |
| - i = 0; |
64 |
| - continue; |
65 |
| - } |
66 |
| - |
67 |
| - let avoidInsert = false; |
68 |
| - let j = 0; |
69 |
| - href = stylesheetDescriptor[j++]; |
70 |
| - |
71 |
| - if ((resourceEl = resourceMap.get(href))) { |
72 |
| - // We have an already inserted stylesheet. |
73 |
| - loadingState = resourceEl['_p']; |
74 |
| - avoidInsert = true; |
75 |
| - } else { |
76 |
| - // We haven't already processed this href so we need to construct a stylesheet and hoist it |
77 |
| - // We construct it here and attach a loadingState. We also check whether it matches |
78 |
| - // media before we include it in the dependency array. |
79 |
| - resourceEl = thisDocument.createElement('link'); |
80 |
| - resourceEl.href = href; |
81 |
| - resourceEl.rel = 'stylesheet'; |
82 |
| - resourceEl.dataset['precedence'] = precedence = |
83 |
| - stylesheetDescriptor[j++]; |
84 |
| - while ((attr = stylesheetDescriptor[j++])) { |
85 |
| - resourceEl.setAttribute(attr, stylesheetDescriptor[j++]); |
86 |
| - } |
87 |
| - loadingState = resourceEl['_p'] = new Promise((resolve, reject) => { |
88 |
| - resourceEl.onload = cleanupWith.bind(resourceEl, resolve); |
89 |
| - resourceEl.onerror = cleanupWith.bind(resourceEl, reject); |
90 |
| - }); |
91 |
| - // Save this resource element so we can bailout if it is used again |
92 |
| - resourceMap.set(href, resourceEl); |
93 |
| - } |
94 |
| - media = resourceEl.getAttribute('media'); |
95 |
| - if (loadingState && (!media || window['matchMedia'](media).matches)) { |
96 |
| - dependencies.push(loadingState); |
97 |
| - } |
98 |
| - if (avoidInsert) { |
99 |
| - // We have a link that is already in the document. We don't want to fall through to the insert path |
100 |
| - continue; |
101 |
| - } |
102 |
| - } else { |
103 |
| - // <style> mode iterates over not-yet-hoisted <style> tags with data-precedence and hoists them. |
104 |
| - resourceEl = styleTagsToHoist[i++]; |
105 |
| - if (!resourceEl) { |
106 |
| - // we are done with all style tags |
107 |
| - break; |
108 |
| - } |
109 |
| - |
110 |
| - precedence = resourceEl.getAttribute('data-precedence'); |
111 |
| - resourceEl.removeAttribute('media'); |
112 |
| - } |
113 |
| - |
114 |
| - // resourceEl is either a newly constructed <link rel="stylesheet" ...> or a <style> tag requiring hoisting |
115 |
| - const prior = precedences.get(precedence) || lastResource; |
116 |
| - if (prior === lastResource) { |
117 |
| - lastResource = resourceEl; |
118 |
| - } |
119 |
| - precedences.set(precedence, resourceEl); |
120 |
| - |
121 |
| - // Finally, we insert the newly constructed instance at an appropriate location |
122 |
| - // in the Document. |
123 |
| - if (prior) { |
124 |
| - prior.parentNode.insertBefore(resourceEl, prior.nextSibling); |
125 |
| - } else { |
126 |
| - const head = thisDocument.head; |
127 |
| - head.insertBefore(resourceEl, head.firstChild); |
128 |
| - } |
129 |
| - } |
130 |
| - |
131 |
| - Promise.all(dependencies).then( |
132 |
| - completeBoundary.bind(null, suspenseBoundaryID, contentID, ''), |
133 |
| - completeBoundary.bind( |
134 |
| - null, |
135 |
| - suspenseBoundaryID, |
136 |
| - contentID, |
137 |
| - 'Resource failed to load', |
138 |
| - ), |
139 |
| - ); |
140 |
| -} |
| 13 | +// This is a string so Closure's advanced compilation mode doesn't mangle it. |
| 14 | +// These will be renamed to local references by the external-runtime-plugin. |
| 15 | +window['$RM'] = new Map(); |
| 16 | +window['$RX'] = clientRenderBoundary; |
| 17 | +window['$RC'] = completeBoundary; |
| 18 | +window['$RR'] = completeBoundaryWithStyles; |
| 19 | +window['$RS'] = completeSegment; |
141 | 20 |
|
142 | 21 | listenToFormSubmissionsForReplaying();
|
0 commit comments