mocks というモック用の API を起動できる CLI ツールを Rust で開発して crates.io で公開しています。
Rust で開発してるので、crates.io で公開・配布することはハードルが低くのですが、Rust の環境がないといけないのがネックでした。
Homebrew でもインストールする方法を整備していますが、今回は Node.js 開発者にとって馴染みのある npm エコシステムを通じて公開・配布できるようにしてみました!
Rust 製 CLI ツールを npm publish する
What is mocks? Why publish it on npm?
mocks については、以下の記事で紹介しています。興味がある方はぜひ見ていってください!

なお、npm で公開された @mocks-rs/mocks
は https://www.npmjs.com/package/@mocks-rs/mocks で確認できます。
モック用の API を起動するというツールの特性上、React などのフロントエンド開発時に使用するというユースケースも想定しているので npm で公開・配布できることはメリットなのかなと感じています。
Rust 製 CLI ツールを npm で公開・配布している例としては Biome CLI が好例かと思います。
npm で公開・配布する
今回の実装は biomejs/biome を参考にしました。
- マルチプラットフォーム対応
-
各プラットフォーム向けにビルドしたバイナリを個別の npm パッケージとして作成しました。
- メインパッケージ
-
メインパッケージである @mocks-rs/mocks がプラットフォーム検出してバイナリを実行する仕様を採用しました。
- Github Actions で自動化
-
GitHub Actions でビルドから
npm publish
による公開まで自動化しました。
ソースコード一式を Github で公開しているので、合わせて確認してみてください!
ディレクトリ構成
mocks プロジェクトのディレクトリ構造です。(バージョン 1.0.4 時点)
https://github.com/mocks-rs/mocks/tree/1.0.4
mocks
├── src # Rust のソースコード
├── packages
│ └── @mocks-rs
│ ├── mocks # メインパッケージ
│ ├── mocks-darwin-arm64 # 各プラットフォーム向けパッケージ
│ ├── mocks-darwin-x64
│ ├── mocks-linux-arm64
│ ├── mocks-linux-x64
│ ├── mocks-win32-arm64
│ └── mocks-win32-x64
└── scripts # バージョンチェックのスクリプトなどを配置
メインパッケージ:@mocks-rs/mocks
npm で公開するための情報を定義する package.json
を作成します。
optionalDependencies
を使用することで、ユーザーの環境に応じて必要なプラットフォーム向けパッケージのみがインストールされます。
{
"name": "@mocks-rs/mocks",
"version": "1.0.4",
"description": "Mock REST APIs from JSON with zero coding within seconds.",
"bin": {
"mocks": "bin/mocks"
},
"optionalDependencies": {
"@mocks-rs/mocks-linux-x64": "1.0.4",
"@mocks-rs/mocks-linux-arm64": "1.0.4",
"@mocks-rs/mocks-darwin-x64": "1.0.4",
"@mocks-rs/mocks-darwin-arm64": "1.0.4",
"@mocks-rs/mocks-win32-x64": "1.0.4",
"@mocks-rs/mocks-win32-arm64": "1.0.4"
}
}
あとは、インストール手順や使い方を記載した README.md を作成しておきましょう。
プラットフォーム別パッケージ
各プラットフォーム向けパッケージ(例:@mocks-rs/mocks-linux-x64
)の package.json
は以下のようになっています。
os
と cpu
フィールドにより、npm が適切なプラットフォーム判定を行ってくれます。
{
"name": "@mocks-rs/mocks-linux-x64",
"version": "1.0.4",
"description": "mocks Linux x64 binary",
"os": ["linux"],
"cpu": ["x64"],
"files": ["mocks"]
}
メインパッケージのバイナリ実行の実装
メインパッケージの bin/mocks
ファイルは、プラットフォーム検出とバイナリ実行を担当するコードです。
#!/usr/bin/env node
// Node.jsプロセスから必要な情報を取得
// platform: 実行中のOSを示す('win32', 'darwin', 'linux'など)
// arch: CPUアーキテクチャを示す('x64', 'arm64'など)
// env: 環境変数オブジェクト
const { platform, arch, env } = process;
// 子プロセスを同期的に実行するためのspawnSync関数をインポートする
const { spawnSync } = require("child_process");
// プラットフォーム別・アーキテクチャ別のバイナリパスマッピング
const PLATFORMS = {
// Windows用のバイナリパス(.exe拡張子付き)
win32: {
x64: "@mocks-rs/mocks-win32-x64/mocks.exe", // Windows 64bit Intel/AMD
arm64: "@mocks-rs/mocks-win32-arm64/mocks.exe", // Windows 64bit ARM
},
// macOS用のバイナリパス
darwin: {
x64: "@mocks-rs/mocks-darwin-x64/mocks", // macOS 64bit Intel
arm64: "@mocks-rs/mocks-darwin-arm64/mocks", // macOS 64bit ARM (Apple Silicon)
},
// Linux用のバイナリパス
linux: {
x64: "@mocks-rs/mocks-linux-x64/mocks", // Linux 64bit Intel/AMD
arm64: "@mocks-rs/mocks-linux-arm64/mocks", // Linux 64bit ARM
},
};
// 現在のプラットフォームとアーキテクチャに適したバイナリパスを取得する関数
function getBinaryPath() {
// 環境変数による上書きをサポート
if (env.MOCKS_BINARY) {
return env.MOCKS_BINARY;
}
// 現在のプラットフォーム(OS)に対応するバイナリマッピングを取得
const platformBinaries = PLATFORMS[platform];
if (!platformBinaries) {
// サポートされていないプラットフォームの場合はnullを返す
return null;
}
return platformBinaries[arch];
}
function main() {
// 現在の環境に適したバイナリパスを取得
const binaryPath = getBinaryPath();
// サポートされていないプラットフォーム/アーキテクチャの場合のエラーハンドリング
if (!binaryPath) {
console.error(`Unsupported platform: ${platform}-${arch}`);
process.exit(1); // 異常終了コード1で終了
}
// require.resolve()を使用してバイナリの実際のファイルパスを解決
let resolvedBinaryPath;
try {
// NPMパッケージ内のバイナリファイルの絶対パスを取得
resolvedBinaryPath = require.resolve(binaryPath);
} catch (error) {
// バイナリが見つからない・NPMパッケージがインストールされていない場合のエラーハンドリング
console.error(`Failed to find binary for ${platform}-${arch}`);
console.error('Try running: npm install --force');
process.exit(1);
}
// 子プロセスとしてバイナリを実行
const result = spawnSync(resolvedBinaryPath, process.argv.slice(2), {
stdio: "inherit", // 標準入出力を親プロセスから継承(ユーザーに直接表示)
windowsHide: false, // Windows上でコンソールウィンドウを隠さない
});
// 子プロセスの終了コードで親プロセスも終了
process.exit(result.status || 0);
}
main();
公開ワークフロー
Github Actions で npm publis
h するワークフローを定義していきます。
Rust セットアップは 再利用可能な Rust セットアップアクションを作成する で紹介しているので、参考にしてみてください!
# RustのCLIツールをnpmパッケージとして公開するワークフロー
name: Publish to npm
on:
workflow_call: # 他のワークフローから呼び出し可能
inputs:
version: # 公開するバージョン(例:1.0.0)
description: 'Version to publish (e.g., 1.0.0)'
required: true
type: string
dry_run: # 実際に公開せずテスト実行
description: 'Dry run (do not actually publish)'
required: false
default: false
type: boolean
jobs:
build-and-publish:
# 複数プラットフォーム対応する
strategy:
fail-fast: false
matrix:
include:
# Linux x64(musl静的リンク)
- target: x86_64-unknown-linux-musl
os: ubuntu-latest
platform: linux-x64
# Linux ARM64(musl静的リンク)
- target: aarch64-unknown-linux-musl
os: ubuntu-latest
platform: linux-arm64
# macOS x64
- target: x86_64-apple-darwin
os: macos-latest
platform: darwin-x64
# macOS ARM64(Apple Silicon)
- target: aarch64-apple-darwin
os: macos-latest
platform: darwin-arm64
# Windows x64(GNU toolchain)
- target: x86_64-pc-windows-gnu
os: ubuntu-latest
platform: win32-x64
# Windows ARM64(MSVC toolchain)
- target: aarch64-pc-windows-msvc
os: windows-latest
platform: win32-arm64
steps:
# Rust セットアップ
- name: Setup Rust
uses: ./.github/actions/setup-rust
with:
targets: ${{ matrix.target }}
# musl(静的リンク)用ツールチェーンのインストール
- name: Install musl toolchain
if: contains(matrix.target, 'musl')
run: |
sudo apt-get install -y musl-tools
# ARM64クロスコンパイル用のGCCツールチェーン
- name: Install Windows cross-compilation tools
if: matrix.target == 'x86_64-pc-windows-gnu'
run: |
sudo apt-get install -y gcc-mingw-w64-x86-64
# セキュリティ監査(Linux x64でのみ実行)
- name: Security audit
if: matrix.target == 'x86_64-unknown-linux-musl'
run: cargo audit
# Rustバイナリのリリースビルド
- name: Build binary
timeout-minutes: 30
run: cargo build --release --target ${{ matrix.target }}
env:
# ARM64クロスコンパイル用リンカー設定
CC_aarch64_unknown_linux_musl: aarch64-linux-gnu-gcc
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER: aarch64-linux-gnu-gcc
# プラットフォーム固有のnpmパッケージ準備
- name: Prepare platform package
shell: bash
run: |
mkdir -p dist/${{ matrix.platform }}
# 既存のパッケージテンプレートをコピー
cp -r packages/@mocks-rs/mocks-${{ matrix.platform }}/* dist/${{ matrix.platform }}/
# ビルドしたバイナリをパッケージにコピー
if [ "${{ matrix.platform }}" = "win32-x64" ] || [ "${{ matrix.platform }}" = "win32-arm64" ]; then
cp target/${{ matrix.target }}/release/mocks.exe dist/${{ matrix.platform }}/
else
cp target/${{ matrix.target }}/release/mocks dist/${{ matrix.platform }}/
fi
# npmレジストリへの公開
- name: Publish platform package
if: github.event.inputs.dry_run == 'false' || inputs.dry_run == false
shell: bash
run: |
cd dist/${{ matrix.platform }}
npm publish --access public # 公開パッケージとして公開
# メインパッケージの公開(全プラットフォームビルド完了後)
publish-main:
needs: build-and-publish # プラットフォーム固有パッケージの公開完了を待機
runs-on: ubuntu-latest
steps:
# メインパッケージ(プラットフォーム固有パッケージの依存関係管理)の公開
- name: Publish main package
if: github.event.inputs.dry_run == 'false' || inputs.dry_run == false
shell: bash
run: |
cd packages/@mocks-rs/mocks
npm publish --access public
mocks のワークフローでは release.yml でテストやバージョンチェックを行った後に、バージョン変更があれば publish-to-npm.yml を呼び出しています。

Node.js 環境でのインストール
npm で公開・配布したことで、以下の方法でインストールできるようになりました。
npm install -g @mocks-rs/mocks
グローバルにインストールしたくない場合は、package.json
に mocks
コマンドを定義して実行できます。
npm install @mocks-rs/mocks
{
"scripts": {
"mocks:init": "mocks init storage.json",
"mocks:run": "mocks run storage.json"
}
}
また、npx 経由でも実行できるようになります。
npx @mocks-rs/mocks init storage.json
npx @mocks-rs/mocks run storage.json
まとめ
Rust 製 CLI ツールを npm で公開・配布することで、Node.js 環境での利用がしやすくなります。
ユーザーの拡大という意味では、npm エコシステムの領域に進出するメリットは非常に大きいと思います!
コメント