Skip to content

Commit 7ffe33e

Browse files
committed
feat(release): add Windows ARM64 and Linux musl prebuilt binary support
Add aarch64-pc-windows-msvc, x86_64-unknown-linux-musl, and aarch64-unknown-linux-musl as build targets in the release pipeline, NAPI config, and publish scripts. Add libc field to CLI platform packages for correct npm resolution on musl vs glibc systems. Add install test jobs for Windows ARM64, Linux musl x64 (Docker), and Linux musl arm64 (QEMU). Document supported platforms in the getting started guide.
1 parent dd10240 commit 7ffe33e

7 files changed

Lines changed: 256 additions & 25 deletions

File tree

.github/actions/build-upstream/action.yml

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,22 +58,48 @@ runs:
5858
pnpm --filter "@voidzero-dev/*" build
5959
pnpm --filter vite-plus build-ts
6060
61+
# Musl targets need Zig as the C/C++ cross-compiler (via cargo-zigbuild)
62+
# GNU targets use napi-cross which bundles its own cross toolchain
63+
- name: Setup Zig
64+
if: contains(inputs.target, 'musl')
65+
uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2.2.1
66+
with:
67+
version: 0.14.1
68+
69+
- name: Install cargo-zigbuild
70+
if: contains(inputs.target, 'musl')
71+
uses: taiki-e/install-action@f92912fad184299a31e22ad070a5059fd07d4f59 # v2.68.7
72+
with:
73+
tool: cargo-zigbuild
74+
75+
# Determine cross-compile flag: musl uses Zig (-x), GNU uses napi-cross
76+
- name: Determine cross-compile strategy
77+
id: cross
78+
if: contains(inputs.target, 'linux')
79+
shell: bash
80+
run: |
81+
if [[ "${{ inputs.target }}" == *"musl"* ]]; then
82+
echo "napi-flag=-x" >> $GITHUB_OUTPUT
83+
else
84+
echo "napi-flag=--use-napi-cross" >> $GITHUB_OUTPUT
85+
fi
86+
6187
# NAPI builds - only run on cache miss (slow, especially on Windows)
6288
# Must run before vite-plus TypeScript builds which depend on the bindings
6389
- name: Build NAPI bindings (x86_64-linux)
6490
shell: bash
65-
if: steps.cache-restore.outputs.cache-hit != 'true' && inputs.target == 'x86_64-unknown-linux-gnu'
91+
if: steps.cache-restore.outputs.cache-hit != 'true' && startsWith(inputs.target, 'x86_64-unknown-linux')
6692
run: |
67-
pnpm --filter=vite-plus build-native --target ${{ inputs.target }} --use-napi-cross
93+
pnpm --filter=vite-plus build-native --target ${{ inputs.target }} ${{ steps.cross.outputs.napi-flag }}
6894
env:
6995
TARGET_CC: clang
7096
DEBUG: napi:*
7197

7298
- name: Build NAPI bindings (aarch64-linux)
7399
shell: bash
74-
if: steps.cache-restore.outputs.cache-hit != 'true' && inputs.target == 'aarch64-unknown-linux-gnu'
100+
if: steps.cache-restore.outputs.cache-hit != 'true' && startsWith(inputs.target, 'aarch64-unknown-linux')
75101
run: |
76-
pnpm --filter=vite-plus build-native --target ${{ inputs.target }} --use-napi-cross
102+
pnpm --filter=vite-plus build-native --target ${{ inputs.target }} ${{ steps.cross.outputs.napi-flag }}
77103
env:
78104
TARGET_CC: clang
79105
TARGET_CFLAGS: '-D_BSD_SOURCE'
@@ -88,19 +114,19 @@ runs:
88114
DEBUG: napi:*
89115

90116
- name: Build Rust CLI binary (x86_64-linux)
91-
if: steps.cache-restore.outputs.cache-hit != 'true' && inputs.target == 'x86_64-unknown-linux-gnu'
117+
if: steps.cache-restore.outputs.cache-hit != 'true' && startsWith(inputs.target, 'x86_64-unknown-linux')
92118
shell: bash
93119
run: |
94-
pnpm exec napi build --use-napi-cross --target ${{ inputs.target }} --release -p vite_global_cli
120+
pnpm exec napi build ${{ steps.cross.outputs.napi-flag }} --target ${{ inputs.target }} --release -p vite_global_cli
95121
env:
96122
TARGET_CC: clang
97123
DEBUG: napi:*
98124

99125
- name: Build Rust CLI binary (aarch64-linux)
100-
if: steps.cache-restore.outputs.cache-hit != 'true' && inputs.target == 'aarch64-unknown-linux-gnu'
126+
if: steps.cache-restore.outputs.cache-hit != 'true' && startsWith(inputs.target, 'aarch64-unknown-linux')
101127
shell: bash
102128
run: |
103-
pnpm exec napi build --use-napi-cross --target ${{ inputs.target }} --release -p vite_global_cli
129+
pnpm exec napi build ${{ steps.cross.outputs.napi-flag }} --target ${{ inputs.target }} --release -p vite_global_cli
104130
env:
105131
TARGET_CC: clang
106132
TARGET_CFLAGS: '-D_BSD_SOURCE'

.github/workflows/release.yml

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,14 @@ jobs:
5050
os: ubuntu-latest
5151
- target: x86_64-unknown-linux-gnu
5252
os: ubuntu-latest
53+
- target: x86_64-unknown-linux-musl
54+
os: ubuntu-latest
55+
- target: aarch64-unknown-linux-musl
56+
os: ubuntu-latest
5357
- target: x86_64-pc-windows-msvc
5458
os: windows-latest
59+
- target: aarch64-pc-windows-msvc
60+
os: windows-latest
5561
steps:
5662
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
5763
- uses: ./.github/actions/clone
@@ -64,14 +70,6 @@ jobs:
6470
- name: Rustup Adds Target
6571
run: rustup target add ${{ matrix.settings.target }}
6672

67-
- name: Add musl target (x86_64)
68-
if: ${{ matrix.settings.target == 'x86_64-unknown-linux-gnu' }}
69-
run: rustup target add x86_64-unknown-linux-musl
70-
71-
- name: Add musl target (aarch64)
72-
if: ${{ matrix.settings.target == 'aarch64-unknown-linux-gnu' }}
73-
run: rustup target add aarch64-unknown-linux-musl
74-
7573
- uses: oxc-project/setup-node@fdbf0dfd334c4e6d56ceeb77d91c76339c2a0885 # v1.0.4
7674

7775
- name: Set binding version

.github/workflows/test-standalone-install.yml

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,119 @@ jobs:
178178
# cd hello && vp run build
179179
"
180180
181+
test-install-sh-musl-x64:
182+
name: Test install.sh (Linux x64 musl via Docker)
183+
runs-on: ubuntu-latest
184+
permissions:
185+
contents: read
186+
steps:
187+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
188+
189+
- name: Run install.sh in Alpine container
190+
run: |
191+
docker run --rm --platform linux/amd64 \
192+
-v "${{ github.workspace }}:/workspace" \
193+
-e VITE_PLUS_VERSION=test \
194+
alpine:3.21 sh -c "
195+
apk add --no-cache curl bash ca-certificates
196+
cat /workspace/packages/cli/install.sh | bash
197+
if [ -f ~/.profile ]; then
198+
source ~/.profile
199+
elif [ -f ~/.bashrc ]; then
200+
source ~/.bashrc
201+
else
202+
export PATH=\"\$HOME/.vite-plus/bin:\$PATH\"
203+
fi
204+
205+
vp --version
206+
vp --help
207+
vp dlx print-current-version
208+
209+
# Verify bin setup
210+
BIN_PATH=\"\$HOME/.vite-plus/bin\"
211+
if [ ! -d \"\$BIN_PATH\" ]; then
212+
echo \"Error: Bin directory not found: \$BIN_PATH\"
213+
exit 1
214+
fi
215+
for shim in node npm npx; do
216+
if [ ! -f \"\$BIN_PATH/\$shim\" ]; then
217+
echo \"Error: Shim not found: \$BIN_PATH/\$shim\"
218+
exit 1
219+
fi
220+
echo \"Found shim: \$BIN_PATH/\$shim\"
221+
done
222+
vp env doctor
223+
224+
export VITE_LOG=trace
225+
vp env run --node 24 -- node -p \"process.versions\"
226+
227+
# Verify upgrade
228+
vp upgrade --check
229+
vp upgrade 0.0.0-f74442ad.20260222-0755
230+
vp --version
231+
vp upgrade --rollback
232+
vp --version
233+
"
234+
235+
test-install-sh-musl-arm64:
236+
name: Test install.sh (Linux ARM64 musl via QEMU)
237+
runs-on: ubuntu-latest
238+
permissions:
239+
contents: read
240+
steps:
241+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
242+
243+
- name: Set up QEMU
244+
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
245+
with:
246+
platforms: arm64
247+
248+
- name: Run install.sh in ARM64 Alpine container
249+
run: |
250+
docker run --rm --platform linux/arm64 \
251+
-v "${{ github.workspace }}:/workspace" \
252+
-e VITE_PLUS_VERSION=test \
253+
alpine:3.21 sh -c "
254+
apk add --no-cache curl bash ca-certificates
255+
cat /workspace/packages/cli/install.sh | bash
256+
if [ -f ~/.profile ]; then
257+
source ~/.profile
258+
elif [ -f ~/.bashrc ]; then
259+
source ~/.bashrc
260+
else
261+
export PATH=\"\$HOME/.vite-plus/bin:\$PATH\"
262+
fi
263+
264+
vp --version
265+
vp --help
266+
vp dlx print-current-version
267+
268+
# Verify bin setup
269+
BIN_PATH=\"\$HOME/.vite-plus/bin\"
270+
if [ ! -d \"\$BIN_PATH\" ]; then
271+
echo \"Error: Bin directory not found: \$BIN_PATH\"
272+
exit 1
273+
fi
274+
for shim in node npm npx; do
275+
if [ ! -f \"\$BIN_PATH/\$shim\" ]; then
276+
echo \"Error: Shim not found: \$BIN_PATH/\$shim\"
277+
exit 1
278+
fi
279+
echo \"Found shim: \$BIN_PATH/\$shim\"
280+
done
281+
vp env doctor
282+
283+
export VITE_LOG=trace
284+
vp env run --node 24 -- node -p \"process.versions\"
285+
286+
# Verify upgrade
287+
vp upgrade --check
288+
vp upgrade 0.0.0-f74442ad.20260222-0755
289+
vp --version
290+
vp upgrade --rollback
291+
vp --version
292+
"
293+
181294
test-install-ps1-v5:
182295
name: Test install.ps1 (Windows x64, PowerShell 5.1)
183296
runs-on: windows-latest
@@ -254,6 +367,73 @@ jobs:
254367
vp upgrade --rollback
255368
vp --version
256369
370+
test-install-ps1-arm64:
371+
name: Test install.ps1 (Windows ARM64)
372+
runs-on: windows-11-arm
373+
permissions:
374+
contents: read
375+
steps:
376+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
377+
378+
- name: Run install.ps1
379+
shell: pwsh
380+
run: |
381+
& ./packages/cli/install.ps1
382+
383+
- name: Set PATH
384+
shell: bash
385+
run: |
386+
echo "$USERPROFILE\.vite-plus\bin" >> $GITHUB_PATH
387+
388+
- name: Verify installation
389+
shell: pwsh
390+
working-directory: ${{ runner.temp }}
391+
run: |
392+
Write-Host "PATH: $env:Path"
393+
vp --version
394+
vp --help
395+
vp create vite --no-interactive --no-agent -- hello --no-interactive -t vanilla
396+
cd hello
397+
vp run build
398+
vp --version
399+
400+
- name: Verify bin setup
401+
shell: pwsh
402+
run: |
403+
$binPath = "$env:USERPROFILE\.vite-plus\bin"
404+
Get-ChildItem -Force $binPath
405+
if (-not (Test-Path $binPath)) {
406+
Write-Error "Bin directory not found: $binPath"
407+
exit 1
408+
}
409+
410+
$expectedShims = @("node.cmd", "npm.cmd", "npx.cmd")
411+
foreach ($shim in $expectedShims) {
412+
$shimFile = Join-Path $binPath $shim
413+
if (-not (Test-Path $shimFile)) {
414+
Write-Error "Shim not found: $shimFile"
415+
exit 1
416+
}
417+
Write-Host "Found shim: $shimFile"
418+
}
419+
where.exe node
420+
where.exe npm
421+
where.exe npx
422+
where.exe vp
423+
424+
$env:Path = "$env:USERPROFILE\.vite-plus\bin;$env:Path"
425+
vp env doctor
426+
vp env run --node 24 -- node -p "process.versions"
427+
428+
- name: Verify upgrade
429+
shell: pwsh
430+
run: |
431+
vp upgrade --check
432+
vp upgrade 0.0.0-f74442ad.20260222-0755
433+
vp --version
434+
vp upgrade --rollback
435+
vp --version
436+
257437
test-install-ps1:
258438
name: Test install.ps1 (Windows x64)
259439
runs-on: windows-latest

crates/vite_global_cli/src/commands/upgrade/registry.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ mod tests {
9999
"darwin-x64",
100100
"linux-arm64-gnu",
101101
"linux-x64-gnu",
102+
"linux-x64-musl",
103+
"linux-arm64-musl",
102104
"win32-arm64-msvc",
103105
"win32-x64-msvc",
104106
];
@@ -123,10 +125,6 @@ mod tests {
123125
for suffix in &detection_suffixes {
124126
let package_name =
125127
format!("{PLATFORM_PACKAGE_SCOPE}/{CLI_PACKAGE_NAME_PREFIX}-{suffix}");
126-
// musl variants are not published, so skip them
127-
if suffix.contains("musl") {
128-
continue;
129-
}
130128
assert!(
131129
published_packages.contains(&package_name),
132130
"Platform suffix '{suffix}' produces CLI package name '{package_name}' \

docs/vite/guide/index.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,25 @@ For Windows:
3232
irm https://staging.viteplus.dev/install.ps1 | iex
3333
```
3434

35+
::: details Supported platforms
36+
37+
Prebuilt binaries are distributed for the following platforms (grouped by [Node.js v24 platform support tier](https://github.com/nodejs/node/blob/v24.x/BUILDING.md#platform-list)):
38+
39+
- Tier 1
40+
- Linux x64 glibc (`x86_64-unknown-linux-gnu`)
41+
- Linux arm64 glibc (`aarch64-unknown-linux-gnu`)
42+
- Windows x64 (`x86_64-pc-windows-msvc`)
43+
- macOS x64 (`x86_64-apple-darwin`)
44+
- macOS arm64 (`aarch64-apple-darwin`)
45+
- Tier 2
46+
- Windows arm64 (`aarch64-pc-windows-msvc`)
47+
- Experimental
48+
- Linux x64 musl (`x86_64-unknown-linux-musl`)
49+
- Other
50+
- Linux arm64 musl (`aarch64-unknown-linux-musl`)
51+
52+
:::
53+
3554
## Node.js Version Manager
3655

3756
Vite+ includes a built-in Node.js version manager. During installation, you can opt-in to let Vite+ manage your Node.js versions.

packages/cli/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,10 @@
339339
"x86_64-apple-darwin",
340340
"aarch64-unknown-linux-gnu",
341341
"x86_64-unknown-linux-gnu",
342-
"x86_64-pc-windows-msvc"
342+
"x86_64-unknown-linux-musl",
343+
"aarch64-unknown-linux-musl",
344+
"x86_64-pc-windows-msvc",
345+
"aarch64-pc-windows-msvc"
343346
]
344347
},
345348
"engines": {

0 commit comments

Comments
 (0)