| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 |
|
| 11 | import { loadRouteModule } from "./routeModules.js";
|
| 12 |
|
| 13 | |
| 14 | |
| 15 | |
| 16 |
|
| 17 | function getKeyedLinksForMatches(matches, routeModules, manifest) {
|
| 18 | return dedupeLinkDescriptors(matches.map((match) => {
|
| 19 | let module = routeModules[match.route.id];
|
| 20 | let route = manifest.routes[match.route.id];
|
| 21 | return [route && route.css ? route.css.map((href) => ({
|
| 22 | rel: "stylesheet",
|
| 23 | href
|
| 24 | })) : [], module?.links?.() || []];
|
| 25 | }).flat(2), getModuleLinkHrefs(matches, manifest));
|
| 26 | }
|
| 27 | function getRouteCssDescriptors(route) {
|
| 28 | if (!route.css) return [];
|
| 29 | return route.css.map((href) => ({
|
| 30 | rel: "stylesheet",
|
| 31 | href
|
| 32 | }));
|
| 33 | }
|
| 34 | async function prefetchRouteCss(route) {
|
| 35 | if (!route.css) return;
|
| 36 | let descriptors = getRouteCssDescriptors(route);
|
| 37 | await Promise.all(descriptors.map(prefetchStyleLink));
|
| 38 | }
|
| 39 | async function prefetchStyleLinks(route, routeModule) {
|
| 40 | if (!route.css && !routeModule.links || !isPreloadSupported()) return;
|
| 41 | let descriptors = [];
|
| 42 | if (route.css) descriptors.push(...getRouteCssDescriptors(route));
|
| 43 | if (routeModule.links) descriptors.push(...routeModule.links());
|
| 44 | if (descriptors.length === 0) return;
|
| 45 | let styleLinks = [];
|
| 46 | for (let descriptor of descriptors) if (!isPageLinkDescriptor(descriptor) && descriptor.rel === "stylesheet") styleLinks.push({
|
| 47 | ...descriptor,
|
| 48 | rel: "preload",
|
| 49 | as: "style"
|
| 50 | });
|
| 51 | await Promise.all(styleLinks.map(prefetchStyleLink));
|
| 52 | }
|
| 53 | async function prefetchStyleLink(descriptor) {
|
| 54 | return new Promise((resolve) => {
|
| 55 | if (descriptor.media && !window.matchMedia(descriptor.media).matches || document.querySelector(`link[rel="stylesheet"][href="${descriptor.href}"]`)) return resolve();
|
| 56 | let link = document.createElement("link");
|
| 57 | Object.assign(link, descriptor);
|
| 58 | function removeLink() {
|
| 59 | if (document.head.contains(link)) document.head.removeChild(link);
|
| 60 | }
|
| 61 | link.onload = () => {
|
| 62 | removeLink();
|
| 63 | resolve();
|
| 64 | };
|
| 65 | link.onerror = () => {
|
| 66 | removeLink();
|
| 67 | resolve();
|
| 68 | };
|
| 69 | document.head.appendChild(link);
|
| 70 | });
|
| 71 | }
|
| 72 | function isPageLinkDescriptor(object) {
|
| 73 | return object != null && typeof object.page === "string";
|
| 74 | }
|
| 75 | function isHtmlLinkDescriptor(object) {
|
| 76 | if (object == null) return false;
|
| 77 | if (object.href == null) return object.rel === "preload" && typeof object.imageSrcSet === "string" && typeof object.imageSizes === "string";
|
| 78 | return typeof object.rel === "string" && typeof object.href === "string";
|
| 79 | }
|
| 80 | async function getKeyedPrefetchLinks(matches, manifest, routeModules) {
|
| 81 | return dedupeLinkDescriptors((await Promise.all(matches.map(async (match) => {
|
| 82 | let route = manifest.routes[match.route.id];
|
| 83 | if (route) {
|
| 84 | let mod = await loadRouteModule(route, routeModules);
|
| 85 | return mod.links ? mod.links() : [];
|
| 86 | }
|
| 87 | return [];
|
| 88 | }))).flat(1).filter(isHtmlLinkDescriptor).filter((link) => link.rel === "stylesheet" || link.rel === "preload").map((link) => link.rel === "stylesheet" ? {
|
| 89 | ...link,
|
| 90 | rel: "prefetch",
|
| 91 | as: "style"
|
| 92 | } : {
|
| 93 | ...link,
|
| 94 | rel: "prefetch"
|
| 95 | }));
|
| 96 | }
|
| 97 | function getNewMatchesForLinks(page, nextMatches, currentMatches, manifest, location, mode) {
|
| 98 | let isNew = (match, index) => {
|
| 99 | if (!currentMatches[index]) return true;
|
| 100 | return match.route.id !== currentMatches[index].route.id;
|
| 101 | };
|
| 102 | let matchPathChanged = (match, index) => {
|
| 103 | return currentMatches[index].pathname !== match.pathname || currentMatches[index].route.path?.endsWith("*") && currentMatches[index].params["*"] !== match.params["*"];
|
| 104 | };
|
| 105 | if (mode === "assets") return nextMatches.filter((match, index) => isNew(match, index) || matchPathChanged(match, index));
|
| 106 | if (mode === "data") return nextMatches.filter((match, index) => {
|
| 107 | let manifestRoute = manifest.routes[match.route.id];
|
| 108 | if (!manifestRoute || !manifestRoute.hasLoader) return false;
|
| 109 | if (isNew(match, index) || matchPathChanged(match, index)) return true;
|
| 110 | if (match.route.shouldRevalidate) {
|
| 111 | let routeChoice = match.route.shouldRevalidate({
|
| 112 | currentUrl: new URL(location.pathname + location.search + location.hash, window.origin),
|
| 113 | currentParams: currentMatches[0]?.params || {},
|
| 114 | nextUrl: new URL(page, window.origin),
|
| 115 | nextParams: match.params,
|
| 116 | defaultShouldRevalidate: true
|
| 117 | });
|
| 118 | if (typeof routeChoice === "boolean") return routeChoice;
|
| 119 | }
|
| 120 | return true;
|
| 121 | });
|
| 122 | return [];
|
| 123 | }
|
| 124 | function getModuleLinkHrefs(matches, manifest, { includeHydrateFallback } = {}) {
|
| 125 | return dedupeHrefs(matches.map((match) => {
|
| 126 | let route = manifest.routes[match.route.id];
|
| 127 | if (!route) return [];
|
| 128 | let hrefs = [route.module];
|
| 129 | if (route.clientActionModule) hrefs = hrefs.concat(route.clientActionModule);
|
| 130 | if (route.clientLoaderModule) hrefs = hrefs.concat(route.clientLoaderModule);
|
| 131 | if (includeHydrateFallback && route.hydrateFallbackModule) hrefs = hrefs.concat(route.hydrateFallbackModule);
|
| 132 | if (route.imports) hrefs = hrefs.concat(route.imports);
|
| 133 | return hrefs;
|
| 134 | }).flat(1));
|
| 135 | }
|
| 136 | function dedupeHrefs(hrefs) {
|
| 137 | return [...new Set(hrefs)];
|
| 138 | }
|
| 139 | function sortKeys(obj) {
|
| 140 | let sorted = {};
|
| 141 | let keys = Object.keys(obj).sort();
|
| 142 | for (let key of keys) sorted[key] = obj[key];
|
| 143 | return sorted;
|
| 144 | }
|
| 145 | function dedupeLinkDescriptors(descriptors, preloads) {
|
| 146 | let set = /* @__PURE__ */ new Set();
|
| 147 | let preloadsSet = new Set(preloads);
|
| 148 | return descriptors.reduce((deduped, descriptor) => {
|
| 149 | if (preloads && !isPageLinkDescriptor(descriptor) && descriptor.as === "script" && descriptor.href && preloadsSet.has(descriptor.href)) return deduped;
|
| 150 | let key = JSON.stringify(sortKeys(descriptor));
|
| 151 | if (!set.has(key)) {
|
| 152 | set.add(key);
|
| 153 | deduped.push({
|
| 154 | key,
|
| 155 | link: descriptor
|
| 156 | });
|
| 157 | }
|
| 158 | return deduped;
|
| 159 | }, []);
|
| 160 | }
|
| 161 | let _isPreloadSupported;
|
| 162 | function isPreloadSupported() {
|
| 163 | if (_isPreloadSupported !== void 0) return _isPreloadSupported;
|
| 164 | let el = document.createElement("link");
|
| 165 | _isPreloadSupported = el.relList.supports("preload");
|
| 166 | el = null;
|
| 167 | return _isPreloadSupported;
|
| 168 | }
|
| 169 |
|
| 170 | export { getKeyedLinksForMatches, getKeyedPrefetchLinks, getModuleLinkHrefs, getNewMatchesForLinks, isPageLinkDescriptor, prefetchRouteCss, prefetchStyleLinks };
|