History

Package workerd for local binaries

Rhys Sullivan committed 4 months ago

Commit 4be58bc1 parent da4f37c8 files · +491 −56Browse files

Showing the changes to apps/cli/src (2 of 8 files). Show all

Unified · Split

2 files
  1. apps/cli/src/build.ts +92 −1
  2. apps/cli/src/native-bindings.ts +19 −5
apps/cli/src/build.ts+92−1
@@ -2,7 +2,7 @@ import { cp, mkdir, rm, writeFile, chmod } from "node:fs/promises"; · 1 unmodified line
22 import { existsSync } from "node:fs";
33 import { createRequire } from "node:module";
44 import { resolve, join, dirname } from "node:path";
5−import { fileURLToPath } from "node:url";
5+import { fileURLToPath, pathToFileURL } from "node:url";
66 import { parseArgs } from "node:util";
77 import { $ } from "bun";
88
@@ -11,6 +11,8 @@ const cliRoot = resolve(repoRoot, "apps/cli"); · 2 unmodified lines
1111 const webRoot = resolve(repoRoot, "apps/local");
1212 const distDir = resolve(cliRoot, "dist");
1313 const ONEPASSWORD_CORE_WASM_FILENAME = "onepassword-core_bg.wasm";
14+const WORKERD_VERSION = "1.20260708.1";
15+const WORKER_BUNDLER_DIRNAME = "worker-bundler";
1416
1517 const resolveQuickJsWasmPath = (): string => {
1618 const req = createRequire(join(repoRoot, "packages/kernel/runtime-quickjs/package.json"));
@@ -33,6 +35,34 @@ const resolveOnePasswordCoreWasmPath = (): string => { · 16 unmodified lines
3335 return wasmPath;
3436 };
3537
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+
3666 // ---------------------------------------------------------------------------
3767 // Metadata
3868 // ---------------------------------------------------------------------------
@@ -119,6 +149,7 @@ const bunTarget = (t: Target): Bun.Build.CompileTarget => { · 80 unmodified lines
119149 };
120150
121151 const binaryName = (t: Target) => (t.os === "win32" ? "executor.exe" : "executor");
152+const workerdBinaryName = (t: Target) => (t.os === "win32" ? "workerd.exe" : "workerd");
122153
123154 const isCurrentPlatform = (t: Target) =>
124155 t.os === process.platform && t.arch === process.arch && !t.abi;
@@ -211,6 +242,41 @@ const resolveLibsqlNative = (t: Target): string | null => { · 86 unmodified lines
211242 }
212243 };
213244
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+
214280 // ---------------------------------------------------------------------------
215281 // Build mode
216282 // ---------------------------------------------------------------------------
@@ -333,6 +399,8 @@ const buildBinaries = async (targets: Target[], mode: BuildMode) => { · 116 unmodified lines
333399
334400 const quickJsWasmPath = resolveQuickJsWasmPath();
335401 const onePasswordCoreWasmPath = resolveOnePasswordCoreWasmPath();
402+ const workerBundlerDistPath = resolveWorkerBundlerDistPath();
403+ const packedWorkerBundlerSource = await createPackedWorkerBundlerSource(workerBundlerDistPath);
336404
337405 try {
338406 for (const target of targets) {
@@ -375,12 +443,35 @@ const buildBinaries = async (targets: Target[], mode: BuildMode) => { · 36 unmodified lines
375443 await cp(libsqlNative, join(binDir, "libsql.node"));
376444 }
377445
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+
378460 // Smoke test on current platform
379461 if (isCurrentPlatform(target)) {
380462 const bin = join(binDir, binaryName(target));
381463 console.log(` Smoke test: ${bin} --version`);
382464 const version = await $`${bin} --version`.text();
383465 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");
384475 }
385476
386477 // Variant package.json. All variants publish to the SAME npm package
apps/cli/src/native-bindings.ts+19−5
@@ -1,11 +1,10 @@
11 // ---------------------------------------------------------------------------
22 // Native-binding bootstrap for the `bun build --compile` binary.
33 //
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.
98 //
109 // This MUST be the FIRST import in main.ts. ES modules evaluate every import
1110 // before the importer's own body, and libSQL resolves its native addon EAGERLY
@@ -43,3 +42,18 @@ if ( · 31 unmodified lines
4342 ) {
4443 process.env.EXECUTOR_KEYRING_NATIVE_PATH = keyringNodeOnDisk;
4544 }
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+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t