UNPKG

one

Version:

One is a React framework for web, iOS, and Android apps.

198 lines (195 loc) • 6.79 kB
import { hasWebHistory, isNative } from "../constants.mjs"; import { handleSkewError, isChunkLoadError } from "../utils/dynamicImport.mjs"; import { diagnoseRouteLoadFailure } from "./diagnoseRouteLoadFailure.mjs"; import { hmrImport } from "./hmrImport.mjs"; let lastVersion = 0; let context; function useViteRoutes(routes, routerRoot, options, version) { if (version && version > lastVersion) { context = null; lastVersion = version; for (const key of Object.keys(preloadedModules)) { delete preloadedModules[key]; } } if (!context) { loadRoutes(routes, routerRoot, options); } return context; } const preloadedModules = {}; function registerPreloadedRoute(key, module) { preloadedModules[key] = module; } function getPreloadedModule(key) { return preloadedModules[key]; } function getPreloadedModuleKeys() { return Object.keys(preloadedModules); } function matchDynamicRoute(routePattern, actualPath) { const routeSegments = routePattern.split("/"); const pathSegments = actualPath.split("/"); const hasCatchAll = routeSegments.some((s) => s.startsWith("[...")); if (hasCatchAll) { const catchAllIdx = routeSegments.findIndex((s) => s.startsWith("[...")); for (let i = 0; i < catchAllIdx; i++) { if (!routeSegments[i]) continue; if (routeSegments[i].startsWith("[")) continue; if (routeSegments[i] !== pathSegments[i]) return false; } return pathSegments.length >= catchAllIdx; } if (routeSegments.length !== pathSegments.length) return false; for (let i = 0; i < routeSegments.length; i++) { const routeSeg = routeSegments[i]; const pathSeg = pathSegments[i]; if (routeSeg.startsWith("[") && routeSeg.endsWith("]")) { continue; } if (routeSeg !== pathSeg) return false; } return true; } async function preloadRouteModules(href) { const globbed = globalThis["__importMetaGlobbed"]; if (!globbed) return; const normalizedHref = href === "/" ? "" : href.replace(/^\//, "").replace(/\/$/, ""); const promises = []; for (const key of Object.keys(globbed)) { let routePath = key.replace(/^\/[^/]+\//, ""); routePath = routePath.replace(/\([^)]+\)\//g, ""); routePath = routePath.replace(/\/_layout\.tsx$/, "").replace(/\/index(\+[a-z]+)?\.tsx$/, "").replace(/(\+[a-z]+)?\.tsx$/, ""); routePath = routePath.replace(/^\//, ""); const isStaticMatch = routePath === normalizedHref || routePath.startsWith(normalizedHref + "/") || normalizedHref.startsWith(routePath + "/") || routePath === "" || normalizedHref !== "" && routePath === normalizedHref.split("/")[0]; const isDynamicMatch = routePath.includes("[") && matchDynamicRoute(routePath, normalizedHref); if ((isStaticMatch || isDynamicMatch) && typeof globbed[key] === "function") { promises.push(globbed[key]().then((mod) => { preloadedModules[key] = mod; })); } } await Promise.all(promises); } function loadRoutes(paths, routerRoot, options) { if (context) return context; globalThis["__importMetaGlobbed"] = paths; context = globbedRoutesToRouteContext(paths, routerRoot, options); return context; } function globbedRoutesToRouteContext(paths, routerRoot, options) { const routesSync = {}; const routePaths = {}; const promises = {}; const loadedRoutes = {}; const clears = {}; Object.keys(paths).forEach((path) => { if (!paths[path]) { console.error(`Error: Missing route at path ${path}`); return; } const loadRouteFunction = paths[path]; const pathWithoutRelative = path.replace(`/${routerRoot}/`, "./"); const originalPath = pathWithoutRelative.slice(1).replace(/\.[jt]sx?$/, ""); if (options?.routeModes?.[originalPath] === "spa") { console.info(`Spa mode: ${originalPath}`); loadedRoutes[pathWithoutRelative] = () => { return null; }; } else { routesSync[pathWithoutRelative] = loadRouteFunction; routePaths[pathWithoutRelative] = path; } }); const moduleKeys = Object.keys(routesSync); let hmrVersion = 0; if (typeof window !== "undefined") { ; window.__oneRouteCache = { clear: () => { hmrVersion++; Object.keys(loadedRoutes).forEach((key) => { delete loadedRoutes[key]; }); Object.keys(promises).forEach((key) => { delete promises[key]; }); Object.keys(preloadedModules).forEach((key) => { delete preloadedModules[key]; }); }, clearFile: (file) => { const normalizedFile = file.replace(/\\/g, "/").replace(/^\//, ""); const routeId = moduleKeys.find((key) => routePaths[key].replace(/\\/g, "/").replace(/^\//, "") === normalizedFile); if (!routeId) return false; hmrVersion++; delete loadedRoutes[routeId]; delete promises[routeId]; delete preloadedModules[routePaths[routeId]]; return true; }, getVersion: () => hmrVersion }; } function resolve(id) { clearTimeout(clears[id]); if (loadedRoutes[id]) { return loadedRoutes[id]; } const preloadKey = id.replace("./", `/${routerRoot}/`); const preloaded = getPreloadedModule(preloadKey); if (preloaded) { loadedRoutes[id] = preloaded; return preloaded; } if (typeof routesSync[id] !== "function") { return routesSync[id]; } if (!promises[id]) { let importPromise; if (process.env.NODE_ENV === "development" && hmrVersion > 0 && routePaths[id]) { importPromise = isNative ? routesSync[id]().then(() => hmrImport(routePaths[id])) : hmrImport(routePaths[id]); } else { importPromise = routesSync[id](); } promises[id] = importPromise.then((val) => { loadedRoutes[id] = val; delete promises[id]; if (process.env.NODE_ENV === "development") { clears[id] = setTimeout(() => { delete loadedRoutes[id]; }, 500); } return val; }).catch((err) => { console.error(`Error loading route`, id, err, new Error().stack); const reloading = isChunkLoadError(err) && handleSkewError(); if (process.env.NODE_ENV === "development") { ; globalThis.__oneReportRouteLoadError?.({ id, message: err instanceof Error ? err.message : String(err), stack: err instanceof Error ? err.stack : void 0 }); if (hasWebHistory && routePaths[id] && !reloading) { diagnoseRouteLoadFailure(id, routePaths[id]).then((message) => { if (message) console.error(message); }).catch(() => {}); } } loadedRoutes[id] = { default: () => null }; delete promises[id]; }); if (process.env.NODE_ENV === "development") { promises[id].stack = new Error().stack; } } throw promises[id]; } resolve.keys = () => moduleKeys; resolve.id = ""; resolve.resolve = (id) => id; return resolve; } export { getPreloadedModule, getPreloadedModuleKeys, globbedRoutesToRouteContext, loadRoutes, preloadRouteModules, registerPreloadedRoute, useViteRoutes }; //# sourceMappingURL=useViteRoutes.mjs.map