25
26
import hasOwnProperty from 'shared/hasOwnProperty';
27
import {checkAttributeStringCoercion} from 'shared/CheckStringCoercion';
28
-import ReactDOMSharedInternals from 'shared/ReactDOMSharedInternals.js';
29
-const {Dispatcher} = ReactDOMSharedInternals;
28
29
import {
30
precacheFiberNode,
1934
tagCaches = null;
1935
}
1936
1939
-// It is valid to preload even when we aren't actively rendering. For cases where Float functions are
1940
-// called when there is no rendering we track the last used document. It is not safe to insert
1941
-// arbitrary resources into the lastCurrentDocument b/c it may not actually be the document
1942
-// that the resource is meant to apply too (for example stylesheets or scripts). This is only
1943
-// appropriate for resources that don't really have a strict tie to the document itself for example
1944
-// preloads
1945
-let lastCurrentDocument: ?Document = null;
1946
-let previousDispatcher = null;
1947
-export function prepareRendererToRender(rootContainer: Container) {
1948
- if (enableFloat) {
1949
- const rootNode = getHoistableRoot(rootContainer);
1950
- lastCurrentDocument = getDocumentFromRoot(rootNode);
1951
-
1952
- previousDispatcher = Dispatcher.current;
1953
- Dispatcher.current = ReactDOMClientDispatcher;
1954
- }
1955
-}
1956
-
1957
-export function resetRendererAfterRender() {
1958
- if (enableFloat) {
1959
- Dispatcher.current = previousDispatcher;
1960
- previousDispatcher = null;
1961
- }
1962
-}
1963
-
1937
// global collections of Resources
1938
const preloadPropsMap: Map<string, PreloadProps> = new Map();
1939
const preconnectsSet: Set<string> = new Set();
1955
return currentContainer ? getHoistableRoot(currentContainer) : null;
1956
}
1957
1985
-// Preloads are somewhat special. Even if we don't have the Document
1986
-// used by the root that is rendering a component trying to insert a preload
1987
-// we can still seed the file cache by doing the preload on any document we have
1988
-// access to. We prefer the currentDocument if it exists, we also prefer the
1989
-// lastCurrentDocument if that exists. As a fallback we will use the window.document
1990
-// if available.
1991
-function getDocumentForPreloads(): ?Document {
1992
- const root = getCurrentResourceRoot();
1993
- if (root) {
1994
- return root.ownerDocument || root;
1995
- } else {
1996
- try {
1997
- return lastCurrentDocument || window.document;
1998
- } catch (error) {
1999
- return null;
2000
- }
2001
- }
2002
-}
2003
-
1958
function getDocumentFromRoot(root: HoistableRoot): Document {
1959
return root.ownerDocument || root;
1960
}
1969
preinit,
1970
};
1971
1972
+// We expect this to get inlined. It is a function mostly to communicate the special nature of
1973
+// how we resolve the HoistableRoot for ReactDOM.pre*() methods. Because we support calling
1974
+// these methods outside of render there is no way to know which Document or ShadowRoot is 'scoped'
1975
+// and so we have to fall back to something universal. Currently we just refer to the global document.
1976
+// This is notable because nowhere else in ReactDOM do we actually reference the global document or window
1977
+// because we may be rendering inside an iframe.
1978
+function getDocumentForImperativeFloatMethods(): Document {
1979
+ return document;
1980
+}
1981
+
1982
function preconnectAs(
1983
rel: 'preconnect' | 'dns-prefetch',
1984
crossOrigin: null | '' | 'use-credentials',
1985
href: string,
1986
) {
2023
- const ownerDocument = getDocumentForPreloads();
2024
- if (typeof href === 'string' && href && ownerDocument) {
1987
+ const ownerDocument = getDocumentForImperativeFloatMethods();
1988
+ if (typeof href === 'string' && href) {
1989
const limitedEscapedHref =
1990
escapeSelectorAttributeValueInsideDoubleQuotes(href);
1991
let key = `link[rel="${rel}"][href="${limitedEscapedHref}"]`;
2007
}
2008
2009
function prefetchDNS(href: string, options?: mixed) {
2010
+ if (!enableFloat) {
2011
+ return;
2012
+ }
2013
if (__DEV__) {
2014
if (typeof href !== 'string' || !href) {
2015
console.error(
2072
type?: string,
2073
};
2074
function preload(href: string, options: PreloadOptions) {
2075
+ if (!enableFloat) {
2076
+ return;
2077
+ }
2078
if (__DEV__) {
2079
validatePreloadArguments(href, options);
2080
}
2111
- const ownerDocument = getDocumentForPreloads();
2081
+ const ownerDocument = getDocumentForImperativeFloatMethods();
2082
if (
2083
typeof href === 'string' &&
2084
href &&
2136
integrity?: string,
2137
};
2138
function preinit(href: string, options: PreinitOptions) {
2139
+ if (!enableFloat) {
2140
+ return;
2141
+ }
2142
if (__DEV__) {
2143
validatePreinitArguments(href, options);
2144
}
2145
+ const ownerDocument = getDocumentForImperativeFloatMethods();
2146
2147
if (
2148
typeof href === 'string' &&
2150
typeof options === 'object' &&
2151
options !== null
2152
) {
2179
- const resourceRoot = getCurrentResourceRoot();
2153
const as = options.as;
2181
- if (!resourceRoot) {
2182
- if (as === 'style' || as === 'script') {
2183
- // We are going to emit a preload as a best effort fallback since this preinit
2184
- // was called outside of a render. Given the passive nature of this fallback
2185
- // we do not warn in dev when props disagree if there happens to already be a
2186
- // matching preload with this href
2187
- const preloadDocument = getDocumentForPreloads();
2188
- if (preloadDocument) {
2189
- const limitedEscapedHref =
2190
- escapeSelectorAttributeValueInsideDoubleQuotes(href);
2191
- const preloadKey = `link[rel="preload"][as="${as}"][href="${limitedEscapedHref}"]`;
2192
- let key = preloadKey;
2193
- switch (as) {
2194
- case 'style':
2195
- key = getStyleKey(href);
2196
- break;
2197
- case 'script':
2198
- key = getScriptKey(href);
2199
- break;
2200
- }
2201
- if (!preloadPropsMap.has(key)) {
2202
- const preloadProps = preloadPropsFromPreinitOptions(
2203
- href,
2204
- as,
2205
- options,
2206
- );
2207
- preloadPropsMap.set(key, preloadProps);
2208
-
2209
- if (null === preloadDocument.querySelector(preloadKey)) {
2210
- const instance = preloadDocument.createElement('link');
2211
- setInitialProperties(instance, 'link', preloadProps);
2212
- markNodeAsHoistable(instance);
2213
- (preloadDocument.head: any).appendChild(instance);
2214
- }
2215
- }
2216
- }
2217
- }
2218
- return;
2219
- }
2154
2155
switch (as) {
2156
case 'style': {
2223
- const styles = getResourcesFromRoot(resourceRoot).hoistableStyles;
2157
+ const styles = getResourcesFromRoot(ownerDocument).hoistableStyles;
2158
2159
const key = getStyleKey(href);
2160
const precedence = options.precedence || 'default';
2173
};
2174
2175
// Attempt to hydrate instance from DOM
2242
- let instance: null | Instance = resourceRoot.querySelector(
2176
+ let instance: null | Instance = ownerDocument.querySelector(
2177
getStylesheetSelectorFromKey(key),
2178
);
2179
if (instance) {
2189
if (preloadProps) {
2190
adoptPreloadPropsForStylesheet(stylesheetProps, preloadProps);
2191
}
2258
- const ownerDocument = getDocumentFromRoot(resourceRoot);
2192
const link = (instance = ownerDocument.createElement('link'));
2193
markNodeAsHoistable(link);
2194
setInitialProperties(link, 'link', stylesheetProps);
2205
});
2206
2207
state.loading |= Inserted;
2275
- insertStylesheet(instance, precedence, resourceRoot);
2208
+ insertStylesheet(instance, precedence, ownerDocument);
2209
}
2210
2211
// Construct a Resource and cache it
2220
}
2221
case 'script': {
2222
const src = href;
2290
- const scripts = getResourcesFromRoot(resourceRoot).hoistableScripts;
2223
+ const scripts = getResourcesFromRoot(ownerDocument).hoistableScripts;
2224
2225
const key = getScriptKey(src);
2226
2233
}
2234
2235
// Attempt to hydrate instance from DOM
2303
- let instance: null | Instance = resourceRoot.querySelector(
2236
+ let instance: null | Instance = ownerDocument.querySelector(
2237
getScriptSelectorFromKey(key),
2238
);
2239
if (!instance) {
2244
if (preloadProps) {
2245
adoptPreloadPropsForScript(scriptProps, preloadProps);
2246
}
2314
- const ownerDocument = getDocumentFromRoot(resourceRoot);
2247
instance = ownerDocument.createElement('script');
2248
markNodeAsHoistable(instance);
2249
setInitialProperties(instance, 'link', scriptProps);
2264
}
2265
}
2266
2335
-function preloadPropsFromPreinitOptions(
2336
- href: string,
2337
- as: ResourceType,
2338
- options: PreinitOptions,
2339
-): PreloadProps {
2340
- return {
2341
- href,
2342
- rel: 'preload',
2343
- as,
2344
- crossOrigin: as === 'font' ? '' : options.crossOrigin,
2345
- integrity: options.integrity,
2346
- };
2347
-}
2348
-
2267
function stylesheetPropsFromPreinitOptions(
2268
href: string,
2269
precedence: string,