Skip to content

feat(binding-builder): add binding-builder cli #10876

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ runs:
shell: bash
run: |
cd ./crates/node_binding
pnpm install --ignore-workspace --no-lockfile
Copy link
Contributor Author

@h-a-n-a h-a-n-a Jul 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bad part is we have to link binding-builder-cli to crates/node_binding. This requires the binding to fallback to workspace install instead of plain package install. cc @stormslowly

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove --ignore-workspace will install all workspace depenceies and slow down installation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could probably install the binding builder cli as a dependency (not from the current workspace) after the first release, then we can revert the workflow back.

pnpm install --frozen-lockfile
cd ../../

- name: Save pnpm cache
Expand Down
2 changes: 2 additions & 0 deletions biome.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"ignore": [
"packages/rspack/src/config/schema.check.js",
"packages/**/etc/**/*",
"packages/binding-builder-cli/scripts/banner.d.ts",
"crates/**/*",
"tests/**/*",
"packages/rspack-test-tools/template/**/*",
Expand Down Expand Up @@ -63,6 +64,7 @@
"packages/rspack-test-tools/template",
"packages/rspack-test-tools/src/helper/legacy/**/*",
"packages/rspack/module.d.ts",
"packages/binding-builder-cli/scripts/banner.d.ts",
// --- ignore runtime code in browser
"packages/rspack/hot",
"packages/rspack/src/runtime/moduleFederationDefaultRuntime.js"
Expand Down
6 changes: 4 additions & 2 deletions crates/node_binding/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ plugin = ["rspack_binding_api/plugin"]
sftrace-setup = ["rspack_binding_api/sftrace-setup"]

[package.metadata.cargo-shear]
# Adding napi-derive as a dependency to workaround an issue where `dts` will no longer work without it.
ignored = ["napi-derive"]
ignored = [
# Add napi-derive as a dependency to workaround an issue where `dts` will no longer work without it.
"napi-derive",
]

[dependencies]
rspack_binding_api = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion crates/node_binding/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"bugs": "https://github.com/web-infra-dev/rspack/issues",
"repository": "web-infra-dev/rspack",
"devDependencies": {
"@napi-rs/cli": "3.0.0-alpha.88",
"@rspack/binding-builder-cli": "workspace:*",
"@napi-rs/wasm-runtime": "^0.2.11",
"emnapi": "^1.4.3",
"typescript": "^5.8.3",
Expand Down
47 changes: 6 additions & 41 deletions crates/node_binding/scripts/build.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const path = require("path");
const { readFileSync, writeFileSync } = require("fs");
const { values, positionals } = require("util").parseArgs({
args: process.argv.slice(2),
options: {
Expand All @@ -15,8 +13,6 @@ const { spawn } = require("child_process");

const CARGO_SAFELY_EXIT_CODE = 0;

let watch = process.argv.includes("--watch");

build().then((value) => {
// Regarding cargo's non-zero exit code as an error.
if (value !== CARGO_SAFELY_EXIT_CODE) {
Expand All @@ -30,77 +26,46 @@ build().then((value) => {
async function build() {
return new Promise((resolve, reject) => {
let args = [
"build",
"--platform",
"--dts",
"binding.d.ts",
"--no-js",
// "--no-const-enum",
"--no-dts-header",
"--pipe",
`"node ${path.resolve(__dirname, "dts-header.js")}"`
"--no-dts-cache",
];
let features = [];
let envs = { ...process.env };

if (values.profile) {
args.push("--profile", values.profile);
}
if (watch) {
args.push("--watch");
}
if (process.env.USE_ZIG) {
args.push("--cross-compile");
}
if (process.env.RUST_TARGET) {
args.push("--target", process.env.RUST_TARGET);
}
if (!process.env.DISABLE_PLUGIN) {
args.push("--no-default-features");
features.push("plugin");
}
args.push("--no-dts-cache");
if (values.profile === "release-debug" &&
(!process.env.RUST_TARGET || process.env.RUST_TARGET.includes("linux") || process.env.RUST_TARGET.includes("darwin"))
) {
features.push("sftrace-setup");
envs.RUSTFLAGS = "-Zinstrument-xray=always";
}

if (features.length) {
args.push("--features " + features.join(","));
args.push("--features", features.join(","));
}

if (positionals.length > 0) {
// napi need `--` to separate options and positional arguments.
args.push("--");
args.push(...positionals);
}

console.log(`Run command: napi ${args.join(" ")}`);
console.log(`Running command: rspack-builder ${args.join(" ")}`);

let cp = spawn("napi", args, {
let cp = spawn("rspack-builder", args, {
stdio: "inherit",
shell: true,
env: envs,
});

cp.on("error", reject);
cp.on("exit", (code) => {
if (code === CARGO_SAFELY_EXIT_CODE) {

// Fix an issue where napi cli does not generate `string_enum` with `enum`s.
let dts = path.resolve(__dirname, "../binding.d.ts");
writeFileSync(dts,
readFileSync(dts, "utf8")
.replaceAll("const enum", "enum")
// Remove the NormalModule type declaration generated by N-API.
// We manually declare the NormalModule type in banner.d.ts
// This allows users to extend NormalModule with static methods through type augmentation.
.replaceAll(/export\s+declare\s+class\s+NormalModule\s*\{([\s\S]*?)\}\s*(?=\n\s*(?:export|declare|class|$))/g, "")
);

}
resolve(code);
});
cp.on("exit", resolve);
});
}
12 changes: 6 additions & 6 deletions crates/rspack_binding_builder_testing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@
"binding.d.ts"
],
"scripts": {
"build:dev": "node scripts/build.js",
"build:debug": "node scripts/build.js --profile release-debug",
"build:ci": "node scripts/build.js --profile ci",
"build:profiling": "node scripts/build.js --profile profiling",
"build:release": "node scripts/build.js --profile release"
"build:dev": "rspack-builder",
"build:debug": "rspack-builder --profile release-debug",
"build:ci": "rspack-builder --profile ci",
"build:profiling": "rspack-builder --profile profiling",
"build:release": "rspack-builder --profile release"
},
"homepage": "https://rspack.rs",
"bugs": "https://github.com/web-infra-dev/rspack/issues",
"repository": "web-infra-dev/rspack",
"devDependencies": {
"@napi-rs/cli": "3.0.0-alpha.88",
"@rspack/binding-builder-cli": "workspace:*",
"@napi-rs/wasm-runtime": "^0.2.11",
"emnapi": "^1.4.3",
"typescript": "^5.8.3",
Expand Down
63 changes: 0 additions & 63 deletions crates/rspack_binding_builder_testing/scripts/build.js

This file was deleted.

22 changes: 22 additions & 0 deletions packages/binding-builder-cli/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
MIT License

Copyright (c) 2022-present Bytedance, Inc. and its affiliates.


Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
if (positionals.length > 0) {
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
112 changes: 112 additions & 0 deletions packages/binding-builder-cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<picture>
<img alt="Rspack Banner" src="https://assets.rspack.rs/rspack/rspack-banner.png">
</picture>

# @rspack/binding-builder-cli

Binding builder cli for rspack custom binding users.

## Rationale

This package is designed to provide a command-line interface for building custom bindings for rspack.

Rspack internally performs post-processing modifications on the generated TypeScript definition (`.d.ts`) files from NAPI-RS bindings. The `@rspack/binding-builder-cli` synchronizes these modifications, ensuring that the generated `.d.ts` files are complete and provide access to all type information available in `@rspack/binding`.

## Installation

```bash
# Install as a dependency
npm install @rspack/binding-builder-cli
```

## Usage

### Basic Usage

```bash
# Basic build
rspack-builder

# Release build
rspack-builder --release

# Build with specific profile
rspack-builder --profile release-debug

# Watch mode for development
rspack-builder --watch
```

### Advanced Options

#### Build Target and Paths

```bash
# Specify build target
rspack-builder --target x86_64-unknown-linux-musl

# Set working directory
rspack-builder --cwd /path/to/project

# Custom Cargo.toml path
rspack-builder --manifest-path /path/to/Cargo.toml

# Custom package.json path
rspack-builder --package-json-path /path/to/package.json
```

#### TypeScript Definition Options

```bash
# Custom .d.ts output path
rspack-builder --dts custom-binding.d.ts

# Custom header for .d.ts file
rspack-builder --dts-header /path/to/header.d.ts

# Disable default .d.ts header
rspack-builder --no-dts-header

# Disable .d.ts cache
rspack-builder --no-dts-cache
```

#### Feature Management

```bash
# Enable specific features
rspack-builder --features plugin,serde

# Enable all features
rspack-builder --all-features

# Disable default features
rspack-builder --no-default-features

# Combine options
rspack-builder --no-default-features --features plugin
```

#### Platform and Output Options

```bash
# Enable platform-specific naming
rspack-builder --platform

# Disable JS binding generation
rspack-builder --no-js

# Generate ESM format
rspack-builder --esm

# Strip binary for minimum size
rspack-builder --strip
```

### Help

View all available options:

```bash
rspack-builder --help
```
2 changes: 2 additions & 0 deletions packages/binding-builder-cli/bin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
require("./scripts/build");
Loading
Loading