Skip to content

feat: add esbuild single-file bundle as lightweight distribution #1577

@Mossaka

Description

@Mossaka

Problem

The AWF CLI binary is ~50MB because pkg bundles the entire Node.js 18 runtime. GitHub hosted runners (the primary deployment target) already have Node.js 22 in the tool cache, making the bundled runtime redundant.

Additionally, pkg targets Node.js 18 which has been EOL since April 2025, while the project's own engines field requires >=20.12.0 and CI only tests against Node 20/22.

Proposal

Ship an esbuild single-file bundle (awf-bundle.js, ~2MB) alongside the existing pkg binaries. The install script detects Node.js availability and prefers the lightweight bundle.

Changes

  1. scripts/build-bundle.mjs — esbuild config bundling dist/cli.js into a single CJS file with platform: 'node', target: 'node20', minify: true, and #!/usr/bin/env node banner.

  2. src/docker-manager.ts — Support embedded seccomp profile via esbuild define. The bundled code writes the profile from memory; the existing file-based path remains as fallback for tsc output. Guard --build-local to error clearly when running from the bundle (requires full repo checkout).

  3. package.json — Add esbuild devDep, add build:bundle script.

  4. .github/workflows/release.yml — Build esbuild bundle alongside pkg binaries, include awf-bundle.js in release artifacts and checksums.

  5. install.sh — Add Node.js >= 20 detection. Download bundle when Node available, fall back to pkg binary otherwise. Add AWF_FORCE_BINARY=1 escape hatch.

Technical details

There are only 2 __dirname usage sites in production code (src/docker-manager.ts):

  • Line 360: projectRoot for --build-local Docker context paths — only needed with full repo checkout, not applicable to standalone bundle
  • Lines 1681/1688: seccomp profile loading — solved by inlining JSON at build time via esbuild define

Non-goals

  • Do NOT bump pkg targets from node18 to node20/22 (pkg is unmaintained, uncertain support)
  • Do NOT remove pkg binaries (handled separately in #NEXT)

Verification

  • npm run build:bundle produces release/awf-bundle.js < 5MB
  • node release/awf-bundle.js --version and --help work correctly
  • sudo node release/awf-bundle.js --allow-domains example.com -- curl https://example.com works end-to-end
  • install.sh with Node 22 downloads bundle; without Node downloads pkg binary
  • Existing pkg binary path continues to work unchanged

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions