Node.js で CLI ツールを作る手順 (pnpm + TypeScript + tsup)
Node.jsでの開発フローを勉強するためにCLIツールを作って、ローカル利用するまでの手順をまとめる。 npm publishは行わず、ローカルでパッケージ化してインストールする前提です。
1. 事前準備
Node.js は LTS 版を使う前提にします。
# 例: asdfを使っている場合
asdf install nodejs 22.14.0
asdf global nodejs 22.14.0
# パッケージマネージャーはpnpmを使う
corepack enable
corepack prepare pnpm@latest --activate
2. プロジェクト作成
mkdir my-cli-tool
cd my-cli-tool
pnpm init
最初に package.json の name と license は確定させておくとよい
3. 必須依存の追加
pnpm add -D typescript tsup @types/node
- typescript: 型付きで開発する
- tsup: CLI 実行ファイルをビルドする
4. ディレクトリ構成
my-cli-tool/
├── package.json
├── tsconfig.json
├── tsup.config.ts
└── src/
└── cli.ts
5. TypeScript 設定
tsconfig.json の最小例:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"sourceMap": true,
"outDir": "dist",
"skipLibCheck": true
},
"include": ["src"]
}
6. ビルド設定 (tsup)
tsup.config.ts 例:
import { defineConfig } from "tsup";
export default defineConfig({
entry: ["src/cli.ts"],
format: ["esm"],
dts: false,
platform: "node",
target: "node22",
banner: {
js: "#!/usr/bin/env node",
},
outExtension() {
return { js: ".js" };
},
sourcemap: true,
clean: true,
});
7. package.json の scripts / bin
package.json の重要項目例:
{
"name": "my-cli-tool",
"version": "1.0.0",
"type": "module",
"bin": {
"mycli": "./dist/cli.js"
},
"files": ["dist"],
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"cli": "node ./dist/cli.js",
"typecheck": "tsc --noEmit",
"prepack": "pnpm build"
}
}
ポイント:
- bin で CLI コマンド名と実行ファイルを紐付ける
- files で配布対象を dist に限定する
- prepack で pack 前に自動ビルドする
8. CLI 実装
src/cli.ts 例:
type Command = "greet" | "help";
function parseCommand(arg?: string): Command {
if (arg === "greet") return "greet";
return "help";
}
function run(): void {
const command = parseCommand(process.argv[2]);
if (command === "greet") {
const name = process.argv[3] ?? "world";
console.log(`hello, ${name}`);
return;
}
console.log("Usage:");
console.log(" mycli greet <name>");
}
run();
9. パッケージ化の前に CLI を実行して確認
まずビルドして、生成物を直接実行します。
pnpm build
pnpm cli greet ken
watch で開発しながら確認する場合:
pnpm dev
# 別ターミナル
node dist/cli.js greet ken
型チェックも通しておくと安全です。
pnpm typecheck
10. パッケージ化前チェック
# 配布される内容を確認
pnpm pack --dry-run
ここで意図しないファイル(テストデータ、秘密情報など)が入っていないか確認します。
11-1. パッケージ作成とローカルインストール
配布用 tarball を作成します。
# dist を最新化
pnpm build
# .tgz を作成
pnpm pack
すると my-cli-tool-1.0.0.tgz のようなファイルが生成されます。 利用側プロジェクトでローカルインストールします。
# 利用側プロジェクトへ移動
cd ../my-app
# 生成した tarball を指定してインストール
pnpm add ../my-cli-tool/my-cli-tool-1.0.0.tgz
インストール後は次のように実行できます。
pnpm exec mycli greet ken
開発中に再パッケージして入れ直す場合は、次を繰り返します。
- パッケージ側で pnpm build && pnpm pack
- 利用側で pnpm add ../my-cli-tool/my-cli-tool-x.y.z.tgz
11-2. 開発モードでのインストール
頻繁に試す場合にはインストールをせず file: 依存を使う方法もあります。
pnpm add file:../my-cli-tool
この方法は手軽ですが、distの更新を手動で行う必要があります。