9
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Node.jsでCLIツールを作るなら「citty」がオススメ!

Last updated at Posted at 2025-02-21

Node.jsでCLIツールを作ろうとすると、どのライブラリを選べばいいか迷うことはありませんか? 本稿では、シンプルで使いやすい「citty」というライブラリをご紹介します。

cittyには次のような魅力的な特徴があります:

  • TypeScriptによる型安全な引数(args)の定義
  • 直感的なサブコマンドの作り方
  • 美しいヘルプ表示

僕自身、cittyを使ってCLIツールを作ってみて、その使いやすさに感動しました。本稿では、cittyの基本的な使い方から実践的な実装方法まで、順を追って解説していきます。

cittyのインストール

まずは、新しいプロジェクトを作成し、cittyをインストールしましょう。

# プロジェクトの作成
mkdir my-cli && cd my-cli
npm init -y

# package.jsonの設定
# "type": "module" を追加する(ESモジュールとして実行するため)

# cittyのインストール
npm install citty

最もシンプルなCLIの作成

cittyを使った最も基本的なCLIを作ってみましょう。以下のコードをindex.tsに保存します:

index.ts
import { defineCommand, runMain } from "citty";

const main = defineCommand({
  meta: {
    name: "my-cli",
    description: "My first CLI using citty",
  },
  run() {
    console.log("Hello from my CLI!");
  },
});

runMain(main);

このコードについて説明しましょう:

  • defineCommandで新しいコマンドを定義
  • metaオブジェクトでコマンドの基本情報を設定
  • run関数に実行時の処理を記述
  • runMainでコマンドを実行

実行してみましょう:

node --experimental-strip-types index.ts
出力結果
Hello from my CLI!

/* 最近のNode.jsはTypeScriptが直接実行できて便利ですね! */

型安全な引数の定義

cittyの大きな魅力の一つは、型安全に引数を定義できることです。例えば、ユーザーから名前(--name)を受け取る引数を追加してみましょう:

index.ts
import { defineCommand, runMain } from "citty";

const main = defineCommand({
  meta: {
    name: "my-cli",
    description: "CLI with arguments",
  },
  args: {
    name: {
      type: "string",
      description: "Your name",
      required: true,
    },
  },
  run({ args }) {
    console.log(`Hello, ${args.name}!`);
  },
});

runMain(main);

このコードのポイントを説明します:

  • argsオブジェクトで引数を定義
  • 各引数にtypeを指定することで型安全性を確保
  • required: trueで必須パラメータとして設定
  • descriptionでヘルプ表示時の説明文を設定
node --experimental-strip-types index.ts --name Taro
出力結果
Hello, Taro!

サブコマンドの実装

大規模なCLIツールでは、複数のコマンドを提供したいケースがあります。cittyではサブコマンドもかなり直感的に実装できます:

index.ts
import { defineCommand, runMain } from "citty";

// サブコマンドの定義
const greetCommand = defineCommand({
  meta: { 
    name: "greet", 
    description: "Say hello" 
  },
  args: {
    name: { type: "string", required: true },
  },
  run({ args }) {
    console.log(`Hello, ${args.name}!`);
  },
});

const main = defineCommand({
  meta: { 
    name: "my-cli", 
    description: "CLI with subcommands" 
  },
  subCommands: {
    greet: greetCommand, // サブコマンドの組み入れ
  },
});

runMain(main);

サブコマンドごとにdefineCommandを使って定義し、それをsubCommandsに加えることで、サブコマンドを追加できます。簡単ですね。

実行例:

node --experimental-strip-types index.ts greet --name Taro
出力結果
Hello, Taro!

美しいヘルプ表示

cittyの魅力の一つは、デフォルトできれいなヘルプを自動生成してくれることです。--helpオプションを付けて実行してみましょう:

node --experimental-strip-types index.ts --help

このように、コマンドの使い方が見やすく表示されます。サブコマンドのヘルプも確認できます:

node --experimental-strip-types index.ts greet --help

まとめ

cittyは、以下のような点がいい感じです:

  • TypeScriptの型システムを活かした安全な引数定義
  • 直感的なAPIによるシンプルな実装
  • サブコマンドの柔軟な管理
  • 美しく見やすいヘルプ表示

Node.jsでCLIツールを作る際は、ぜひcittyの採用を検討してみてください。シンプルさと型安全性を両立した素晴らしいライブラリだと思います。

最後までお読みいただき、ありがとうございました。


Twitterでは、Node.js、TypeScriptに関する話題を発信しています。よろしければフォローをお願いします! @suin

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?