|
| 1 | +#!/usr/bin/env bun |
| 2 | +/** |
| 3 | + * Build a single-file standalone link-cli binary for the requested target. |
| 4 | + * |
| 5 | + * Usage: |
| 6 | + * bun run scripts/build-binary.ts <target> |
| 7 | + * |
| 8 | + * Targets: darwin-arm64 | darwin-x64 | linux-x64 | windows-x64 |
| 9 | + * |
| 10 | + * Output is written to dist-bin/link-cli-<target>[.exe]. |
| 11 | + * |
| 12 | + * The bundle entrypoint is the same packages/cli/dist/cli.js that tsup emits, |
| 13 | + * so this script must run AFTER `pnpm turbo run build`. |
| 14 | + * |
| 15 | + * Two of ink's transitive dependencies are stubbed at bundle time: |
| 16 | + * - react-devtools-core: only used when DEV=true; ink uses a dynamic import, |
| 17 | + * but tsup bundles the static reference inside ink/build/devtools.js, which |
| 18 | + * then breaks compile if the optional dep is not installed. |
| 19 | + * - update-notifier: marked external in tsup config; replaced with a noop |
| 20 | + * so the standalone binary does not need the on-disk package present. |
| 21 | + */ |
| 22 | +import { mkdirSync } from 'node:fs'; |
| 23 | +import type { BunPlugin } from 'bun'; |
| 24 | + |
| 25 | +const TARGETS = { |
| 26 | + 'darwin-arm64': 'bun-darwin-arm64', |
| 27 | + 'darwin-x64': 'bun-darwin-x64', |
| 28 | + 'linux-x64': 'bun-linux-x64', |
| 29 | + 'windows-x64': 'bun-windows-x64', |
| 30 | +} as const; |
| 31 | + |
| 32 | +type Target = keyof typeof TARGETS; |
| 33 | + |
| 34 | +const stubPlugin: BunPlugin = { |
| 35 | + name: 'stub-optional-deps', |
| 36 | + setup(build) { |
| 37 | + build.onResolve( |
| 38 | + { filter: /^(react-devtools-core|update-notifier)$/ }, |
| 39 | + (args) => ({ path: args.path, namespace: 'stub' }), |
| 40 | + ); |
| 41 | + build.onLoad({ filter: /.*/, namespace: 'stub' }, (args) => { |
| 42 | + if (args.path === 'react-devtools-core') { |
| 43 | + return { |
| 44 | + contents: 'export default { connectToDevTools() {} };', |
| 45 | + loader: 'js', |
| 46 | + }; |
| 47 | + } |
| 48 | + return { |
| 49 | + contents: |
| 50 | + 'const noop = () => ({ notify: () => {} }); export default noop;', |
| 51 | + loader: 'js', |
| 52 | + }; |
| 53 | + }); |
| 54 | + }, |
| 55 | +}; |
| 56 | + |
| 57 | +const target = (process.argv[2] ?? 'darwin-arm64') as Target; |
| 58 | +const flag = TARGETS[target]; |
| 59 | +if (!flag) { |
| 60 | + console.error(`Unknown target: ${target}`); |
| 61 | + console.error(`Valid targets: ${Object.keys(TARGETS).join(', ')}`); |
| 62 | + process.exit(1); |
| 63 | +} |
| 64 | + |
| 65 | +mkdirSync('dist-bin', { recursive: true }); |
| 66 | + |
| 67 | +const ext = target.startsWith('windows') ? '.exe' : ''; |
| 68 | +const outfile = `./dist-bin/link-cli-${target}${ext}`; |
| 69 | + |
| 70 | +console.log(`Building ${flag} -> ${outfile}`); |
| 71 | + |
| 72 | +await Bun.build({ |
| 73 | + entrypoints: ['./packages/cli/dist/cli.js'], |
| 74 | + // @ts-expect-error compile is a Bun.build option but not in the public types yet |
| 75 | + compile: { target: flag, outfile }, |
| 76 | + plugins: [stubPlugin], |
| 77 | + minify: true, |
| 78 | +}); |
0 commit comments