UNPKG

one

Version:

One is a new React Framework that makes Vite serve both native and web.

632 lines 24 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var workerHandler_exports = {}; __export(workerHandler_exports, { createWorkerHandler: () => createWorkerHandler }); module.exports = __toCommonJS(workerHandler_exports); var import_constants = require("../constants.cjs"); var import_createHandleRequest = require("../createHandleRequest.cjs"); var import_cleanUrl = require("../utils/cleanUrl.cjs"); var import_isResponse = require("../utils/isResponse.cjs"); var import_resolveResponse = require("../vite/resolveResponse.cjs"); var import_ssrLoaderData = require("./ssrLoaderData.cjs"); var import_staticHtmlFetcher = require("./staticHtmlFetcher.cjs"); function createWorkerHandler(options) { const { oneOptions } = options; let currentLazyRoutes = options.lazyRoutes; let compiledManifest = (0, import_createHandleRequest.compileManifest)(options.buildInfo.manifest); let routeToBuildInfo = options.buildInfo.routeToBuildInfo; let routeMap = options.buildInfo.routeMap; let currentPreloads = options.buildInfo.preloads; let currentCssPreloads = options.buildInfo.cssPreloads; const debugRouter = process.env.ONE_DEBUG_ROUTER; const redirects = oneOptions.web?.redirects; let compiledRedirects = null; if (redirects?.length) { compiledRedirects = redirects.map(r => { const regexSource = r.source.replace(/:(\w+)/g, (_, name) => `(?<${name}>[^/]+)`); return { regex: new RegExp(`^${regexSource}$`), destination: r.destination, permanent: r.permanent || false }; }); } const useStreaming = !process.env.ONE_BUFFERED_SSR; const htmlHeaders = { "content-type": "text/html" }; const ssrHtmlHeaders = { "content-type": "text/html", "cache-control": "no-cache" }; const loaderCache = /* @__PURE__ */new Map(); const moduleImportCache = /* @__PURE__ */new Map(); const loaderCacheFnMap = /* @__PURE__ */new Map(); const pendingLoaderResults = /* @__PURE__ */new Map(); let render = null; let renderStream = null; let renderLoading = null; let renderGeneration = 0; function ensureRenderLoaded() { if (render) return; if (renderLoading) return renderLoading; const gen = ++renderGeneration; renderLoading = (async () => { const entry = await currentLazyRoutes.serverEntry(); if (gen !== renderGeneration) return; render = entry.default.render; renderStream = entry.default.renderStream || null; })(); return renderLoading; } function findNearestNotFoundPath(urlPath) { let cur = urlPath; while (cur) { const parent = cur.lastIndexOf("/") > 0 ? cur.slice(0, cur.lastIndexOf("/")) : ""; if (routeMap[`${parent}/+not-found`]) return `${parent}/+not-found`; if (!parent) break; cur = parent; } return "/+not-found"; } function make404LoaderJs(path, logReason) { const nfPath = findNearestNotFoundPath(path); if (logReason) console.error(`[one] 404 loader for ${path}: ${logReason}`); return `export function loader(){return{__oneError:404,__oneErrorMessage:'Not Found',__oneNotFoundPath:${JSON.stringify(nfPath)}}}`; } async function readStaticHtml(htmlPath) { const fetchStaticHtml = (0, import_staticHtmlFetcher.getFetchStaticHtml)(); if (fetchStaticHtml) return await fetchStaticHtml(htmlPath); if (debugRouter) { console.warn(`[one/worker] no fetchStaticHtml set, cannot read ${htmlPath}`); } return null; } function resolveLoaderSync(lazyKey) { const cacheKey = lazyKey || ""; const cached = loaderCache.get(cacheKey); if (cached !== void 0) return cached; return (async () => { let routeExported; if (moduleImportCache.has(cacheKey)) { routeExported = moduleImportCache.get(cacheKey); } else if (lazyKey && currentLazyRoutes.pages[lazyKey]) { routeExported = await currentLazyRoutes.pages[lazyKey](); moduleImportCache.set(cacheKey, routeExported); } else { console.warn(`[one/worker] no lazy route for ${cacheKey}`); loaderCache.set(cacheKey, null); return null; } const loader = routeExported?.loader || null; loaderCache.set(cacheKey, loader); loaderCacheFnMap.set(cacheKey, routeExported?.loaderCache ?? null); return loader; })(); } async function importAndRunLoader(routeId, lazyKey, loaderProps) { if (!lazyKey) return { loaderData: void 0, routeId }; const cacheMapKey = lazyKey; const loaderCacheFn = loaderCacheFnMap.get(cacheMapKey); let coalFullKey; let coalTtl = 0; if (loaderCacheFn) { const cacheResult = loaderCacheFn(loaderProps?.params, loaderProps?.request); const cacheKey = typeof cacheResult === "string" ? cacheResult : cacheResult?.key; coalTtl = typeof cacheResult === "string" ? 0 : cacheResult?.ttl ?? 0; if (cacheKey != null) { coalFullKey = routeId + "\0" + cacheKey; const existing = pendingLoaderResults.get(coalFullKey); if (existing && (!existing.expires || Date.now() < existing.expires)) { const loaderData = await existing.promise; return { loaderData, routeId }; } } } try { const loaderOrPromise = resolveLoaderSync(lazyKey); const loader = loaderOrPromise instanceof Promise ? await loaderOrPromise : loaderOrPromise; if (!loader) return { loaderData: void 0, routeId }; if (coalFullKey) { const promise = loader(loaderProps); const entry = { promise, expires: 0 }; pendingLoaderResults.set(coalFullKey, entry); promise.then(() => { entry.expires = coalTtl > 0 ? Date.now() + coalTtl : 0; if (coalTtl <= 0) Promise.resolve().then(() => pendingLoaderResults.delete(coalFullKey)); }, () => pendingLoaderResults.delete(coalFullKey)); const loaderData2 = await promise; return { loaderData: loaderData2, routeId }; } const loaderData = await loader(loaderProps); return { loaderData, routeId }; } catch (err) { if ((0, import_isResponse.isResponse)(err)) throw err; if (err?.code === "ENOENT") return { loaderData: void 0, routeId, isEnoent: true }; console.error(`[one] Error running loader for ${routeId}:`, err); return { loaderData: void 0, routeId }; } } const requestHandlers = { async handleStaticFile() { return null; }, async handleAPI({ route }) { if (currentLazyRoutes.api[route.page]) { return await currentLazyRoutes.api[route.page](); } console.warn(`[one/worker] no lazy API route for ${route.page}`); return null; }, async loadMiddleware(route) { if (currentLazyRoutes.middlewares[route.contextKey]) { return await currentLazyRoutes.middlewares[route.contextKey](); } console.warn(`[one/worker] no lazy middleware for ${route.contextKey}`); return null; }, async handleLoader({ route, loaderProps }) { const routeFile = route.routeFile || route.file; let loader; try { const loaderResult = resolveLoaderSync(routeFile); loader = loaderResult instanceof Promise ? await loaderResult : loaderResult; } catch (err) { if (err?.code === "ERR_MODULE_NOT_FOUND") return null; throw err; } if (!loader) return null; let json; try { json = await loader(loaderProps); } catch (err) { if (err?.code === "ENOENT") { return make404LoaderJs(loaderProps?.path || "/", `ENOENT ${err?.path || err}`); } throw err; } if ((0, import_isResponse.isResponse)(json)) throw json; return `export function loader() { return ${JSON.stringify(json)} }`; }, async handlePage({ route, url, loaderProps }) { const routeBuildInfo = routeToBuildInfo[route.file]; if (route.type === "ssr") { if (!routeBuildInfo) { console.error(`Error in route`, route); throw new Error(`No buildinfo found for ${url}, route: ${route.file}, in keys: ${Object.keys(routeToBuildInfo).join("\n ")}`); } try { const layoutRoutes = route.layouts || []; const layoutLoaderPromises = []; const noLoaderResults = []; for (const layout of layoutRoutes) { const cacheKey = layout.contextKey || ""; const cachedLoader = loaderCache.get(cacheKey); if (cachedLoader === null) { noLoaderResults.push({ loaderData: void 0, routeId: layout.contextKey }); } else { layoutLoaderPromises.push(importAndRunLoader(layout.contextKey, layout.contextKey, loaderProps)); } } const pageLoaderPromise = importAndRunLoader(route.file, route.file, loaderProps); let layoutResults; let pageResult; try { if (layoutLoaderPromises.length === 0) { layoutResults = noLoaderResults; pageResult = await pageLoaderPromise; } else { const [asyncLayoutResults, pr] = await Promise.all([Promise.all(layoutLoaderPromises), pageLoaderPromise]); layoutResults = [...noLoaderResults, ...asyncLayoutResults]; pageResult = pr; } } catch (err) { if ((0, import_isResponse.isResponse)(err)) return err; throw err; } if (pageResult.isEnoent) { const nfPath = findNearestNotFoundPath(loaderProps?.path || "/"); const nfHtml = routeMap[nfPath]; if (nfHtml) { const html = await readStaticHtml(nfHtml); if (html) { return new Response(html, { headers: { "content-type": "text/html" }, status: 404 }); } } return new Response("404 Not Found", { status: 404 }); } const matchPathname = loaderProps?.path || "/"; const matchParams = loaderProps?.params || {}; const matches = new Array(layoutResults.length + 1); for (let i = 0; i < layoutResults.length; i++) { const result = layoutResults[i]; matches[i] = { routeId: result.routeId, pathname: matchPathname, params: matchParams, loaderData: result.loaderData }; } matches[layoutResults.length] = { routeId: pageResult.routeId, pathname: matchPathname, params: matchParams, loaderData: pageResult.loaderData }; const loaderData = pageResult.loaderData; for (const layout of layoutRoutes) { const key = layout.contextKey; const loaderFn = loaderCache.get(key); if (loaderFn) { const result = layoutResults.find(r => r.routeId === key); if (result) (0, import_ssrLoaderData.setSSRLoaderData)(loaderFn, result.loaderData); } } const pageLoaderFn = loaderCache.get(route.file); if (pageLoaderFn) (0, import_ssrLoaderData.setSSRLoaderData)(pageLoaderFn, pageResult.loaderData); globalThis["__vxrnresetState"]?.(); const renderProps = { mode: route.type, loaderData, loaderProps, path: loaderProps?.path || "/", preloads: routeBuildInfo.criticalPreloads || routeBuildInfo.preloads, deferredPreloads: routeBuildInfo.deferredPreloads, css: routeBuildInfo.css, cssContents: routeBuildInfo.cssContents, matches }; const _rl = ensureRenderLoaded(); if (_rl) await _rl; const status = route.isNotFound ? 404 : 200; const responseHeaders = route.isNotFound ? htmlHeaders : ssrHtmlHeaders; if (useStreaming) { const stream = await renderStream(renderProps); return new Response(stream, { headers: responseHeaders, status }); } const rendered = await render(renderProps); return new Response(rendered, { headers: responseHeaders, status }); } catch (err) { if ((0, import_isResponse.isResponse)(err)) return err; console.error(`[one] Error rendering SSR route ${route.file} ${err?.["stack"] ?? err} url: ${url}`); return null; } } else { const layoutRoutes = route.layouts || []; const needsSpaShell = route.type === "spa" && layoutRoutes.some(layout => layout.layoutRenderMode === "ssg" || layout.layoutRenderMode === "ssr"); if (needsSpaShell) { try { const layoutResults = await Promise.all(layoutRoutes.map(layout => importAndRunLoader(layout.contextKey, layout.contextKey, loaderProps))); const matches = layoutResults.map(result => ({ routeId: result.routeId, pathname: loaderProps?.path || "/", params: loaderProps?.params || {}, loaderData: result.loaderData })); globalThis["__vxrnresetState"]?.(); const _rl = ensureRenderLoaded(); if (_rl) await _rl; const spaRouteBuildInfo = routeToBuildInfo[route.file]; const rendered = await render({ mode: "spa-shell", loaderData: void 0, loaderProps, path: loaderProps?.path || "/", preloads: spaRouteBuildInfo?.criticalPreloads || spaRouteBuildInfo?.preloads, deferredPreloads: spaRouteBuildInfo?.deferredPreloads, css: spaRouteBuildInfo?.css, cssContents: spaRouteBuildInfo?.cssContents, matches }); return new Response(rendered, { headers: htmlHeaders, status: route.isNotFound ? 404 : 200 }); } catch (err) { if ((0, import_isResponse.isResponse)(err)) return err; console.error(`[one] Error rendering spa-shell for ${route.file} ${err?.["stack"] ?? err} url: ${url}`); } } const isDynamicRoute = Object.keys(route.routeKeys).length > 0; const routeCleanPath = route.urlCleanPath.replace(/\?/g, ""); const notFoundKey = route.isNotFound ? route.page.replace(/\[([^\]]+)\]/g, ":$1") : null; const htmlPath = notFoundKey ? routeMap[notFoundKey] : isDynamicRoute ? routeMap[routeCleanPath] || routeMap[url.pathname] : routeMap[url.pathname] || routeMap[routeBuildInfo?.cleanPath]; if (htmlPath) { const html = await readStaticHtml(htmlPath); if (html) { return new Response(html, { headers: htmlHeaders, status: route.isNotFound ? 404 : 200 }); } } if (isDynamicRoute) { const notFoundRoute = findNearestNotFoundPath(url.pathname); const notFoundHtmlPath = routeMap[notFoundRoute]; if (notFoundHtmlPath) { const notFoundHtml = await readStaticHtml(notFoundHtmlPath); if (notFoundHtml) { const notFoundMarker = `<script>window.__one404=${JSON.stringify({ originalPath: url.pathname, notFoundPath: notFoundRoute })}</script>`; const injectedHtml = notFoundHtml.includes("</head>") ? notFoundHtml.replace("</head>", `${notFoundMarker}</head>`) : notFoundHtml.replace("<body", `${notFoundMarker}<body`); return new Response(injectedHtml, { headers: htmlHeaders, status: 404 }); } } return new Response("404 Not Found", { status: 404 }); } return null; } } }; function setCacheHeaders(response, route, isAPI) { if (!response.headers.has("cache-control") && !response.headers.has("Cache-Control")) { try { if (isAPI) { response.headers.set("cache-control", "no-store"); } else if (route.type === "ssg" || route.type === "spa") { response.headers.set("cache-control", "public, s-maxage=60, stale-while-revalidate=120"); } else { response.headers.set("cache-control", "no-cache"); } } catch {} } return response; } async function handleRequest(request) { const url = (0, import_createHandleRequest.getURLfromRequestURL)(request); const pathname = url.pathname; const method = request.method; if (compiledRedirects) { for (const redirect of compiledRedirects) { const match = redirect.regex.exec(pathname); if (match) { let destination = redirect.destination; if (match.groups) { for (const [name, value] of Object.entries(match.groups)) { destination = destination.replace(`:${name}`, value); } } if (debugRouter) console.info(`[one] \u21AA redirect ${pathname} \u2192 ${destination}`); return new Response(null, { status: redirect.permanent ? 301 : 302, headers: { location: new URL(destination, url.origin).toString() } }); } } } if (pathname.endsWith(import_constants.PRELOAD_JS_POSTFIX)) { if (!currentPreloads[pathname]) { return new Response("", { headers: { "Content-Type": "text/javascript" } }); } return null; } if (pathname.endsWith(import_constants.CSS_PRELOAD_JS_POSTFIX)) { if (!currentCssPreloads?.[pathname]) { return new Response("export default Promise.resolve()", { headers: { "Content-Type": "text/javascript" } }); } return null; } if (pathname.endsWith(import_constants.LOADER_JS_POSTFIX_UNCACHED)) { const originalUrl = (0, import_cleanUrl.getPathFromLoaderPath)(pathname); for (const route of compiledManifest.pageRoutes) { if (route.file === "") continue; if (!route.compiledRegex.test(originalUrl)) continue; if (route.type === "ssg" && Object.keys(route.routeKeys).length > 0 && !routeMap[originalUrl]) { return new Response(make404LoaderJs(originalUrl, "ssg route not in routeMap"), { headers: { "Content-Type": "text/javascript" } }); } if (route.hasLoader === false) { return new Response("export function loader() { return undefined }", { headers: { "Content-Type": "text/javascript" } }); } const loaderRoute = { ...route, routeFile: route.file, file: route.loaderServerPath || pathname }; const finalUrl = new URL(originalUrl, url.origin); finalUrl.search = url.search; const cleanedRequest = new Request(finalUrl, request); try { return await (0, import_createHandleRequest.resolveLoaderRoute)(requestHandlers, cleanedRequest, finalUrl, loaderRoute); } catch (err) { if (err?.code === "ERR_MODULE_NOT_FOUND") { return new Response("export function loader() { return undefined }", { headers: { "Content-Type": "text/javascript" } }); } console.error(`Error running loader: ${err}`); return null; } } return null; } if (pathname.endsWith(".js") || pathname.endsWith(".css")) { return null; } for (const route of compiledManifest.apiRoutes) { if (route.compiledRegex.test(pathname)) { if (debugRouter) console.info(`[one] \u26A1 ${pathname} \u2192 matched API route: ${route.page}`); const response = await (0, import_createHandleRequest.resolveAPIRoute)(requestHandlers, request, url, route); if (response && (0, import_isResponse.isResponse)(response)) { return setCacheHeaders(response, route, true); } return null; } } if (method === "GET") { for (const route of compiledManifest.pageRoutes) { if (!route.compiledRegex.test(pathname)) continue; if (debugRouter) { console.info(`[one] \u26A1 ${pathname} \u2192 matched page route: ${route.page} (${route.type})`); } if (route.type === "ssr" && !route.middlewares?.length) { const params = {}; const match = route.compiledRegex.exec(pathname); if (match?.groups) { for (const [key, value] of Object.entries(match.groups)) { params[route.routeKeys[key]] = value; } } const loaderProps = { path: pathname, search: url.search, subdomain: (0, import_createHandleRequest.getSubdomain)(url), request, params }; const response = await (0, import_resolveResponse.resolveResponse)(async () => { try { return await requestHandlers.handlePage({ request, route, url, loaderProps }); } catch (err) { if ((0, import_isResponse.isResponse)(err)) return err; throw err; } }); if (response && (0, import_isResponse.isResponse)(response)) { return setCacheHeaders(response, route, false); } return null; } try { const response = await (0, import_createHandleRequest.resolvePageRoute)(requestHandlers, request, url, route); if (response && (0, import_isResponse.isResponse)(response)) { return setCacheHeaders(response, route, false); } } catch (err) { console.error(` [one] Error handling request: ${err["stack"]}`); } return null; } } return null; } function updateRoutes(newBuildInfo, newLazyRoutes) { compiledManifest = (0, import_createHandleRequest.compileManifest)(newBuildInfo.manifest); routeToBuildInfo = newBuildInfo.routeToBuildInfo; routeMap = newBuildInfo.routeMap; currentPreloads = newBuildInfo.preloads; currentCssPreloads = newBuildInfo.cssPreloads; if (newLazyRoutes) currentLazyRoutes = newLazyRoutes; loaderCache.clear(); moduleImportCache.clear(); loaderCacheFnMap.clear(); pendingLoaderResults.clear(); render = null; renderStream = null; renderLoading = null; } return { handleRequest, updateRoutes }; }