UNPKG

21.8 kBJavaScriptView Raw
1/**
2 * react-router v8.0.0
3 *
4 * Copyright (c) Remix Software Inc.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE.md file in the root directory of this source tree.
8 *
9 * @license MIT
10 */
11import { matchRoutes } from "../../router/utils.js";
12import { DataRouterContext, DataRouterStateContext, useIsRSCRouterContext } from "../../context.js";
13import { useLocation } from "../../hooks.js";
14import { warnOnce } from "../../server-runtime/warnings.js";
15import invariant from "./invariant.js";
16import { getKeyedLinksForMatches, getKeyedPrefetchLinks, getModuleLinkHrefs, getNewMatchesForLinks, isPageLinkDescriptor } from "./links.js";
17import { escapeHtml } from "./markup.js";
18import { singleFetchUrl } from "./single-fetch.js";
19import { getPartialManifest, isFogOfWarEnabled } from "./fog-of-war.js";
20import * as React$1 from "react";
21//#region lib/dom/ssr/components.tsx
22function useDataRouterContext() {
23 let context = React$1.useContext(DataRouterContext);
24 invariant(context, "You must render this element inside a <DataRouterContext.Provider> element");
25 return context;
26}
27function useDataRouterStateContext() {
28 let context = React$1.useContext(DataRouterStateContext);
29 invariant(context, "You must render this element inside a <DataRouterStateContext.Provider> element");
30 return context;
31}
32const FrameworkContext = React$1.createContext(void 0);
33FrameworkContext.displayName = "FrameworkContext";
34function useFrameworkContext() {
35 let context = React$1.useContext(FrameworkContext);
36 invariant(context, "You must render this element inside a <HydratedRouter> element");
37 return context;
38}
39function usePrefetchBehavior(prefetch, theirElementProps) {
40 let frameworkContext = React$1.useContext(FrameworkContext);
41 let [maybePrefetch, setMaybePrefetch] = React$1.useState(false);
42 let [shouldPrefetch, setShouldPrefetch] = React$1.useState(false);
43 let { onFocus, onBlur, onMouseEnter, onMouseLeave, onTouchStart } = theirElementProps;
44 let ref = React$1.useRef(null);
45 React$1.useEffect(() => {
46 if (prefetch === "render") setShouldPrefetch(true);
47 if (prefetch === "viewport") {
48 let callback = (entries) => {
49 entries.forEach((entry) => {
50 setShouldPrefetch(entry.isIntersecting);
51 });
52 };
53 let observer = new IntersectionObserver(callback, { threshold: .5 });
54 if (ref.current) observer.observe(ref.current);
55 return () => {
56 observer.disconnect();
57 };
58 }
59 }, [prefetch]);
60 React$1.useEffect(() => {
61 if (maybePrefetch) {
62 let id = setTimeout(() => {
63 setShouldPrefetch(true);
64 }, 100);
65 return () => {
66 clearTimeout(id);
67 };
68 }
69 }, [maybePrefetch]);
70 let setIntent = () => {
71 setMaybePrefetch(true);
72 };
73 let cancelIntent = () => {
74 setMaybePrefetch(false);
75 setShouldPrefetch(false);
76 };
77 if (!frameworkContext) return [
78 false,
79 ref,
80 {}
81 ];
82 if (prefetch !== "intent") return [
83 shouldPrefetch,
84 ref,
85 {}
86 ];
87 return [
88 shouldPrefetch,
89 ref,
90 {
91 onFocus: composeEventHandlers(onFocus, setIntent),
92 onBlur: composeEventHandlers(onBlur, cancelIntent),
93 onMouseEnter: composeEventHandlers(onMouseEnter, setIntent),
94 onMouseLeave: composeEventHandlers(onMouseLeave, cancelIntent),
95 onTouchStart: composeEventHandlers(onTouchStart, setIntent)
96 }
97 ];
98}
99function composeEventHandlers(theirHandler, ourHandler) {
100 return (event) => {
101 theirHandler && theirHandler(event);
102 if (!event.defaultPrevented) ourHandler(event);
103 };
104}
105function getActiveMatches(matches, errors, isSpaMode) {
106 if (isSpaMode && !isHydrated) return [matches[0]];
107 if (errors) {
108 let errorIdx = matches.findIndex((m) => errors[m.route.id] !== void 0);
109 return matches.slice(0, errorIdx + 1);
110 }
111 return matches;
112}
113const CRITICAL_CSS_DATA_ATTRIBUTE = "data-react-router-critical-css";
114/**
115* Renders all the [`<link>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link)
116* tags created by the route module's [`links`](../../start/framework/route-module#links)
117* export. You should render it inside the [`<head>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head)
118* of your document.
119*
120* @example
121* import { Links } from "react-router";
122*
123* export default function Root() {
124* return (
125* <html>
126* <head>
127* <Links />
128* </head>
129* <body></body>
130* </html>
131* );
132* }
133*
134* @public
135* @category Components
136* @mode framework
137* @param props Props
138* @param {LinksProps.nonce} props.nonce n/a
139* @param {LinksProps.crossOrigin} props.crossOrigin n/a
140* @returns A collection of React elements for [`<link>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link)
141* tags
142*/
143function Links({ nonce, crossOrigin }) {
144 let { isSpaMode, manifest, routeModules, criticalCss, nonce: contextNonce } = useFrameworkContext();
145 let { errors, matches: routerMatches } = useDataRouterStateContext();
146 let matches = getActiveMatches(routerMatches, errors, isSpaMode);
147 let keyedLinks = React$1.useMemo(() => getKeyedLinksForMatches(matches, routeModules, manifest), [
148 matches,
149 routeModules,
150 manifest
151 ]);
152 if (nonce == null && contextNonce) nonce = contextNonce;
153 return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, typeof criticalCss === "string" ? /* @__PURE__ */ React$1.createElement("style", {
154 [CRITICAL_CSS_DATA_ATTRIBUTE]: "",
155 nonce,
156 dangerouslySetInnerHTML: { __html: criticalCss }
157 }) : null, typeof criticalCss === "object" ? /* @__PURE__ */ React$1.createElement("link", {
158 [CRITICAL_CSS_DATA_ATTRIBUTE]: "",
159 rel: "stylesheet",
160 href: criticalCss.href,
161 nonce,
162 crossOrigin
163 }) : null, keyedLinks.map(({ key, link }) => isPageLinkDescriptor(link) ? /* @__PURE__ */ React$1.createElement(PrefetchPageLinks, {
164 key,
165 nonce,
166 ...link,
167 crossOrigin: link.crossOrigin ?? crossOrigin
168 }) : /* @__PURE__ */ React$1.createElement("link", {
169 key,
170 nonce,
171 ...link,
172 crossOrigin: link.crossOrigin ?? crossOrigin
173 })));
174}
175/**
176* Renders [`<link rel=prefetch|modulepreload>`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement/rel)
177* tags for modules and data of another page to enable an instant navigation to
178* that page. [`<Link prefetch>`](./Link#prefetch) uses this internally, but you
179* can render it to prefetch a page for any other reason.
180*
181* For example, you may render one of this as the user types into a search field
182* to prefetch search results before they click through to their selection.
183*
184* @example
185* import { PrefetchPageLinks } from "react-router";
186*
187* <PrefetchPageLinks page="/absolute/path" />
188*
189* @public
190* @category Components
191* @mode framework
192* @param props Props
193* @param {PageLinkDescriptor.page} props.page n/a
194* @param props.linkProps Additional props to spread onto the [`<link>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link)
195* tags, such as [`crossOrigin`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement/crossOrigin),
196* [`integrity`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement/integrity),
197* [`rel`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement/rel),
198* etc.
199* @returns A collection of React elements for [`<link>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link)
200* tags
201*/
202function PrefetchPageLinks({ page, ...linkProps }) {
203 let rsc = useIsRSCRouterContext();
204 let { nonce: contextNonce } = useFrameworkContext();
205 let { router } = useDataRouterContext();
206 let matches = React$1.useMemo(() => matchRoutes(router.routes, page, router.basename), [
207 router.routes,
208 page,
209 router.basename
210 ]);
211 if (!matches) return null;
212 if (linkProps.nonce == null && contextNonce) linkProps = {
213 ...linkProps,
214 nonce: contextNonce
215 };
216 if (rsc) return /* @__PURE__ */ React$1.createElement(RSCPrefetchPageLinksImpl, {
217 page,
218 matches,
219 ...linkProps
220 });
221 return /* @__PURE__ */ React$1.createElement(PrefetchPageLinksImpl, {
222 page,
223 matches,
224 ...linkProps
225 });
226}
227function useKeyedPrefetchLinks(matches) {
228 let { manifest, routeModules } = useFrameworkContext();
229 let [keyedPrefetchLinks, setKeyedPrefetchLinks] = React$1.useState([]);
230 React$1.useEffect(() => {
231 let interrupted = false;
232 getKeyedPrefetchLinks(matches, manifest, routeModules).then((links) => {
233 if (!interrupted) setKeyedPrefetchLinks(links);
234 });
235 return () => {
236 interrupted = true;
237 };
238 }, [
239 matches,
240 manifest,
241 routeModules
242 ]);
243 return keyedPrefetchLinks;
244}
245function RSCPrefetchPageLinksImpl({ page, matches: nextMatches, ...linkProps }) {
246 let location = useLocation();
247 let dataHrefs = React$1.useMemo(() => {
248 if (page === location.pathname + location.search + location.hash) return [];
249 let url = singleFetchUrl(page, "rsc");
250 let hasSomeRoutesWithShouldRevalidate = false;
251 let targetRoutes = [];
252 for (let match of nextMatches) if (typeof match.route.shouldRevalidate === "function") hasSomeRoutesWithShouldRevalidate = true;
253 else targetRoutes.push(match.route.id);
254 if (hasSomeRoutesWithShouldRevalidate && targetRoutes.length > 0) url.searchParams.set("_routes", targetRoutes.join(","));
255 return [url.pathname + url.search];
256 }, [
257 page,
258 location,
259 nextMatches
260 ]);
261 return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, dataHrefs.map((href) => /* @__PURE__ */ React$1.createElement("link", {
262 key: href,
263 rel: "prefetch",
264 as: "fetch",
265 href,
266 ...linkProps
267 })));
268}
269function PrefetchPageLinksImpl({ page, matches: nextMatches, ...linkProps }) {
270 let location = useLocation();
271 let { manifest, routeModules } = useFrameworkContext();
272 let { loaderData, matches } = useDataRouterStateContext();
273 let newMatchesForData = React$1.useMemo(() => getNewMatchesForLinks(page, nextMatches, matches, manifest, location, "data"), [
274 page,
275 nextMatches,
276 matches,
277 manifest,
278 location
279 ]);
280 let newMatchesForAssets = React$1.useMemo(() => getNewMatchesForLinks(page, nextMatches, matches, manifest, location, "assets"), [
281 page,
282 nextMatches,
283 matches,
284 manifest,
285 location
286 ]);
287 let dataHrefs = React$1.useMemo(() => {
288 if (page === location.pathname + location.search + location.hash) return [];
289 let routesParams = /* @__PURE__ */ new Set();
290 let foundOptOutRoute = false;
291 nextMatches.forEach((m) => {
292 let manifestRoute = manifest.routes[m.route.id];
293 if (!manifestRoute || !manifestRoute.hasLoader) return;
294 if (!newMatchesForData.some((m2) => m2.route.id === m.route.id) && m.route.id in loaderData && routeModules[m.route.id]?.shouldRevalidate) foundOptOutRoute = true;
295 else if (manifestRoute.hasClientLoader) foundOptOutRoute = true;
296 else routesParams.add(m.route.id);
297 });
298 if (routesParams.size === 0) return [];
299 let url = singleFetchUrl(page, "data");
300 if (foundOptOutRoute && routesParams.size > 0) url.searchParams.set("_routes", nextMatches.filter((m) => routesParams.has(m.route.id)).map((m) => m.route.id).join(","));
301 return [url.pathname + url.search];
302 }, [
303 loaderData,
304 location,
305 manifest,
306 newMatchesForData,
307 nextMatches,
308 page,
309 routeModules
310 ]);
311 let moduleHrefs = React$1.useMemo(() => getModuleLinkHrefs(newMatchesForAssets, manifest), [newMatchesForAssets, manifest]);
312 let keyedPrefetchLinks = useKeyedPrefetchLinks(newMatchesForAssets);
313 return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, dataHrefs.map((href) => /* @__PURE__ */ React$1.createElement("link", {
314 key: href,
315 rel: "prefetch",
316 as: "fetch",
317 href,
318 ...linkProps
319 })), moduleHrefs.map((href) => /* @__PURE__ */ React$1.createElement("link", {
320 key: href,
321 rel: "modulepreload",
322 href,
323 ...linkProps
324 })), keyedPrefetchLinks.map(({ key, link }) => /* @__PURE__ */ React$1.createElement("link", {
325 key,
326 nonce: linkProps.nonce,
327 ...link,
328 crossOrigin: link.crossOrigin ?? linkProps.crossOrigin
329 })));
330}
331/**
332* Renders all the [`<meta>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta)
333* tags created by the route module's [`meta`](../../start/framework/route-module#meta)
334* export. You should render it inside the [`<head>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head)
335* of your document.
336*
337* @example
338* import { Meta } from "react-router";
339*
340* export default function Root() {
341* return (
342* <html>
343* <head>
344* <Meta />
345* </head>
346* </html>
347* );
348* }
349*
350* @public
351* @category Components
352* @mode framework
353* @returns A collection of React elements for [`<meta>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta)
354* tags
355*/
356function Meta() {
357 let { isSpaMode, routeModules } = useFrameworkContext();
358 let { errors, matches: routerMatches, loaderData } = useDataRouterStateContext();
359 let location = useLocation();
360 let _matches = getActiveMatches(routerMatches, errors, isSpaMode);
361 let error = null;
362 if (errors) error = errors[_matches[_matches.length - 1].route.id];
363 let meta = [];
364 let leafMeta = null;
365 let matches = [];
366 for (let i = 0; i < _matches.length; i++) {
367 let _match = _matches[i];
368 let routeId = _match.route.id;
369 let data = loaderData[routeId];
370 let params = _match.params;
371 let routeModule = routeModules[routeId];
372 let routeMeta = [];
373 let match = {
374 id: routeId,
375 loaderData: data,
376 meta: [],
377 params: _match.params,
378 pathname: _match.pathname,
379 handle: _match.route.handle,
380 error
381 };
382 matches[i] = match;
383 if (routeModule?.meta) routeMeta = typeof routeModule.meta === "function" ? routeModule.meta({
384 loaderData: data,
385 params,
386 location,
387 matches,
388 error
389 }) : Array.isArray(routeModule.meta) ? [...routeModule.meta] : routeModule.meta;
390 else if (leafMeta) routeMeta = [...leafMeta];
391 routeMeta = routeMeta || [];
392 if (!Array.isArray(routeMeta)) throw new Error("The route at " + _match.route.path + " returns an invalid value. All route meta functions must return an array of meta objects.\n\nTo reference the meta function API, see https://reactrouter.com/start/framework/route-module#meta");
393 match.meta = routeMeta;
394 matches[i] = match;
395 meta = [...routeMeta];
396 leafMeta = meta;
397 }
398 return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, meta.flat().map((metaProps) => {
399 if (!metaProps) return null;
400 if ("tagName" in metaProps) {
401 let { tagName, ...rest } = metaProps;
402 if (!isValidMetaTag(tagName)) {
403 console.warn(`A meta object uses an invalid tagName: ${tagName}. Expected either 'link' or 'meta'`);
404 return null;
405 }
406 let Comp = tagName;
407 return /* @__PURE__ */ React$1.createElement(Comp, {
408 key: JSON.stringify(rest),
409 ...rest
410 });
411 }
412 if ("title" in metaProps) return /* @__PURE__ */ React$1.createElement("title", { key: "title" }, String(metaProps.title));
413 if ("charset" in metaProps) {
414 metaProps.charSet ??= metaProps.charset;
415 delete metaProps.charset;
416 }
417 if ("charSet" in metaProps && metaProps.charSet != null) return typeof metaProps.charSet === "string" ? /* @__PURE__ */ React$1.createElement("meta", {
418 key: "charSet",
419 charSet: metaProps.charSet
420 }) : null;
421 if ("script:ld+json" in metaProps) try {
422 let json = JSON.stringify(metaProps["script:ld+json"]);
423 return /* @__PURE__ */ React$1.createElement("script", {
424 key: `script:ld+json:${json}`,
425 type: "application/ld+json",
426 dangerouslySetInnerHTML: { __html: escapeHtml(json) }
427 });
428 } catch (e) {
429 return null;
430 }
431 return /* @__PURE__ */ React$1.createElement("meta", {
432 key: JSON.stringify(metaProps),
433 ...metaProps
434 });
435 }));
436}
437function isValidMetaTag(tagName) {
438 return typeof tagName === "string" && /^(meta|link)$/.test(tagName);
439}
440/**
441* Tracks whether hydration is finished, so scripts can be skipped
442* during client-side updates.
443*/
444let isHydrated = false;
445function setIsHydrated() {
446 isHydrated = true;
447}
448/**
449* Renders the client runtime of your app. It should be rendered inside the
450* [`<body>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/body)
451* of the document.
452*
453* If server rendering, you can omit `<Scripts/>` and the app will work as a
454* traditional web app without JavaScript, relying solely on HTML and browser
455* behaviors.
456*
457* @example
458* import { Scripts } from "react-router";
459*
460* export default function Root() {
461* return (
462* <html>
463* <head />
464* <body>
465* <Scripts />
466* </body>
467* </html>
468* );
469* }
470*
471* @public
472* @category Components
473* @mode framework
474* @param scriptProps Additional props to spread onto the [`<script>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script)
475* tags, such as [`crossOrigin`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement/crossOrigin),
476* [`nonce`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/nonce),
477* etc.
478* @returns A collection of React elements for [`<script>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script)
479* tags
480*/
481function Scripts(scriptProps) {
482 let { manifest, serverHandoffString, isSpaMode, renderMeta, routeDiscovery, ssr, nonce: contextNonce } = useFrameworkContext();
483 let { router, static: isStatic, staticContext } = useDataRouterContext();
484 let { matches: routerMatches } = useDataRouterStateContext();
485 let isRSCRouterContext = useIsRSCRouterContext();
486 let enableFogOfWar = isFogOfWarEnabled(routeDiscovery, ssr);
487 if (scriptProps.nonce == null && contextNonce) scriptProps = {
488 ...scriptProps,
489 nonce: contextNonce
490 };
491 if (renderMeta) renderMeta.didRenderScripts = true;
492 let matches = getActiveMatches(routerMatches, null, isSpaMode);
493 React$1.useEffect(() => {
494 setIsHydrated();
495 }, []);
496 let initialScripts = React$1.useMemo(() => {
497 if (isRSCRouterContext) return null;
498 let contextScript = staticContext ? `window.__reactRouterContext = ${serverHandoffString};window.__reactRouterContext.stream = new ReadableStream({start(controller){window.__reactRouterContext.streamController = controller;}}).pipeThrough(new TextEncoderStream());` : " ";
499 let routeModulesScript = !isStatic ? " " : `${manifest.hmr?.runtime ? `import ${JSON.stringify(manifest.hmr.runtime)};` : ""}${!enableFogOfWar ? `import ${JSON.stringify(manifest.url)}` : ""};
500${matches.map((match, routeIndex) => {
501 let routeVarName = `route${routeIndex}`;
502 let manifestEntry = manifest.routes[match.route.id];
503 invariant(manifestEntry, `Route ${match.route.id} not found in manifest`);
504 let { clientActionModule, clientLoaderModule, clientMiddlewareModule, hydrateFallbackModule, module } = manifestEntry;
505 let chunks = [
506 ...clientActionModule ? [{
507 module: clientActionModule,
508 varName: `${routeVarName}_clientAction`
509 }] : [],
510 ...clientLoaderModule ? [{
511 module: clientLoaderModule,
512 varName: `${routeVarName}_clientLoader`
513 }] : [],
514 ...clientMiddlewareModule ? [{
515 module: clientMiddlewareModule,
516 varName: `${routeVarName}_clientMiddleware`
517 }] : [],
518 ...hydrateFallbackModule ? [{
519 module: hydrateFallbackModule,
520 varName: `${routeVarName}_HydrateFallback`
521 }] : [],
522 {
523 module,
524 varName: `${routeVarName}_main`
525 }
526 ];
527 if (chunks.length === 1) return `import * as ${routeVarName} from ${JSON.stringify(module)};`;
528 return [chunks.map((chunk) => `import * as ${chunk.varName} from "${chunk.module}";`).join("\n"), `const ${routeVarName} = {${chunks.map((chunk) => `...${chunk.varName}`).join(",")}};`].join("\n");
529 }).join("\n")}
530 ${enableFogOfWar ? `window.__reactRouterManifest = ${JSON.stringify(getPartialManifest(manifest, router), null, 2)};` : ""}
531 window.__reactRouterRouteModules = {${matches.map((match, index) => `${JSON.stringify(match.route.id)}:route${index}`).join(",")}};
532
533import(${JSON.stringify(manifest.entry.module)});`;
534 return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, /* @__PURE__ */ React$1.createElement("script", {
535 ...scriptProps,
536 suppressHydrationWarning: true,
537 dangerouslySetInnerHTML: { __html: contextScript },
538 type: void 0
539 }), /* @__PURE__ */ React$1.createElement("script", {
540 ...scriptProps,
541 suppressHydrationWarning: true,
542 dangerouslySetInnerHTML: { __html: routeModulesScript },
543 type: "module",
544 async: true
545 }));
546 }, []);
547 let preloads = isHydrated || isRSCRouterContext ? [] : [...new Set(manifest.entry.imports.concat(getModuleLinkHrefs(matches, manifest, { includeHydrateFallback: true })))];
548 let sri = typeof manifest.sri === "object" ? manifest.sri : {};
549 warnOnce(!isRSCRouterContext, "The <Scripts /> element is a no-op when using RSC and can be safely removed.");
550 return isHydrated || isRSCRouterContext ? null : /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, typeof manifest.sri === "object" ? /* @__PURE__ */ React$1.createElement("script", {
551 ...scriptProps,
552 "rr-importmap": "",
553 type: "importmap",
554 suppressHydrationWarning: true,
555 dangerouslySetInnerHTML: { __html: JSON.stringify({ integrity: sri }) }
556 }) : null, !enableFogOfWar ? /* @__PURE__ */ React$1.createElement("link", {
557 rel: "modulepreload",
558 href: manifest.url,
559 crossOrigin: scriptProps.crossOrigin,
560 integrity: sri[manifest.url],
561 nonce: scriptProps.nonce,
562 suppressHydrationWarning: true
563 }) : null, /* @__PURE__ */ React$1.createElement("link", {
564 rel: "modulepreload",
565 href: manifest.entry.module,
566 crossOrigin: scriptProps.crossOrigin,
567 integrity: sri[manifest.entry.module],
568 nonce: scriptProps.nonce,
569 suppressHydrationWarning: true
570 }), preloads.map((path) => /* @__PURE__ */ React$1.createElement("link", {
571 key: path,
572 rel: "modulepreload",
573 href: path,
574 crossOrigin: scriptProps.crossOrigin,
575 integrity: sri[path],
576 nonce: scriptProps.nonce,
577 suppressHydrationWarning: true
578 })), initialScripts);
579}
580function mergeRefs(...refs) {
581 return (value) => {
582 refs.forEach((ref) => {
583 if (typeof ref === "function") ref(value);
584 else if (ref != null) ref.current = value;
585 });
586 };
587}
588//#endregion
589export { CRITICAL_CSS_DATA_ATTRIBUTE, FrameworkContext, Links, Meta, PrefetchPageLinks, Scripts, mergeRefs, setIsHydrated, useFrameworkContext, usePrefetchBehavior };