Skip to content
blog.kenichikat.me
Go back

Node.js CLIツール開発メモ

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

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"
  }
}

ポイント:

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

開発中に再パッケージして入れ直す場合は、次を繰り返します。

  1. パッケージ側で pnpm build && pnpm pack
  2. 利用側で pnpm add ../my-cli-tool/my-cli-tool-x.y.z.tgz

11-2. 開発モードでのインストール

頻繁に試す場合にはインストールをせず file: 依存を使う方法もあります。

pnpm add file:../my-cli-tool

この方法は手軽ですが、distの更新を手動で行う必要があります。


Share this post on:

Previous Post
asdf環境でpnpmのグローバルインストール先を分離する
Next Post
過去日付でコミットしてgithubの草を生やした話