12k
All articles

Node.jsでターミナルインターフェースを構築する

Ink、neo-blessed、rawモードのプリミティブを使いNode.jsでターミナルUIを構築し、キーボード操作に対応したCLIダッシュボードやリアルタイム表示を実現する。

OpenReplay Team
OpenReplay Team
Node.jsでターミナルインターフェースを構築する

あなたのCLIツールは動作していますが、見た目は1985年のもののようです。ユーザーは単純なテキストプロンプト以上のものを期待しています。インタラクティブなダッシュボード、リアルタイム更新、キーボード駆動のナビゲーションを求めています。そこで登場するのがターミナルユーザーインターフェース(TUI)であり、Node.js 22 LTSはそれらを構築するために必要なすべてを提供しています。

このガイドでは、Node.jsターミナルUI開発のコアプリミティブをカバーし、最新のTUIエコシステムを調査し、Inkやneo-blessedなどのフレームワークが本番環境のCLIツールにどのように適合するかを示します。

重要なポイント

  • TUIは、引数を受け取り、実行して終了する単純なCLIとは異なり、永続的でインタラクティブな表示を維持します
  • Node.js 22は、ターミナルインターフェースを構築するためのrawモード、リサイズイベント、ストリーム処理などのコアプリミティブを提供します
  • InkはReactのコンポーネントモデルをターミナルに導入し、JSXに慣れた開発者に最適です
  • neo-blessedは、マウスサポートを備えた従来のウィジェットベースのレイアウトのためにblessedのレガシーを継承しています
  • oclifのようなCLIフレームワークとTUIライブラリを組み合わせて、整理された機能豊富なコマンドラインツールを構築できます

TUIと単純なCLIを区別するもの

CLIは引数を受け取り、実行して終了します。TUIは永続的でインタラクティブな表示を維持します。htoplsを比較してみてください。

TUIが必要になるのは以下のような場合です:

  • リアルタイムデータの可視化(監視ダッシュボード、進捗追跡)
  • 複雑なナビゲーション(マルチペインレイアウト、スクロール可能なリスト)
  • ユーザーインタラクション中の永続的な状態
  • 順次テキスト出力を超えたリッチなフィードバック

Node.js 22でのTUI開発では、基礎となるプリミティブを理解することで、適切な抽象化レベルを選択できます。

Node.js 22のコアターミナルプリミティブ

stdin、stdout、およびRawモード

Node.jsはprocess.stdinprocess.stdoutをストリームとして公開しています。TUIでは、通常stdinでrawモードを有効にします:

import * as readline from  'node:readline'

process.stdin.setRawMode(true)
readline.emitKeypressEvents(process.stdin)

Rawモードは、Enterキーを待つのではなく、各キー押下を即座に送信します。これにより、リアルタイムのキーボード入力処理が可能になります。これはあらゆるインタラクティブインターフェースに不可欠です。

ANSIエスケープシーケンス

ターミナルは、スタイリングとカーソル制御のための特殊文字シーケンスを解釈します。カーソルの移動、行のクリア、色の適用はすべてANSIコードを使用します。ライブラリはこれを抽象化しますが、その存在を知っておくことはデバッグに役立ちます。

リサイズイベント

ターミナルはリサイズされます。TUIはそれに応答する必要があります:

process.stdout.on('resize', () => {
  const { columns, rows } = process.stdout
  // インターフェースを再描画
})

Unicodeとカラーサポート

最新のターミナルはUnicodeをうまく処理しますが、SSHセッションや古いエミュレータは異なります。カラーサポートを前提とする前にprocess.stdout.isTTYを確認し、TERMが限定的な機能を示す環境のためのフォールバックを検討してください。

最新のTUIエコシステム

Ink: ターミナル用のReact

Inkは、今日のターミナルインターフェース開発を支配しています。Reactのコンポーネントモデルをターミナルに導入します。JSXを記述すると、Inkがレンダリングを処理します。

import React from 'react'
import { render, Text, Box } from 'ink'

const App = () => (
  <Box flexDirection="column">
    <Text color="green">Status: Running</Text>
  </Box>
)

render(<App />)

周辺ツールがInkの地位を強化しています:

  • @inkjs/uiは既製のコンポーネント(スピナー、選択入力、プログレスバー)を提供します
  • create-ink-appは新しいプロジェクトをスキャフォールドします
  • Pastelは大規模なInkアプリケーション用のフレームワークレイヤーを提供します

Reactに慣れている場合、Inkはすぐに馴染みやすく感じられます。

Blessedファミリー: neo-blessedダッシュボード

オリジナルのblessedライブラリは、ウィジェット、レイアウト、マウスサポートを備えた豊富なNode.jsターミナルUIの先駆者でした。現在はほとんどメンテナンスされていません。

neo-blessedreblessedが開発を継続しています。これらのフォークは時折更新を受け、最新のNodeバージョンとの互換性の問題を修正しています。

neo-blessedダッシュボードでは、以下が得られます:

  • ボックスレイアウト、リスト、テーブル、フォーム
  • マウスサポート
  • スクロールとフォーカス管理
  • blessed-contribウィジェット(チャート、ゲージ、マップ)

Reactの宣言的モデルではなく、従来のウィジェットベースのレイアウトが必要な場合は、blessedファミリーのライブラリを選択してください。

TUIレイヤーとCLIフレームワークの組み合わせ

oclifでNode.js CLIを構築すると、引数解析、コマンド構成、プラグインアーキテクチャが得られます。しかし、oclifはCLIレイヤーを処理します。インターフェースはレンダリングしません。

パターン: oclifをコマンド構造に使用し、特定のコマンド内でTUIコンポーネントをレンダリングします:

import { Command } from '@oclif/core'
import { render } from 'ink'
import Dashboard from './components/Dashboard.js'

export default class Monitor extends Command {
  async run() {
    render(<Dashboard />)
}
}

この分離により、マルチコマンドツールを整理しながら、必要な場所でリッチなインターフェースを有効にできます。

アプローチの選択

ニーズソリューション
Reactの知識、コンポーネントの再利用Ink
従来のウィジェット、複雑なレイアウトneo-blessed
マルチコマンドCLI構造oclif + TUIレイヤー
単純なプロンプトのみInquirerまたはraw readline

まとめ

プリミティブから始めましょう。rawモードとリサイズ処理を理解してください。次に、あなたのメンタルモデルに合った抽象化を選択します: React開発者にはInk、ウィジェットベースの考え方にはneo-blessedです。

ターミナルは制限ではありません。Node.js 22の最新APIとこれらのフレームワークを使用すれば、コマンドラインの効率性を維持しながら、グラフィカルツールに匹敵するインターフェースを構築できます。

よくある質問

InkをTypeScriptで使用できますか?

はい、Inkは完全なTypeScriptサポートを備えています。ライブラリは型定義を同梱しており、create-ink-appはTypeScriptプロジェクトを直接スキャフォールドできます。@inkjs/uiのようなほとんどのInkエコシステムパッケージも、TypeScript型を標準で含んでいます。

TUIアプリケーションで正常なシャットダウンを処理するにはどうすればよいですか?

processオブジェクトのSIGINTおよびSIGTERMシグナルをリッスンします。Inkでは、終了前にrender()によって返されるunmount関数を呼び出します。neo-blessedの場合は、screen.destroy()を呼び出します。常にrawモードを無効にし、代替スクリーンバッファをクリアしてターミナルの状態を復元してください。

TUIはSSH接続経由で動作しますか?

一般的には動作しますが、注意点があります。SSHセッションでは、カラーサポートが制限されていたり、ターミナルの寸法が異なる場合があります。常にprocess.stdout.isTTYとTERM環境変数を確認してください。一般的なSSHクライアントでテストし、制約のある環境のために簡略化されたフォールバックモードの提供を検討してください。

同じプロジェクトでInkとneo-blessedを組み合わせることはできますか?

技術的には可能ですが、推奨されません。両方のライブラリは異なる方法でターミナルの状態を管理し、レンダリング時に競合する可能性があります。コマンドまたはインターフェースごとに1つのアプローチを選択してください。両方の機能が必要な場合は、oclifを使用して異なるTUIライブラリを使用するコマンドを分離することを検討してください。

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.