Skip to content

Commit 500d14c

Browse files
rubnogueiraclaude
andcommitted
feat: ship native binaries via GitHub Releases
Replace the source-compile-on-install flow (which lost binaries through pnpm's side-effects cache) with the prebuild + prebuild-install pattern. - GitHub Actions matrix builds prebuilt .tar.gz per (platform, arch, libc, ABI) for Node 24.15.0 and 26.1.0 across darwin (x64, arm64), linux (x64, arm64 each with glibc + musl) and win32 (x64) - On a tagged push, the workflow attaches every variant to a GitHub Release via softprops/action-gh-release@v2 - Consumers install with "node-expat": "github:PruvoNet/node-expat#v2.4.2"; prebuild-install reads binary.host/remote_path from package.json and downloads the matching asset at install time, falling back to node-gyp rebuild only if no matching prebuild exists - Drop the custom scripts/install.js (prebuild-install supersedes it) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 2ffcf20 commit 500d14c

5 files changed

Lines changed: 5720 additions & 2090 deletions

File tree

.github/workflows/prebuild.yml

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
name: prebuild
2+
3+
on:
4+
push:
5+
branches: [master, main, build-release]
6+
tags: ['v*']
7+
pull_request:
8+
workflow_dispatch:
9+
10+
# Least-privilege default: matrix jobs only need to read the repo to clone.
11+
# The `release` job overrides this below with `contents: write` for upload.
12+
permissions:
13+
contents: read
14+
15+
# Node versions to produce prebuilds for. One .tar.gz per ABI per
16+
# (platform, arch, libc) combination is produced. On consumer install,
17+
# prebuild-install downloads only the asset matching the consumer's runtime.
18+
env:
19+
NODE_TARGETS: "24.15.0 26.1.0"
20+
21+
jobs:
22+
prebuild:
23+
name: ${{ matrix.id }}
24+
runs-on: ${{ matrix.runner }}
25+
strategy:
26+
fail-fast: false
27+
matrix:
28+
include:
29+
- id: darwin-x64
30+
runner: macos-13
31+
- id: darwin-arm64
32+
runner: macos-14
33+
- id: linux-x64-glibc
34+
runner: ubuntu-latest
35+
- id: linux-x64-musl
36+
runner: ubuntu-latest
37+
container: node:24-alpine
38+
- id: linux-arm64-glibc
39+
runner: ubuntu-24.04-arm
40+
- id: linux-arm64-musl
41+
runner: ubuntu-24.04-arm
42+
container: node:24-alpine
43+
- id: win32-x64
44+
runner: windows-latest
45+
46+
container: ${{ matrix.container }}
47+
48+
steps:
49+
- name: Install Alpine build deps
50+
if: matrix.container == 'node:24-alpine'
51+
run: apk add --no-cache bash python3 make g++ git tar
52+
53+
- uses: actions/checkout@v5
54+
55+
- name: Set up Node (non-container runners)
56+
if: matrix.container == ''
57+
uses: actions/setup-node@v5
58+
with:
59+
node-version: '24'
60+
61+
- name: Install npm deps (no scripts so install hook can't fire)
62+
run: npm ci --ignore-scripts
63+
64+
- name: Build prebuilds for all target ABIs
65+
shell: bash
66+
run: |
67+
set -euo pipefail
68+
args=""
69+
for v in $NODE_TARGETS; do
70+
args="$args -t $v"
71+
done
72+
# --strip removes debug symbols. --tag-libc tags linux assets with
73+
# glibc/musl so prebuild-install can request the right one on the
74+
# consumer side.
75+
npx prebuild $args --strip --tag-libc
76+
77+
- name: Verify each tarball contains a .node binary
78+
shell: bash
79+
run: |
80+
set -euo pipefail
81+
ls -la prebuilds/
82+
shopt -s nullglob
83+
tarballs=(prebuilds/*.tar.gz)
84+
if [ ${#tarballs[@]} -eq 0 ]; then
85+
echo "ERROR: no prebuilds produced" >&2
86+
exit 1
87+
fi
88+
for f in "${tarballs[@]}"; do
89+
echo "--- $f ---"
90+
tar -tzf "$f"
91+
tar -tzf "$f" | grep -q '\.node$' || { echo "ERROR: no .node file in $f" >&2; exit 1; }
92+
done
93+
94+
- uses: actions/upload-artifact@v4
95+
with:
96+
name: prebuilds-${{ matrix.id }}
97+
path: prebuilds/*.tar.gz
98+
if-no-files-found: error
99+
retention-days: 30
100+
101+
release:
102+
name: attach prebuilds to GitHub Release
103+
needs: prebuild
104+
if: startsWith(github.ref, 'refs/tags/v')
105+
runs-on: ubuntu-latest
106+
permissions:
107+
contents: write
108+
steps:
109+
- uses: actions/checkout@v5
110+
111+
- name: Download all prebuild artifacts
112+
uses: actions/download-artifact@v4
113+
with:
114+
pattern: prebuilds-*
115+
path: artifacts
116+
merge-multiple: true
117+
118+
- name: List downloaded assets
119+
run: ls -la artifacts/
120+
121+
- name: Create / update Release and upload assets
122+
uses: softprops/action-gh-release@v2
123+
with:
124+
# Auto-uses the tag from github.ref. Idempotent: re-runs on the same
125+
# tag will update the existing release and overwrite asset names
126+
# that collide.
127+
files: artifacts/*.tar.gz
128+
generate_release_notes: true
129+
fail_on_unmatched_files: true

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
build/
22
node_modules/
3+
prebuilds/
34

45
!.editorconfig
56
!.gitignore

0 commit comments

Comments
 (0)