Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
4.2 kB · 98 lines
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899import { createHash } from "node:crypto";import { readFile, writeFile } from "node:fs/promises";import path from "node:path";import ts from "typescript";
// Tokens have only type imports. Compile them with the project's TypeScript// dependency so this works even when Node was built without type stripping.const { outputText } = ts.transpileModule( await readFile( new URL("../../components/src/lib/theme/tokens.ts", import.meta.url), "utf8", ), { compilerOptions: { module: ts.ModuleKind.ESNext } },);const { borderRadius, colors, loadingIndicator, spacing, surfaces, textAlphas, touchTargets, typeScale,} = await import( `data:text/javascript;base64,${Buffer.from(outputText).toString("base64")}`);
// Expo's shared chunk is eager even when every app screen is lazy. Keep its// generated bundles intact, but let a tiny bootloader start them after paint.const output = process.argv[2] ?? "dist";const htmlPath = path.join(output, "index.html");let html = await readFile(htmlPath, "utf8");const scripts = [];html = html.replace( /<script\b[^>]*\bsrc="([^"]+)"[^>]*>\s*<\/script>/g, (_, src) => { scripts.push(src); return ""; },);if (!scripts.length || !html.includes('<div id="root"></div>')) { throw new Error("Expected Expo SPA HTML with scripts and an empty #root");}
const code = await readFile(new URL("./web-bootstrap.js", import.meta.url));const hash = createHash("sha256").update(code).digest("hex").slice(0, 16);const filename = `bootstrap-${hash}.js`;await writeFile(path.join(output, "_expo/static/js/web", filename), code);
const css = `#web-bootstrap { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: ${spacing[4]}px; padding: ${spacing[6]}px; background: var(--bootstrap-background, ${surfaces.dark[0]}); color: ${textAlphas.dark[1]}; font: ${typeScale.base.fontSize}px/${typeScale.base.lineHeight}px system-ui, sans-serif; text-align: center;}#bootstrap-spinner { width: ${loadingIndicator.size}px; height: ${loadingIndicator.size}px; color: var(--bootstrap-primary, ${colors.primary[500]}); animation: bootstrap-spin ${loadingIndicator.duration}ms linear infinite;}#web-bootstrap [hidden] { display: none; }html,body { background-color: var(--bootstrap-background, ${surfaces.dark[0]}); }#bootstrap-retry { font: inherit; color: inherit; background: ${surfaces.dark[2]}; padding: ${spacing[2]}px ${spacing[4]}px; border: none; border-radius: ${borderRadius.md}px; min-height: ${touchTargets.minimum}px; cursor: pointer;}#bootstrap-retry:focus-visible { outline: ${spacing[1] / 2}px solid currentColor; outline-offset: ${spacing[1] / 2}px; }@keyframes bootstrap-spin { to { transform: rotate(360deg); } }@media (prefers-reduced-motion: reduce) { #bootstrap-spinner { animation: none; } }`;html = html.replace("</head>", `<style>${css}</style></head>`);html = html.replace( '<div id="root"></div>', `<div id="root"><div id="web-bootstrap"> <svg id="bootstrap-spinner" viewBox="0 0 32 32" role="progressbar" aria-label="Loading"> <circle cx="16" cy="16" r="14" fill="none" stroke="currentColor" stroke-width="4" opacity="${loadingIndicator.trackOpacity}"></circle> <circle cx="16" cy="16" r="14" fill="none" stroke="currentColor" stroke-width="4" stroke-dasharray="80" stroke-dashoffset="60"></circle> </svg> <div id="bootstrap-status" role="status" aria-live="polite" hidden></div> <button id="bootstrap-retry" type="button" hidden>Try again</button> </div></div>`,);// Escape '<' so a filename cannot terminate the JSON script element.const manifest = JSON.stringify(scripts).replace(/</g, "\\u003c");// Match Expo's asset base URL rather than assuming deployment at the host root.const baseUrl = scripts[0].slice(0, scripts[0].lastIndexOf("/") + 1);html = html.replace( "</body>", `<script id="bootstrap-scripts" type="application/json">${manifest}</script><script src="${baseUrl}${filename}" defer></script></body>`,);await writeFile(htmlPath, html);console.log( `Web bootstrap: ${code.length} initial JS bytes; ${scripts.length} Expo scripts deferred until after paint`,);