UNPKG

elm-pages

Version:

Hybrid Elm framework with full-stack and static routes.

111 lines (102 loc) 3.52 kB
import * as renderer from "../../generator/src/render.js"; import * as path from "node:path"; import * as fs from "./dir-helpers.js"; import { readFileSync, writeFileSync } from "node:fs"; import { parentPort, threadId, workerData } from "node:worker_threads"; import * as url from "node:url"; async function run({ mode, pathname, serverRequest, portsFilePath }) { console.time(`${threadId} ${pathname}`); try { const renderResult = await renderer.render( typeof portsFilePath === "string" ? await import(url.pathToFileURL(path.resolve(portsFilePath)).href) : portsFilePath, workerData.basePath, await requireElm(mode), mode, pathname, serverRequest, function (patterns) { if (mode === "dev-server" && patterns.size > 0) { parentPort.postMessage({ tag: "watch", data: [...patterns] }); } }, true ); if (mode === "dev-server") { parentPort.postMessage({ tag: "done", data: renderResult }); } else if (mode === "build") { outputString(renderResult, pathname); } else { throw `Unknown mode ${mode}`; } } catch (error) { if (error.errorsJson) { parentPort.postMessage({ tag: "error", data: error.errorsJson }); } else { parentPort.postMessage({ tag: "error", data: error }); } } console.timeEnd(`${threadId} ${pathname}`); } async function requireElm(mode) { const compiledElmPath = path.join( process.cwd(), "elm-stuff/elm-pages/elm.cjs" ); let pathAsUrl = url.pathToFileURL(compiledElmPath); const warnOriginal = console.warn; console.warn = function () {}; const Elm = (await import(pathAsUrl.toString())).default; console.warn = warnOriginal; return Elm; } async function outputString( /** @type { { kind: 'page'; data: PageProgress } | { kind: 'api'; data: Object } } */ fromElm, /** @type string */ pathname ) { switch (fromElm.kind) { case "html": { const args = fromElm; const normalizedRoute = args.route.replace(/index$/, ""); await fs.tryMkdir(`./dist/${normalizedRoute}`); const template = readFileSync("./dist/template.html", "utf8"); writeFileSync( `dist/${normalizedRoute}/index.html`, renderTemplate(template, fromElm) ); args.contentDatPayload && writeFileSync( `dist/${normalizedRoute}/content.dat`, Buffer.from(args.contentDatPayload.buffer) ); parentPort.postMessage({ tag: "done" }); break; } case "api-response": { const body = fromElm.body.body; console.log(`Generated ${pathname}`); fs.writeFileSyncSafe(path.join("dist", pathname), body); if (pathname === "/all-paths.json") { parentPort.postMessage({ tag: "all-paths", data: body }); } else { parentPort.postMessage({ tag: "done" }); } break; } } } function renderTemplate(template, renderResult) { const info = renderResult.htmlString; return template .replace( /<!--\s*PLACEHOLDER_HEAD_AND_DATA\s*-->/, `${info.headTags} <script id="__ELM_PAGES_BYTES_DATA__" type="application/octet-stream">${info.bytesData}</script>` ) .replace(/<!--\s*PLACEHOLDER_TITLE\s*-->/, info.title) .replace(/<!--\s*PLACEHOLDER_HTML\s* -->/, info.html) .replace(/<!-- ROOT -->\S*<html lang="en">/m, info.rootElement); } parentPort.on("message", run); /** @typedef { { tag : 'PageProgress'; args : Arg[] } } PageProgress */