Showing the changes to apps/cli/src (2 of 8 files). Show all
Unified · Split
| @@ -2,7 +2,7 @@ import { cp, mkdir, rm, writeFile, chmod } from "node:fs/promises"; · 1 unmodified line | ||
| 2 | 2 | import { existsSync } from "node:fs"; |
| 3 | 3 | import { createRequire } from "node:module"; |
| 4 | 4 | import { resolve, join, dirname } from "node:path"; |
| 5 | −import { fileURLToPath } from "node:url"; | |
| 5 | +import { fileURLToPath, pathToFileURL } from "node:url"; | |
| 6 | 6 | import { parseArgs } from "node:util"; |
| 7 | 7 | import { $ } from "bun"; |
| 8 | 8 | |
| @@ -11,6 +11,8 @@ const cliRoot = resolve(repoRoot, "apps/cli"); · 2 unmodified lines | ||
| 11 | 11 | const webRoot = resolve(repoRoot, "apps/local"); |
| 12 | 12 | const distDir = resolve(cliRoot, "dist"); |
| 13 | 13 | const ONEPASSWORD_CORE_WASM_FILENAME = "onepassword-core_bg.wasm"; |
| 14 | +const WORKERD_VERSION = "1.20260708.1"; | |
| 15 | +const WORKER_BUNDLER_DIRNAME = "worker-bundler"; | |
| 14 | 16 | |
| 15 | 17 | const resolveQuickJsWasmPath = (): string => { |
| 16 | 18 | const req = createRequire(join(repoRoot, "packages/kernel/runtime-quickjs/package.json")); |
| @@ -33,6 +35,34 @@ const resolveOnePasswordCoreWasmPath = (): string => { · 16 unmodified lines | ||
| 33 | 35 | return wasmPath; |
| 34 | 36 | }; |
| 35 | 37 | |
| 38 | +const resolveWorkerBundlerDistPath = (): string => { | |
| 39 | + const req = createRequire(join(repoRoot, "packages/plugins/apps/package.json")); | |
| 40 | + const pkgJson = req.resolve("@cloudflare/worker-bundler/package.json"); | |
| 41 | + const distPath = join(dirname(pkgJson), "dist"); | |
| 42 | + if (!existsSync(join(distPath, "index.js")) || !existsSync(join(distPath, "esbuild.wasm"))) { | |
| 43 | + throw new Error(`@cloudflare/worker-bundler dist files not found at ${distPath}`); | |
| 44 | + } | |
| 45 | + return distPath; | |
| 46 | +}; | |
| 47 | + | |
| 48 | +const createPackedWorkerBundlerSource = async (distPath: string): Promise<string> => { | |
| 49 | + const esbuildPath = join(repoRoot, "node_modules/.bun/node_modules/esbuild/lib/main.js"); | |
| 50 | + if (!existsSync(esbuildPath)) throw new Error(`esbuild not found at ${esbuildPath}`); | |
| 51 | + const { build } = await import(pathToFileURL(esbuildPath).href); | |
| 52 | + const result = await build({ | |
| 53 | + entryPoints: [join(distPath, "index.js")], | |
| 54 | + bundle: true, | |
| 55 | + format: "esm", | |
| 56 | + platform: "browser", | |
| 57 | + external: ["./esbuild.wasm"], | |
| 58 | + logLevel: "silent", | |
| 59 | + write: false, | |
| 60 | + }); | |
| 61 | + const source = result.outputFiles[0]?.text; | |
| 62 | + if (source === undefined) throw new Error("failed to bundle @cloudflare/worker-bundler"); | |
| 63 | + return source; | |
| 64 | +}; | |
| 65 | + | |
| 36 | 66 | // --------------------------------------------------------------------------- |
| 37 | 67 | // Metadata |
| 38 | 68 | // --------------------------------------------------------------------------- |
| @@ -119,6 +149,7 @@ const bunTarget = (t: Target): Bun.Build.CompileTarget => { · 80 unmodified lines | ||
| 119 | 149 | }; |
| 120 | 150 | |
| 121 | 151 | const binaryName = (t: Target) => (t.os === "win32" ? "executor.exe" : "executor"); |
| 152 | +const workerdBinaryName = (t: Target) => (t.os === "win32" ? "workerd.exe" : "workerd"); | |
| 122 | 153 | |
| 123 | 154 | const isCurrentPlatform = (t: Target) => |
| 124 | 155 | t.os === process.platform && t.arch === process.arch && !t.abi; |
| @@ -211,6 +242,41 @@ const resolveLibsqlNative = (t: Target): string | null => { · 86 unmodified lines | ||
| 211 | 242 | } |
| 212 | 243 | }; |
| 213 | 244 | |
| 245 | +const resolveWorkerdBinary = (t: Target): string | null => { | |
| 246 | + const platformMap: Record<string, string> = { | |
| 247 | + "darwin-arm64": "@cloudflare/workerd-darwin-arm64", | |
| 248 | + "darwin-x64": "@cloudflare/workerd-darwin-64", | |
| 249 | + "linux-arm64": "@cloudflare/workerd-linux-arm64", | |
| 250 | + "linux-x64": "@cloudflare/workerd-linux-64", | |
| 251 | + "win32-x64": "@cloudflare/workerd-windows-64", | |
| 252 | + }; | |
| 253 | + const key = [t.os, t.arch, t.abi].filter(Boolean).join("-"); | |
| 254 | + const pkg = platformMap[key]; | |
| 255 | + if (!pkg) return null; | |
| 256 | + const binary = workerdBinaryName(t); | |
| 257 | + try { | |
| 258 | + const req = createRequire( | |
| 259 | + join(repoRoot, "packages/kernel/runtime-workerd-subprocess/package.json"), | |
| 260 | + ); | |
| 261 | + const pkgJson = req.resolve(`${pkg}/package.json`); | |
| 262 | + for (const candidate of [ | |
| 263 | + join(dirname(pkgJson), "bin", binary), | |
| 264 | + join(dirname(pkgJson), binary), | |
| 265 | + ]) { | |
| 266 | + if (existsSync(candidate)) return candidate; | |
| 267 | + } | |
| 268 | + } catch { | |
| 269 | + const packageRoot = join( | |
| 270 | + repoRoot, | |
| 271 | + `node_modules/.bun/${pkg.replace("/", "+")}@${WORKERD_VERSION}/node_modules/${pkg}`, | |
| 272 | + ); | |
| 273 | + for (const candidate of [join(packageRoot, "bin", binary), join(packageRoot, binary)]) { | |
| 274 | + if (existsSync(candidate)) return candidate; | |
| 275 | + } | |
| 276 | + } | |
| 277 | + return null; | |
| 278 | +}; | |
| 279 | + | |
| 214 | 280 | // --------------------------------------------------------------------------- |
| 215 | 281 | // Build mode |
| 216 | 282 | // --------------------------------------------------------------------------- |
| @@ -333,6 +399,8 @@ const buildBinaries = async (targets: Target[], mode: BuildMode) => { · 116 unmodified lines | ||
| 333 | 399 | |
| 334 | 400 | const quickJsWasmPath = resolveQuickJsWasmPath(); |
| 335 | 401 | const onePasswordCoreWasmPath = resolveOnePasswordCoreWasmPath(); |
| 402 | + const workerBundlerDistPath = resolveWorkerBundlerDistPath(); | |
| 403 | + const packedWorkerBundlerSource = await createPackedWorkerBundlerSource(workerBundlerDistPath); | |
| 336 | 404 | |
| 337 | 405 | try { |
| 338 | 406 | for (const target of targets) { |
| @@ -375,12 +443,35 @@ const buildBinaries = async (targets: Target[], mode: BuildMode) => { · 36 unmodified lines | ||
| 375 | 443 | await cp(libsqlNative, join(binDir, "libsql.node")); |
| 376 | 444 | } |
| 377 | 445 | |
| 446 | + const workerdBinary = resolveWorkerdBinary(target); | |
| 447 | + if (workerdBinary && existsSync(workerdBinary)) { | |
| 448 | + await cp(workerdBinary, join(binDir, workerdBinaryName(target))); | |
| 449 | + if (target.os !== "win32") await chmod(join(binDir, workerdBinaryName(target)), 0o755); | |
| 450 | + } | |
| 451 | + | |
| 452 | + await cp(workerBundlerDistPath, join(binDir, WORKER_BUNDLER_DIRNAME, "dist"), { | |
| 453 | + recursive: true, | |
| 454 | + }); | |
| 455 | + await writeFile( | |
| 456 | + join(binDir, WORKER_BUNDLER_DIRNAME, "dist", "index.bundled.js"), | |
| 457 | + packedWorkerBundlerSource, | |
| 458 | + ); | |
| 459 | + | |
| 378 | 460 | // Smoke test on current platform |
| 379 | 461 | if (isCurrentPlatform(target)) { |
| 380 | 462 | const bin = join(binDir, binaryName(target)); |
| 381 | 463 | console.log(` Smoke test: ${bin} --version`); |
| 382 | 464 | const version = await $`${bin} --version`.text(); |
| 383 | 465 | console.log(` OK: ${version.trim()}`); |
| 466 | + console.log(` Smoke test: packed apps source sync and invoke`); | |
| 467 | + const smoke = Bun.spawn( | |
| 468 | + ["bun", "run", join(cliRoot, "scripts/smoke-packed-apps.ts"), bin], | |
| 469 | + { | |
| 470 | + cwd: repoRoot, | |
| 471 | + stdio: ["ignore", "inherit", "inherit"], | |
| 472 | + }, | |
| 473 | + ); | |
| 474 | + if ((await smoke.exited) !== 0) throw new Error("packed apps smoke failed"); | |
| 384 | 475 | } |
| 385 | 476 | |
| 386 | 477 | // Variant package.json. All variants publish to the SAME npm package |
| @@ -1,11 +1,10 @@ | ||
| 1 | 1 | // --------------------------------------------------------------------------- |
| 2 | 2 | // Native-binding bootstrap for the `bun build --compile` binary. |
| 3 | 3 | // |
| 4 | −// `bun --compile` bundles JS into bunfs but does NOT include `.node` native | |
| 5 | −// addons, so a dynamic `require('@libsql/<platform>')` / keyring walk inside | |
| 6 | −// the binary fails. build.ts copies each platform's `.node` next to the | |
| 7 | −// executable (`libsql.node`, `keyring.node`); here we publish their on-disk | |
| 8 | −// paths via env vars the loaders read. | |
| 4 | +// `bun --compile` bundles JS into bunfs but does NOT include native binaries, | |
| 5 | +// wasm sidecars, or runtime-read package files. build.ts copies those artifacts | |
| 6 | +// next to the executable; here we publish their on-disk paths via env vars the | |
| 7 | +// loaders read. | |
| 9 | 8 | // |
| 10 | 9 | // This MUST be the FIRST import in main.ts. ES modules evaluate every import |
| 11 | 10 | // before the importer's own body, and libSQL resolves its native addon EAGERLY |
| @@ -43,3 +42,18 @@ if ( · 31 unmodified lines | ||
| 43 | 42 | ) { |
| 44 | 43 | process.env.EXECUTOR_KEYRING_NATIVE_PATH = keyringNodeOnDisk; |
| 45 | 44 | } |
| 45 | + | |
| 46 | +const workerdOnDisk = join(execDir, process.platform === "win32" ? "workerd.exe" : "workerd"); | |
| 47 | +if (typeof Bun !== "undefined" && !process.env.EXECUTOR_WORKERD_BIN && existsSync(workerdOnDisk)) { | |
| 48 | + process.env.EXECUTOR_WORKERD_BIN = workerdOnDisk; | |
| 49 | +} | |
| 50 | + | |
| 51 | +const workerBundlerOnDisk = join(execDir, "worker-bundler"); | |
| 52 | +if ( | |
| 53 | + typeof Bun !== "undefined" && | |
| 54 | + !process.env.EXECUTOR_WORKER_BUNDLER_DIR && | |
| 55 | + existsSync(join(workerBundlerOnDisk, "dist", "index.js")) && | |
| 56 | + existsSync(join(workerBundlerOnDisk, "dist", "esbuild.wasm")) | |
| 57 | +) { | |
| 58 | + process.env.EXECUTOR_WORKER_BUNDLER_DIR = workerBundlerOnDisk; | |
| 59 | +} | |