one
Version:
One is a new React Framework that makes Vite serve both native and web.
370 lines (361 loc) • 15.7 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf, __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: !0 });
}, __copyProps = (to, from, except, desc) => {
if (from && typeof from == "object" || typeof from == "function")
for (let key of __getOwnPropNames(from))
!__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target,
mod
)), __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod);
var buildPage_exports = {};
__export(buildPage_exports, {
buildPage: () => buildPage,
printBuildTimings: () => printBuildTimings
});
module.exports = __toCommonJS(buildPage_exports);
var import_node_path = require("node:path"), import_fs_extra = __toESM(require("fs-extra"), 1), constants = __toESM(require("../constants"), 1), import_cleanUrl = require("../utils/cleanUrl"), import_isResponse = require("../utils/isResponse"), import_toAbsolute = require("../utils/toAbsolute"), import_replaceLoader = require("../vite/replaceLoader");
const { readFile, outputFile } = import_fs_extra.default;
function urlPathToFilePath(urlPath) {
const parts = urlPath.replace(/^\//, "").split("/");
return (0, import_node_path.join)(...parts);
}
const buildTiming = process.env.ONE_BUILD_TIMING === "1", timings = {};
function recordTiming(label, ms) {
buildTiming && (timings[label] ||= []).push(ms);
}
function printBuildTimings() {
if (buildTiming) {
console.info(`
\u{1F4CA} Build timing breakdown:`);
for (const [label, times] of Object.entries(timings)) {
const avg = times.reduce((a, b) => a + b, 0) / times.length, total = times.reduce((a, b) => a + b, 0);
console.info(
` ${label}: ${avg.toFixed(1)}ms avg, ${total.toFixed(0)}ms total (${times.length} calls)`
);
}
}
}
async function buildPage(serverEntry, path, relativeId, params, foundRoute, clientManifestEntry, staticDir, clientDir, builtMiddlewares, serverJsPath, preloads, allCSS, routePreloads, allCSSContents, criticalPreloads, deferredPreloads, useAfterLCP, useAfterLCPAggressive) {
let t0 = performance.now();
const render = await getRender(serverEntry);
recordTiming("getRender", performance.now() - t0);
const htmlPath = `${path.endsWith("/") ? `${removeTrailingSlash(path)}/index` : path}.html`, clientJsPath = clientManifestEntry ? (0, import_node_path.join)("dist/client", clientManifestEntry.file) : "", htmlOutPath = (0, import_toAbsolute.toAbsolute)((0, import_node_path.join)(staticDir, htmlPath)), preloadPath = (0, import_cleanUrl.getPreloadPath)(path), cssPreloadPath = (0, import_cleanUrl.getPreloadCSSPath)(path);
let loaderPath = "", loaderData = {};
try {
const routeImports = [], routeRegistrations = [];
let routeIndex = 0;
for (const [routeKey, bundlePath] of Object.entries(routePreloads)) {
const varName = `_r${routeIndex++}`;
routeImports.push(`import * as ${varName} from "${bundlePath}"`), routeRegistrations.push(`registerPreloadedRoute("${routeKey}", ${varName})`);
}
const registrationCalls = routeRegistrations.map(
(call) => call.replace("registerPreloadedRoute(", "window.__oneRegisterPreloadedRoute(")
), preloadContent = [
// import all route modules
...routeImports,
// static imports for cache warming (original behavior)
...preloads.map((preload) => `import "${preload}"`),
// register all route modules using window global
...registrationCalls
].join(`
`);
t0 = performance.now(), await import_fs_extra.default.writeFile(
(0, import_node_path.join)(clientDir, urlPathToFilePath(preloadPath)),
preloadContent
), recordTiming("writePreload", performance.now() - t0);
const uniqueCSS = [...new Set(allCSS)], cssPreloadContent = `
const CSS_TIMEOUT = 1000
const cssUrls = ${JSON.stringify(uniqueCSS)}
// Global cache for loaded CSS - avoids DOM queries and tracks across navigations
const loaded = (window.__oneLoadedCSS ||= new Set())
// Prefetch CSS without applying - called on link hover
export function prefetchCSS() {
cssUrls.forEach(href => {
if (loaded.has(href)) return
if (document.querySelector(\`link[href="\${href}"]\`)) return
const link = document.createElement('link')
link.rel = 'prefetch'
link.as = 'style'
link.href = href
document.head.appendChild(link)
})
}
// Inject CSS to apply styles - called on actual navigation
export function injectCSS() {
return Promise.all(cssUrls.map(href => {
// Skip if already loaded
if (loaded.has(href)) return Promise.resolve()
// Remove any prefetch link for this href
const prefetchLink = document.querySelector(\`link[rel="prefetch"][href="\${href}"]\`)
if (prefetchLink) prefetchLink.remove()
// Skip if stylesheet already exists in DOM
if (document.querySelector(\`link[rel="stylesheet"][href="\${href}"]\`)) {
loaded.add(href)
return Promise.resolve()
}
return new Promise(resolve => {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = href
const timeoutId = setTimeout(() => {
console.warn('[one] CSS load timeout:', href)
loaded.add(href)
resolve()
}, CSS_TIMEOUT)
link.onload = link.onerror = () => {
clearTimeout(timeoutId)
loaded.add(href)
resolve()
}
document.head.appendChild(link)
})
}))
}
// For backwards compatibility, also prefetch on import
prefetchCSS()
`;
t0 = performance.now(), await import_fs_extra.default.writeFile(
(0, import_node_path.join)(clientDir, urlPathToFilePath(cssPreloadPath)),
cssPreloadContent
), recordTiming("writeCSSPreload", performance.now() - t0), t0 = performance.now();
const exported = await import((0, import_toAbsolute.toAbsolute)(serverJsPath));
recordTiming("importServerModule", performance.now() - t0);
const loaderProps = { path, params }, matches = [];
if (t0 = performance.now(), foundRoute.layouts?.length) {
const layoutResults = await Promise.all(
foundRoute.layouts.map(async (layout) => {
try {
const layoutServerPath = layout.loaderServerPath;
if (!layoutServerPath)
return { contextKey: layout.contextKey, loaderData: void 0 };
const layoutLoaderData = await (await import((0, import_toAbsolute.toAbsolute)((0, import_node_path.join)("./", "dist/server", layoutServerPath))))?.loader?.(loaderProps);
return { contextKey: layout.contextKey, loaderData: layoutLoaderData };
} catch (err) {
if ((0, import_isResponse.isResponse)(err))
throw err;
return console.warn(
`[one] Warning: layout loader failed for ${layout.contextKey}:`,
err
), { contextKey: layout.contextKey, loaderData: void 0 };
}
})
);
for (const result of layoutResults)
matches.push({
routeId: result.contextKey,
pathname: path,
params: params || {},
loaderData: result.loaderData
});
}
recordTiming("layoutLoaders", performance.now() - t0), t0 = performance.now();
let loaderRedirectInfo = null;
if (exported.loader) {
try {
loaderData = await exported.loader?.(loaderProps) ?? null;
} catch (err) {
if ((0, import_isResponse.isResponse)(err))
loaderRedirectInfo = extractRedirectInfo(err);
else
throw err;
}
if (!loaderRedirectInfo && loaderData && ((0, import_isResponse.isResponse)(loaderData) || loaderData instanceof Response || loaderData?.constructor?.name === "Response") && (loaderRedirectInfo = extractRedirectInfo(loaderData), loaderData = {}), clientJsPath) {
const loaderPartialPath = (0, import_node_path.join)(clientDir, urlPathToFilePath((0, import_cleanUrl.getLoaderPath)(path)));
if (loaderRedirectInfo) {
const redirectData = JSON.stringify({
__oneRedirect: loaderRedirectInfo.path,
__oneRedirectStatus: loaderRedirectInfo.status
});
await outputFile(
loaderPartialPath,
`export function loader(){return ${redirectData}}`
), loaderPath = (0, import_cleanUrl.getLoaderPath)(path), loaderData = {};
} else {
const code = await readFile(clientJsPath, "utf-8"), withLoader = (
// super dirty to quickly make ssr loaders work until we have better
`
if (typeof document === 'undefined') globalThis.document = {}
` + (0, import_replaceLoader.replaceLoader)({
code,
loaderData
})
);
await outputFile(loaderPartialPath, withLoader), loaderPath = (0, import_cleanUrl.getLoaderPath)(path);
}
}
}
if (recordTiming("pageLoader", performance.now() - t0), matches.push({
routeId: foundRoute.file,
pathname: path,
params: params || {},
loaderData
}), foundRoute.type !== "ssr") {
if (globalThis.__vxrnresetState?.(), foundRoute.type === "ssg") {
const renderPreloads = criticalPreloads || preloads, renderDeferredPreloads = useAfterLCPAggressive ? [] : deferredPreloads;
t0 = performance.now();
let html = await render({
path,
preloads: renderPreloads,
deferredPreloads: renderDeferredPreloads,
loaderProps,
loaderData,
css: allCSS,
cssContents: allCSSContents,
mode: "ssg",
routePreloads,
matches
});
recordTiming("ssrRender", performance.now() - t0), useAfterLCP && (html = applyAfterLCPScriptLoad(html, preloads)), t0 = performance.now(), await outputFile(htmlOutPath, html), recordTiming("writeHTML", performance.now() - t0);
} else if (foundRoute.type === "spa")
if (foundRoute.layouts?.some(
(layout) => layout.layoutRenderMode === "ssg" || layout.layoutRenderMode === "ssr"
)) {
globalThis.__vxrnresetState?.();
const renderPreloads = criticalPreloads || preloads, renderDeferredPreloads = deferredPreloads || [], layoutMatches = matches.slice(0, -1);
t0 = performance.now();
let html = await render({
path,
preloads: renderPreloads,
deferredPreloads: renderDeferredPreloads,
loaderProps,
// don't pass loaderData for spa-shell - the page loader runs on client
// passing {} here would make useLoaderState think data is preloaded
loaderData: void 0,
css: allCSS,
cssContents: allCSSContents,
mode: "spa-shell",
routePreloads,
matches: layoutMatches
});
recordTiming("spaShellRender", performance.now() - t0), useAfterLCP && (html = applyAfterLCPScriptLoad(html, preloads)), t0 = performance.now(), await outputFile(htmlOutPath, html), recordTiming("writeHTML", performance.now() - t0);
} else {
const cssOutput = allCSSContents ? allCSSContents.filter(Boolean).map((content) => ` <style>${content}</style>`).join(`
`) : allCSS.map((file) => ` <link rel="stylesheet" href=${file} />`).join(`
`), criticalScripts = (criticalPreloads || preloads).map((preload) => ` <script type="module" src="${preload}"></script>`).join(`
`), deferredLinks = (deferredPreloads || []).map(
(preload) => ` <link rel="modulepreload" fetchPriority="low" href="${preload}"/>`
).join(`
`);
await outputFile(
htmlOutPath,
`<!DOCTYPE html><html><head>
${constants.getSpaHeaderElements({ serverContext: { loaderProps, loaderData } })}
${criticalScripts}
${deferredLinks}
${cssOutput}
</head><body></body></html>`
);
}
}
} catch (err) {
const errMsg = err instanceof Error ? `${err.message}
${err.stack}` : `${err}`;
console.error(
`Error building static page at ${path} with id ${relativeId}:
${errMsg}
loaderData:
${JSON.stringify(loaderData || null, null, 2)}
params:
${JSON.stringify(params || null, null, 2)}`
), console.error(err), process.exit(1);
}
const middlewares = (foundRoute.middlewares || []).map(
(x) => builtMiddlewares[x.contextKey]
), cleanPath = path === "/" ? path : removeTrailingSlash(path);
return {
type: foundRoute.type,
css: allCSS,
cssContents: allCSSContents,
routeFile: foundRoute.file,
middlewares,
cleanPath,
preloadPath,
cssPreloadPath,
loaderPath,
clientJsPath,
serverJsPath,
htmlPath,
loaderData,
params,
path,
preloads,
criticalPreloads,
deferredPreloads
};
}
async function getRender(serverEntry) {
let render = null;
try {
const serverImport = await import(serverEntry);
render = serverImport.default.render || // for an unknown reason this is necessary
serverImport.default.default?.render, typeof render != "function" && (console.error("\u274C Error: didn't find render function in entry", serverImport), process.exit(1));
} catch (err) {
console.error("\u274C Error importing the root entry:"), console.error(` This error happened in the built file: ${serverEntry}`), console.error(err.stack), process.exit(1);
}
return render;
}
function removeTrailingSlash(path) {
return path.endsWith("/") ? path.slice(0, path.length - 1) : path;
}
function extractRedirectInfo(response) {
if (response.status >= 300 && response.status < 400) {
const location = response.headers.get("location");
if (location)
try {
const url = new URL(location);
return {
path: url.pathname + url.search + url.hash,
status: response.status
};
} catch {
return { path: location, status: response.status };
}
}
return null;
}
function applyAfterLCPScriptLoad(html, preloads) {
html = html.replace(/<script\s+type="module"[^>]*async[^>]*><\/script>/gi, "");
const loaderScript = `
<script>
(function() {
var scripts = ${JSON.stringify(preloads)};
function loadScripts() {
scripts.forEach(function(src) {
var script = document.createElement('script');
script.type = 'module';
script.src = src;
document.head.appendChild(script);
});
}
function waitIdle(n) {
if (n <= 0) {
requestAnimationFrame(function() {
requestAnimationFrame(loadScripts);
});
return;
}
setTimeout(function() {
setTimeout(function() {
waitIdle(n - 1);
}, 0);
}, 0);
}
waitIdle(5);
})();
</script>`;
return html = html.replace("</head>", `${loaderScript}</head>`), html;
}
//# sourceMappingURL=buildPage.js.map