UNPKG

everything-dev

Version:

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

335 lines (333 loc) 12.2 kB
const require_runtime = require('./_virtual/_rolldown/runtime.cjs'); const require_config = require('./config.cjs'); const require_integrity = require('./integrity.cjs'); const require_timing = require('./cli/timing.cjs'); const require_shared_deps = require('./shared-deps.cjs'); const require_run = require('./utils/run.cjs'); const require_string = require('./utils/string.cjs'); const require_theme = require('./utils/theme.cjs'); let node_fs = require("node:fs"); let node_path = require("node:path"); let node_process = require("node:process"); node_process = require_runtime.__toESM(node_process, 1); let node_fs_promises = require("node:fs/promises"); //#region src/build.ts const buildCommands = { host: { cmd: "bun", args: ["run", "build"] }, ui: { cmd: "bun", args: ["run", "build"] }, api: { cmd: "bun", args: ["run", "build"] } }; function getPluginRef(entry) { if (!entry || typeof entry === "string") return null; return entry; } async function fileExists(path) { try { await (0, node_fs_promises.access)(path); return true; } catch { return false; } } async function readJsonFile(path) { return JSON.parse(await (0, node_fs_promises.readFile)(path, "utf8")); } function resolveWorkspaceTarget(key, bosConfig, runtimeConfig, configDir) { if (bosConfig?.app && key in bosConfig.app) { const appEntry = bosConfig.app[key]; const devPath = require_config.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 ?? require_config.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; return packages.split(",").map((pkg) => pkg.trim()).filter((pkg) => allPackages.includes(pkg)); } async function runBuildAttempt(cmd, args, cwd, env, verbose, wsKey) { let zephyrAuthShown = false; const result = await require_run.run(cmd, args, { cwd, env, capture: true, onChunk: (stream, chunk) => { if (verbose) if (stream === "stdout") node_process.default.stdout.write(chunk); else node_process.default.stderr.write(chunk); if (zephyrAuthShown) return; const text = chunk.toString("utf-8"); if (/Authentication required.*log in to Zephyr/i.test(text) || /auth\.zephyr-cloud\.io\/authorize/.test(text)) { zephyrAuthShown = true; const urlMatch = text.match(/https:\/\/auth\.zephyr-cloud\.io\/authorize\S+/); console.log(); console.log(require_theme.colors.yellow(` ⚠ Zephyr authentication required for ${wsKey}`)); if (urlMatch) console.log(` ${require_theme.colors.cyan(urlMatch[0])}`); console.log(require_theme.colors.dim(" Waiting for authentication...")); console.log(); } } }); const stdout = result?.stdout ?? ""; const stderr = result?.stderr ?? ""; const exitCode = result?.exitCode ?? 0; const output = `${stdout}\n${stderr}`; const deployEntries = require_integrity.parseDeployLines(output); if (deployEntries.length > 0) { if (exitCode !== 0) { const errorLines = output.split("\n").filter((line) => /\bERROR\b/.test(line) || line.startsWith("Rspack compiled with")).slice(0, 5); if (errorLines.length > 0 && !verbose) { console.log(` ${require_theme.colors.yellow("⚠")} Build completed with errors (exit code ${exitCode}) — Zephyr deployed successfully`); for (const line of errorLines) console.log(` ${require_theme.colors.dim(line.trim())}`); } } return { success: true, url: deployEntries[0]?.url, exitCode: 0, output, deployEntries }; } if (exitCode !== 0) return { success: false, error: `Build failed (exit code ${exitCode})\n${output.trim().split("\n").slice(-5).join("\n")}`, exitCode, output }; const zeMatch = output.match(/ZE\d+/); if (zeMatch) return { success: false, error: `Zephyr upload failed (${zeMatch[0]})`, exitCode: 0, output }; const deployMatch = output.match(/🚀.*Deployed:\s*(https?:\S+)/); if (deployMatch) return { success: true, url: deployMatch[1], exitCode: 0, output }; if (env.DEPLOY === "true") return { success: false, error: "No deploy URL found (Zephyr may have failed)", exitCode: 0, output }; return { success: true, exitCode: 0, output }; } async function buildOneWorkspace(ws, env, opts) { const pkgJson = await readJsonFile(`${ws.path}/package.json`); const buildConfig = opts.deploy && pkgJson.scripts?.deploy ? { cmd: "bun", args: ["run", "deploy"] } : buildCommands[ws.key] ?? { cmd: "bun", args: ["run", "build"] }; const wsEnv = { ...env }; const startTime = Date.now(); let attempt = await runBuildAttempt(buildConfig.cmd, buildConfig.args, ws.path, wsEnv, opts.verbose ?? false, ws.key); let retried = false; if (!attempt.success && attempt.exitCode === 0 && opts.deploy) { if (!opts.verbose) console.log(` ${require_theme.colors.yellow("↻")} ${require_string.padRight(ws.key, 28)} retrying...`); retried = true; attempt = await runBuildAttempt(buildConfig.cmd, buildConfig.args, ws.path, wsEnv, opts.verbose ?? false, ws.key); } const durationMs = Date.now() - startTime; const result = { key: ws.key, kind: ws.kind, success: attempt.success, url: attempt.url, error: attempt.error, deployEntries: attempt.deployEntries, durationMs, retried: retried ? true : void 0 }; if (!opts.verbose) { const name = require_string.padRight(ws.key, 28); if (result.success) { const duration = require_timing.formatDuration(durationMs); const retryTag = retried ? " (retried)" : ""; console.log(` ${require_theme.colors.green(require_theme.icons.ok)} ${name} ${require_theme.colors.dim(duration + retryTag)}`); } else { const errorLine = (result.error ?? "Failed").split("\n")[0]; console.log(` ${require_theme.colors.error(require_theme.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 require_shared_deps.syncResolvedSharedDeps({ configDir: opts.configDir, hostMode: "local", bosConfig: opts.bosConfig ?? void 0, extendsChain: [] })).catalogChanged) await require_run.run("bun", ["install"], { cwd: opts.configDir }); const shouldBuildPlugin = existing.some((entry) => entry.key === "api"); const forceRebuild = opts.deploy; const buildTasks = [buildEverythingDevQuietly(opts.configDir, forceRebuild)]; if (shouldBuildPlugin) buildTasks.push(buildEveryPluginQuietly(opts.configDir, forceRebuild)); await Promise.all(buildTasks); const env = { ...node_process.default.env, NODE_ENV: opts.deploy ? "production" : "development" }; if (opts.deploy) env.DEPLOY = "true"; else delete env.DEPLOY; const bosConfigPath = (0, node_path.join)(opts.configDir, "bos.config.json"); let configSnapshot; if (opts.deploy && (0, node_fs.existsSync)(bosConfigPath)) configSnapshot = (0, node_fs.readFileSync)(bosConfigPath, "utf-8"); 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))); const allDeployEntries = []; 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); if (result.value.deployEntries) allDeployEntries.push(...result.value.deployEntries); const { deployEntries: _deployEntries, ...deployResult } = result.value; deployResults.push(deployResult); } else deployResults.push({ key: ws.key, kind: ws.kind, success: false, error: result.reason?.message ?? "Unknown error" }); } if (configSnapshot && allDeployEntries.length > 0) { const merged = require_integrity.applyDeployResults(JSON.parse(configSnapshot), allDeployEntries); (0, node_fs.writeFileSync)(bosConfigPath, `${JSON.stringify(merged, null, 2)}\n`); } for (const ws of sequentialGroup) { const result = await buildOneWorkspace(ws, env, opts); if (result.success) built.push(ws.key); if (result.deployEntries) { const hostEntries = result.deployEntries.filter((r) => r.urlField.startsWith("app.host")); if (hostEntries.length > 0 && (0, node_fs.existsSync)(bosConfigPath)) { const merged = require_integrity.applyDeployResults(JSON.parse((0, node_fs.readFileSync)(bosConfigPath, "utf-8")), hostEntries); (0, node_fs.writeFileSync)(bosConfigPath, `${JSON.stringify(merged, null, 2)}\n`); } } const { deployEntries: _deployEntries, ...sequentialResult } = result; deployResults.push(sequentialResult); } console.log(); } else for (const resolved of orderedExisting) { const buildConfig = buildCommands[resolved.key] ?? { cmd: "bun", args: ["run", "build"] }; await require_run.run(buildConfig.cmd, buildConfig.args, { cwd: resolved.path, env }); built.push(resolved.key); } return { built, skipped, deployResults: opts.deploy ? deployResults : void 0 }; } async function buildEveryPluginQuietly(cwd, force = false) { if (!await fileExists(`${`${cwd}/packages/every-plugin`}/package.json`)) return; if (await fileExists(`${cwd}/packages/every-plugin/dist/build/rspack/plugin.mjs`) && !force) return; const result = await require_run.run("bun", [ "run", "--cwd", "packages/every-plugin", "build" ], { cwd, capture: true }); if (result.exitCode === 0) return; if (result.stdout.trim()) node_process.default.stdout.write(result.stdout); if (result.stderr.trim()) node_process.default.stderr.write(result.stderr); throw new Error(`bun run --cwd packages/every-plugin build failed with exit code ${result.exitCode}`); } async function buildEverythingDevQuietly(cwd, force = false) { if (!await fileExists(`${`${cwd}/packages/everything-dev`}/package.json`)) return; if (await fileExists(`${cwd}/packages/everything-dev/dist/index.mjs`) && !force) return; const result = await require_run.run("bun", [ "run", "--cwd", "packages/everything-dev", "build" ], { cwd, capture: true }); if (result.exitCode === 0) return; if (result.stdout.trim()) node_process.default.stdout.write(result.stdout); if (result.stderr.trim()) node_process.default.stderr.write(result.stderr); throw new Error(`bun run --cwd packages/everything-dev build failed with exit code ${result.exitCode}`); } //#endregion exports.buildEveryPluginQuietly = buildEveryPluginQuietly; exports.buildEverythingDevQuietly = buildEverythingDevQuietly; exports.buildWorkspaceTargets = buildWorkspaceTargets; exports.fileExists = fileExists; exports.getPluginRef = getPluginRef; exports.readJsonFile = readJsonFile; exports.selectWorkspaceTargets = selectWorkspaceTargets; //# sourceMappingURL=build.cjs.map