Rspack uses npm's optional dependencies feature combined with platform filtering to ensure users only download the binary for their specific OS and architecture.
The main @rspack/binding package (crates/node_binding/package.json) declares all platform-specific packages as optionalDependencies:
"optionalDependencies": {
"@rspack/binding-darwin-arm64": "workspace:*",
"@rspack/binding-darwin-x64": "workspace:*",
"@rspack/binding-linux-x64-gnu": "workspace:*",
"@rspack/binding-linux-x64-musl": "workspace:*",
"@rspack/binding-win32-x64-msvc": "workspace:*",
// ... etc
}Each platform package (in /npm/**/package.json) declares os, cpu, and libc constraints:
// @rspack/binding-darwin-arm64
"publishConfig": {
"os": ["darwin"],
"cpu": ["arm64"]
}
// @rspack/binding-linux-x64-gnu
"publishConfig": {
"os": ["linux"],
"cpu": ["x64"],
"libc": ["glibc"]
}
// @rspack/binding-linux-x64-musl
"publishConfig": {
"os": ["linux"],
"cpu": ["x64"],
"libc": ["musl"]
}npm automatically skips optional dependencies that don't match the current platform's os/cpu/libc.
At runtime, binding.js uses a fallback chain to load the correct binary:
// 1. First tries local .node file (for dev builds)
require('./rspack.darwin-arm64.node')
// 2. Falls back to npm package
require('@rspack/binding-darwin-arm64')
// 3. Falls back to WASI if native fails
require('@rspack/binding-wasm32-wasi')The code detects:
- Platform:
process.platform(darwin, linux, win32, freebsd, etc.) - Architecture:
process.arch(x64, arm64, ia32, etc.) - Libc: Custom
isMusl()function that checks/usr/bin/ldd, process reports, or runsldd --version
npm install @rspack/core
└── installs @rspack/binding (with optionalDependencies)
└── npm checks os/cpu/libc constraints
└── only downloads matching platform package
e.g., @rspack/binding-darwin-arm64 on M1 Mac
At runtime:
require('@rspack/binding')
└── binding.js detects platform
└── requires @rspack/binding-darwin-arm64
└── loads rspack.darwin-arm64.node
Based on the packages in /npm/:
| Package | OS | CPU | Libc |
|---|---|---|---|
@rspack/binding-darwin-arm64 |
macOS | ARM64 (Apple Silicon) | - |
@rspack/binding-darwin-x64 |
macOS | x64 (Intel) | - |
@rspack/binding-linux-x64-gnu |
Linux | x64 | glibc |
@rspack/binding-linux-x64-musl |
Linux | x64 | musl (Alpine) |
@rspack/binding-linux-arm64-gnu |
Linux | ARM64 | glibc |
@rspack/binding-linux-arm64-musl |
Linux | ARM64 | musl (Alpine) |
@rspack/binding-win32-x64-msvc |
Windows | x64 | - |
@rspack/binding-win32-arm64-msvc |
Windows | ARM64 | - |
@rspack/binding-win32-ia32-msvc |
Windows | x86 (32-bit) | - |
@rspack/binding-wasm32-wasi |
Any | Any | - (WASI fallback) |
- This is a standard pattern used by many Rust+Node.js projects (esbuild, swc, lightningcss, etc.)
- The mechanism is generated and managed by NAPI-RS
- The WASI package serves as a universal fallback for unsupported platforms