| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- #!/usr/bin/env bash
- #
- # Build a self-contained CodeGraph bundle: an official Node runtime + the
- # compiled app + its production deps, so CodeGraph runs with NO system Node and
- # NO native build — node:sqlite is built into the bundled Node. One archive per
- # platform.
- #
- # Because dropping better-sqlite3 left zero native addons, the recipe is pure
- # file-packaging (download the target's Node, copy the app, archive) — so any
- # platform's bundle can be built on any OS. No cross-compile, no native runners.
- #
- # Usage:
- # scripts/build-bundle.sh <target> [node-version]
- # target: darwin-arm64 | darwin-x64 | linux-x64 | linux-arm64
- # | win32-x64 | win32-arm64
- # node-version: e.g. v24.16.0 (default below; pin for reproducible builds)
- #
- # Output:
- # unix: release/codegraph-<target>.tar.gz (launcher: bin/codegraph)
- # windows: release/codegraph-<target>.zip (launcher: bin/codegraph.cmd)
- set -euo pipefail
- TARGET="${1:?usage: build-bundle.sh <target> [node-version]}"
- NODE_VERSION="${2:-v24.16.0}"
- ROOT="$(cd "$(dirname "$0")/.." && pwd)"
- OUT="$ROOT/release"
- WORK="$(mktemp -d)"
- trap 'rm -rf "$WORK"' EXIT
- ARCH="${TARGET##*-}" # x64 | arm64
- OSFAM="${TARGET%-*}" # darwin | linux | win32
- echo "[bundle] target=${TARGET} node=${NODE_VERSION}"
- # 1. Download + extract the official Node runtime for the target platform.
- if [ "$OSFAM" = "win32" ]; then
- NODE_DIST="node-${NODE_VERSION}-win-${ARCH}"
- NODE_URL="https://nodejs.org/dist/${NODE_VERSION}/${NODE_DIST}.zip"
- echo "[bundle] downloading ${NODE_URL}"
- curl -fsSL "$NODE_URL" -o "$WORK/node.zip"
- if command -v unzip >/dev/null 2>&1; then
- unzip -q "$WORK/node.zip" -d "$WORK"
- else
- tar -xf "$WORK/node.zip" -C "$WORK" # bsdtar can read zip
- fi
- NODE_BIN="$WORK/${NODE_DIST}/node.exe"
- else
- NODE_DIST="node-${NODE_VERSION}-${TARGET}"
- NODE_URL="https://nodejs.org/dist/${NODE_VERSION}/${NODE_DIST}.tar.gz"
- echo "[bundle] downloading ${NODE_URL}"
- curl -fsSL "$NODE_URL" -o "$WORK/node.tar.gz"
- tar -xzf "$WORK/node.tar.gz" -C "$WORK"
- NODE_BIN="$WORK/${NODE_DIST}/bin/node"
- fi
- [ -f "$NODE_BIN" ] || { echo "[bundle] error: node binary not found ($NODE_BIN)" >&2; exit 1; }
- # 2. Build the app (compiled JS + copied wasm/schema assets).
- echo "[bundle] building app"
- ( cd "$ROOT" && npm run build >/dev/null )
- # 3. Stage: app + production-only deps (pure JS/wasm → portable across platforms).
- STAGE="$WORK/codegraph-${TARGET}"
- mkdir -p "$STAGE/lib" "$STAGE/bin"
- cp -R "$ROOT/dist" "$STAGE/lib/dist"
- cp "$ROOT/package.json" "$ROOT/package-lock.json" "$STAGE/lib/"
- echo "[bundle] installing production dependencies"
- ( cd "$STAGE/lib" && npm ci --omit=dev --ignore-scripts >/dev/null 2>&1 )
- rm -f "$STAGE/lib/package-lock.json"
- # 4. Vendored Node + launcher (the launcher uses the bundled Node by relative
- # path, so no system Node is ever needed).
- #
- # `--liftoff-only`: keep tree-sitter's large WASM grammars on V8's Liftoff
- # baseline compiler so they never reach the turboshaft optimizing tier, whose
- # per-compilation Zone arena OOMs the whole process (`Fatal process out of
- # memory: Zone`) on Node >= 22 — even with tens of GB free. The flag is read at
- # V8 engine init so it must be on node's command line; the parse worker inherits
- # it. See issues #293/#298 and src/extraction/wasm-runtime-flags.ts. (The CLI
- # also self-relaunches with this flag when launched without it, so non-bundled
- # runs are covered too; passing it here avoids that extra spawn.)
- if [ "$OSFAM" = "win32" ]; then
- cp "$NODE_BIN" "$STAGE/node.exe"
- printf '@"%%~dp0..\\node.exe" --liftoff-only "%%~dp0..\\lib\\dist\\bin\\codegraph.js" %%*\r\n' \
- > "$STAGE/bin/codegraph.cmd"
- else
- cp "$NODE_BIN" "$STAGE/node"
- cat > "$STAGE/bin/codegraph" <<'LAUNCH'
- #!/bin/sh
- # Resolve symlinks (e.g. the ~/.local/bin/codegraph link install.sh creates) so
- # we find the real bundle dir, not the symlink's location.
- SELF="$0"
- while [ -L "$SELF" ]; do
- target="$(readlink "$SELF")"
- case "$target" in
- /*) SELF="$target" ;;
- *) SELF="$(dirname "$SELF")/$target" ;;
- esac
- done
- DIR="$(cd "$(dirname "$SELF")/.." && pwd)"
- # --liftoff-only: avoid the V8 turboshaft WASM Zone OOM (issues #293/#298).
- exec "$DIR/node" --liftoff-only "$DIR/lib/dist/bin/codegraph.js" "$@"
- LAUNCH
- chmod +x "$STAGE/bin/codegraph"
- fi
- # 5. Archive (.zip for Windows, .tar.gz otherwise).
- mkdir -p "$OUT"
- if [ "$OSFAM" = "win32" ]; then
- ARCHIVE="$OUT/codegraph-${TARGET}.zip"
- rm -f "$ARCHIVE"
- ( cd "$WORK" && zip -rqX "$ARCHIVE" "codegraph-${TARGET}" )
- else
- ARCHIVE="$OUT/codegraph-${TARGET}.tar.gz"
- # --no-xattrs: don't embed macOS xattrs that make GNU tar warn on Linux.
- tar --no-xattrs -czf "$ARCHIVE" -C "$WORK" "codegraph-${TARGET}"
- fi
- echo "[bundle] wrote ${ARCHIVE} ($(du -h "$ARCHIVE" | cut -f1))"
|