Yargs
機能豊富で高度に拡張可能なNode.js CLIライブラリ。複雑なコマンド構造、検証、カスタマイズに優れています。
GitHub概要
スター11,323
ウォッチ80
フォーク1,006
作成日:2013年11月7日
言語:JavaScript
ライセンス:MIT License
トピックス
なし
スター履歴
データ取得日時: 2025/7/25 02:05
フレームワーク
yargs
概要
yargsは、Node.jsエコシステムで最も人気のあるCLIライブラリの一つです。インタラクティブなコマンドラインツールを構築するために設計されており、引数を解析してエレガントなユーザーインターフェースを生成します。「海賊をテーマにしたoptimistの現代的な後継者」として開発され、動的なヘルプメニューの自動生成、Bash補完機能、豊富な機能セットにより、Node.jsコミュニティで広く採用されています。
なぜNode.jsで最も人気なのか:
- 包括的な機能: 引数解析、コマンドサポート、バリデーション、自動ヘルプ生成を一つのライブラリで提供
- 優れたDX(開発者体験): 直感的なAPIと豊富なドキュメント
- 活発なコミュニティ: 12年以上の開発歴、282人の貢献者、月間数百万ダウンロード
- クロスプラットフォーム対応: Node.js、Deno、ブラウザ環境で動作
詳細説明
歴史と発展
yargsは12年以上前に開発が開始され、Node.jsのCLIライブラリとして成熟してきました。最初は「optimist」の後継として設計されましたが、現在では独自の進歩的な機能セットを持つ、完全に独立したライブラリとなっています。最近のアップデートでは、非同期処理の完全サポート、TypeScript型推論の強化、パフォーマンス改善が行われています。
エコシステムでの位置づけ
Node.jsエコシステムにおいて、yargsは以下の理由で特別な地位を占めています:
- 最も成熟したCLIライブラリ: 長年の開発により安定性と機能の豊富さを実現
- 多くのツールで採用: Mocha、Webpack、ESLintなど多数の著名プロジェクトで使用
- モジュラー設計: CommandInstance、UsageInstance、ValidationInstanceなど明確に分離された設計
- プラットフォーム抽象化: PlatformShimにより異なるJavaScript実行環境に対応
最新動向(2024-2025年)
- 非同期処理の完全サポート: parseAsync()メソッドによるPromiseベースの解析
- 強化されたTypeScript支援: より正確な型推論と型安全性
- 国際化の拡張: チェコ語、ウクライナ語などの新しいロケール対応
- ミドルウェアシステムの改善: グローバルミドルウェアと非同期ミドルウェアの対応
- 補完機能の強化: 位置引数の補完、エイリアス対応、Zsh改善
主な特徴
コア機能
- 宣言的なコマンド構築: 直感的で読みやすい構文でコマンドを定義
- 動的ヘルプ生成: 定義されたコマンドとオプションに基づく自動ヘルプメニュー
- 位置引数とオプション:
<required>
と[optional]
による柔軟な引数定義 - サブコマンドサポート: ネストされたコマンド構造と階層的なCLI設計
- エイリアス機能: コマンドとオプションの短縮形やエイリアス対応
高度な機能
- ミドルウェアシステム: 引数処理のパイプライン化と前後処理のカスタマイズ
- バリデーション機能: 引数の型チェック、範囲検証、カスタムバリデーション
- 設定ファイル統合: JSON、YAML、package.jsonからの設定読み込み
- 環境変数統合: 環境変数からの引数解析(prefix対応)
- 国際化(i18n): 多言語でのヘルプメッセージとエラーメッセージ
- シェル補完: Bash、Zsh、Fishでの自動補完スクリプト生成
開発者体験
- TypeScript完全サポート: 型定義による型安全な開発とIntelliSense対応
- 豊富なAPIメソッド:
.example()
,.usage()
,.epilog()
などによる詳細なヘルプカスタマイズ - テスト支援: ヘッドレスモードでのテスト実行とモック対応
- デバッグ機能: 詳細なエラーメッセージと解析プロセスの可視化
最新機能とアップデート
v17.xシリーズの主要機能
- 完全な非同期サポート:
parseAsync()
メソッドによるPromiseベースの解析 - 非同期ミドルウェア: async/awaitに対応したミドルウェア関数
- 非同期コマンドハンドラー: Promiseを返すコマンドハンドラーの完全サポート
- 非同期バリデーション: 外部サービスとの連携によるバリデーション
最近の改善点
- ESモジュール対応:
import
/export
構文でのモダンな使用方法 - TypeScript型推論の強化: より正確な型チェックとIntelliSense
- パフォーマンス最適化: 起動時間の短縮と解析速度の向上
- 補完機能の拡張: 位置引数、エイリアス、Zsh対応の改善
- 新しいロケール対応: チェコ語、ウクライナ語などの国際化拡張
- ミドルウェアの改善: グローバルミドルウェアとコマンド固有ミドルウェアの対応
メリット・デメリット
メリット
- 豊富な機能と高い柔軟性
- 優れたTypeScriptサポート
- 活発なコミュニティと豊富なドキュメント
- モジュール化された設計
- 直感的なAPI設計
- 包括的なテスト機能
デメリット
- シンプルなスクリプトには過剰な場合がある
- 設定オプションが多く、初心者には複雑
- バンドルサイズがやや大きい
- 学習曲線がある
主要リンク
書き方の例
基本的な使用例
#!/usr/bin/env node
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
const argv = yargs(hideBin(process.argv)).parse();
if (argv.ships > 3 && argv.distance < 53.5) {
console.log('Plunder more riffiwobbles!');
} else {
console.log('Retreat from the xupptumblers!');
}
# 実行例
./plunder.js --ships=4 --distance=22
# 出力: Plunder more riffiwobbles!
コマンドとオプションの定義
#!/usr/bin/env node
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
yargs(hideBin(process.argv))
.command('serve [port]', 'サーバーを起動します', (yargs) => {
return yargs
.positional('port', {
describe: 'バインドするポート',
default: 5000,
type: 'number'
})
}, (argv) => {
if (argv.verbose) console.info(`ポート${argv.port}でサーバーを起動しています`)
startServer(argv.port)
})
.option('verbose', {
alias: 'v',
type: 'boolean',
description: '詳細なログ出力'
})
.parse()
function startServer(port) {
console.log(`サーバーがポート${port}で起動しました`);
}
複数コマンドとエイリアス
#!/usr/bin/env node
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
yargs(hideBin(process.argv))
.command(['start [app]', 'run', 'up'], 'アプリを起動', {}, (argv) => {
console.log('starting up the', argv.app || 'default', 'app')
})
.command({
command: 'configure <key> [value]',
aliases: ['config', 'cfg'],
describe: '設定変数を設定',
builder: (yargs) => yargs.default('value', 'true'),
handler: (argv) => {
console.log(`${argv.key}を${argv.value}に設定しています`)
}
})
.demandCommand()
.help()
.wrap(72)
.parse()
TypeScriptでの使用例
#!/usr/bin/env node
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
interface Arguments {
username: string;
email?: string;
age: number;
verbose: boolean;
}
const argv = yargs(hideBin(process.argv))
.options({
username: {
type: 'string',
demandOption: true,
describe: 'ユーザー名'
},
email: {
type: 'string',
describe: 'メールアドレス'
},
age: {
type: 'number',
default: 25,
describe: '年齢'
},
verbose: {
type: 'boolean',
default: false,
alias: 'v',
describe: '詳細出力'
}
})
.parseSync() as Arguments;
console.log(`ユーザー: ${argv.username} (${argv.age}歳)`);
if (argv.email) {
console.log(`メール: ${argv.email}`);
}
if (argv.verbose) {
console.log('詳細モードが有効です');
}
高度な機能の例
#!/usr/bin/env node
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import fs from 'fs';
// ミドルウェア関数
const normalizeCredentials = (argv) => {
if (!argv.username || !argv.password) {
try {
const credentials = JSON.parse(fs.readFileSync('~/.credentials', 'utf8'));
return { ...argv, ...credentials };
} catch (error) {
console.warn('認証情報ファイルが読み込めません');
}
}
return argv;
};
yargs(hideBin(process.argv))
.usage('使用法: $0 <command> [options]')
.command('login', 'ユーザー認証', (yargs) => {
return yargs
.option('username', {
describe: 'ユーザー名',
type: 'string'
})
.option('password', {
describe: 'パスワード',
type: 'string'
})
}, (argv) => {
authenticateUser(argv.username, argv.password);
}, [normalizeCredentials])
.command('deploy [env]', 'アプリケーションをデプロイ', (yargs) => {
return yargs
.positional('env', {
describe: 'デプロイ環境',
choices: ['dev', 'staging', 'production'],
default: 'dev'
})
.option('force', {
type: 'boolean',
describe: '強制デプロイ'
})
}, async (argv) => {
console.log(`${argv.env}環境へデプロイ中...`);
if (argv.force) {
console.log('強制デプロイモード');
}
await deployApplication(argv.env, argv.force);
})
.middleware(normalizeCredentials)
.demandCommand(1, 'コマンドを指定してください')
.help('h')
.alias('h', 'help')
.version('1.0.0')
.epilog('詳細な使用方法については、各コマンドで --help を使用してください')
.parse();
function authenticateUser(username, password) {
console.log(`ユーザー ${username} を認証中...`);
}
async function deployApplication(env, force) {
return new Promise((resolve) => {
setTimeout(() => {
console.log(`${env}環境へのデプロイが完了しました`);
resolve();
}, 2000);
});
}
コマンドモジュールの例
// commands/server.js
export const command = 'server [port]';
export const describe = 'Webサーバーを起動';
export const builder = {
port: {
default: 3000,
describe: 'サーバーポート',
type: 'number'
},
host: {
default: 'localhost',
describe: 'サーバーホスト',
type: 'string'
}
};
export const handler = (argv) => {
console.log(`サーバーを http://${argv.host}:${argv.port} で起動中...`);
// サーバー起動ロジック
};
// cli.js
#!/usr/bin/env node
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
yargs(hideBin(process.argv))
.commandDir('commands')
.demandCommand()
.help()
.parse();
バリデーションと設定の例
#!/usr/bin/env node
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
const argv = yargs(hideBin(process.argv))
.usage('使用法: $0 -w [num] -h [num]')
.option('width', {
alias: 'w',
describe: '幅',
type: 'number',
demandOption: true
})
.option('height', {
alias: 'h',
describe: '高さ',
type: 'number',
demandOption: true
})
.option('format', {
alias: 'f',
describe: '出力形式',
choices: ['json', 'xml', 'yaml'],
default: 'json'
})
.check((argv) => {
if (argv.width <= 0 || argv.height <= 0) {
throw new Error('幅と高さは正の数である必要があります');
}
return true;
})
.example('$0 -w 10 -h 20', '幅10、高さ20で実行')
.example('$0 -w 5 -h 8 -f xml', 'XML形式で出力')
.help()
.parse();
console.log(`面積: ${argv.width * argv.height}`);
console.log(`形式: ${argv.format}`);