UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

194 lines (192 loc) • 6.38 kB
import { resolveLocalDevelopmentPath } from "./config.mjs"; import { run } from "./utils/run.mjs"; import { colors, icons } from "./utils/theme.mjs"; import { formatDuration } from "./cli/timing.mjs"; import { ensureFreshDeps, findWorkspaceRoot } from "./workspace.mjs"; import { syncResolvedSharedDeps } from "./shared-deps.mjs"; import { padRight } from "./utils/string.mjs"; import process from "node:process"; import { access, readFile } from "node:fs/promises"; //#region src/build.ts const buildCommands = { host: { cmd: "pnpm", args: ["run", "build"] }, ui: { cmd: "pnpm", args: ["run", "build"] }, api: { cmd: "pnpm", args: ["run", "build"] } }; function getPluginRef(entry) { if (!entry || typeof entry === "string") return null; return entry; } async function fileExists(path) { try { await access(path); return true; } catch { return false; } } function resolveWorkspaceTarget(key, bosConfig, runtimeConfig, configDir) { if (bosConfig?.app && key in bosConfig.app) { const appEntry = bosConfig.app[key]; const devPath = resolveLocalDevelopmentPath(appEntry?.development, configDir); if (devPath) return { key, kind: "app", path: devPath }; return { key, kind: "app", path: `${configDir}/${key}` }; } const pluginPath = (runtimeConfig?.plugins?.[key])?.localPath ?? resolveLocalDevelopmentPath(getPluginRef(bosConfig?.plugins?.[key])?.development, configDir); if (pluginPath) return { key, kind: "plugin", path: pluginPath }; return null; } function selectWorkspaceTargets(packages, bosConfig) { const allPackages = [...Object.keys(bosConfig?.app ?? {}), ...Object.keys(bosConfig?.plugins ?? {})]; if (packages === "all") return allPackages; if (packages === "local") return allPackages.filter((k) => isLocalTarget(k, bosConfig)); return packages.split(",").map((pkg) => pkg.trim()).filter((pkg) => allPackages.includes(pkg)); } function isLocalTarget(key, bosConfig) { const dev = ((bosConfig?.app)?.[key] ?? bosConfig?.plugins?.[key])?.development; return typeof dev === "string" && dev.startsWith("local:"); } async function buildOneWorkspace(ws, env, opts) { const buildConfig = buildCommands[ws.key] ?? { cmd: "pnpm", args: ["run", "build"] }; const verbose = opts.verbose ?? false; const startTime = Date.now(); const proc = await run(buildConfig.cmd, buildConfig.args, { cwd: ws.path, env, capture: true, onChunk: (stream, chunk) => { if (stream === "stderr") process.stderr.write(chunk); else if (verbose) process.stdout.write(chunk); } }); const exitCode = proc?.exitCode ?? 0; const durationMs = Date.now() - startTime; const output = `${proc?.stdout ?? ""}\n${proc?.stderr ?? ""}`; const result = { key: ws.key, kind: ws.kind, success: exitCode === 0, ...exitCode !== 0 && { error: `Build failed (exit code ${exitCode})\n${output.trim().split("\n").slice(-5).join("\n")}` }, durationMs }; if (!verbose) { const name = padRight(ws.key, 28); if (result.success) console.log(` ${colors.green(icons.ok)} ${name} ${colors.dim(formatDuration(durationMs))}`); else { const errorLine = (result.error ?? "Failed").split("\n")[0]; console.log(` ${colors.error(icons.err)} ${name} ${errorLine}`); } } return result; } async function buildWorkspaceTargets(opts) { const existing = []; const skipped = []; for (const target of opts.targets) { const resolved = resolveWorkspaceTarget(target, opts.bosConfig, opts.runtimeConfig, opts.configDir); if (!resolved) { skipped.push(target); continue; } if (await fileExists(`${resolved.path}/package.json`)) existing.push(resolved); else skipped.push(target); } if (existing.length === 0) return { built: [], skipped }; if ((await syncResolvedSharedDeps({ configDir: opts.configDir, hostMode: "local", bosConfig: opts.bosConfig ?? void 0, extendsChain: [] })).catalogChanged) await run("pnpm", ["install"], { cwd: findWorkspaceRoot(opts.configDir)?.dir ?? opts.configDir }); const env = { ...process.env, NODE_ENV: opts.deploy ? "production" : "development" }; if (opts.deploy) env.DEPLOY = "true"; else delete env.DEPLOY; const depsReport = await ensureFreshDeps(opts.configDir, existing.map((entry) => entry.path), { force: opts.deploy, env }); if (depsReport.rebuilt.length > 0) console.log(` ${colors.dim(`prerequisites: rebuilt ${depsReport.rebuilt.map((member) => member.name).join(", ")}`)}`); const orderedExisting = opts.deploy ? [ ...existing.filter((entry) => entry.kind === "app" && entry.key !== "host"), ...existing.filter((entry) => entry.kind === "plugin"), ...existing.filter((entry) => entry.kind === "app" && entry.key === "host") ] : existing; const parallelGroup = opts.deploy ? orderedExisting.filter((e) => e.key !== "host") : orderedExisting; const sequentialGroup = opts.deploy ? orderedExisting.filter((e) => e.key === "host") : []; const built = []; const deployResults = []; if (opts.deploy && parallelGroup.length > 0) { const total = parallelGroup.length + sequentialGroup.length; console.log(); console.log(` Building ${total} workspace${total > 1 ? "s" : ""}...`); console.log(); const results = await Promise.allSettled(parallelGroup.map((ws) => buildOneWorkspace(ws, env, opts))); for (let i = 0; i < parallelGroup.length; i++) { const ws = parallelGroup[i]; const result = results[i]; if (result.status === "fulfilled") { if (result.value.success) built.push(ws.key); deployResults.push(result.value); } else deployResults.push({ key: ws.key, kind: ws.kind, success: false, error: result.reason?.message ?? "Unknown error" }); } for (const ws of sequentialGroup) { const result = await buildOneWorkspace(ws, env, opts); if (result.success) built.push(ws.key); deployResults.push(result); } console.log(); } else for (const resolved of orderedExisting) { const buildConfig = buildCommands[resolved.key] ?? { cmd: "pnpm", args: ["run", "build"] }; await run(buildConfig.cmd, buildConfig.args, { cwd: resolved.path, env }); built.push(resolved.key); } return { built, skipped, deployResults: opts.deploy ? deployResults : void 0 }; } //#endregion export { buildWorkspaceTargets, fileExists, getPluginRef, resolveWorkspaceTarget, selectWorkspaceTargets }; //# sourceMappingURL=build.mjs.map