12k
All articles

Создание терминальных интерфейсов с помощью Node.js

Построение терминальных UI на Node.js с Ink, neo-blessed и raw mode для создания CLI-дашбордов с клавиатурным управлением и выводом данных в реальном времени.

OpenReplay Team
OpenReplay Team
Создание терминальных интерфейсов с помощью Node.js

Ваш CLI-инструмент работает, но выглядит так, будто он из 1985 года. Пользователи ожидают большего, чем просто текстовые подсказки — им нужны интерактивные панели управления, обновления в реальном времени и навигация с помощью клавиатуры. Именно для этого существуют терминальные пользовательские интерфейсы (TUI), и Node.js 22 LTS предоставляет всё необходимое для их создания.

Это руководство охватывает основные примитивы для разработки терминальных UI на Node.js, обзор современной экосистемы TUI и показывает, как фреймворки вроде Ink и neo-blessed вписываются в продакшн CLI-инструменты.

Ключевые выводы

  • TUI поддерживают постоянные интерактивные отображения, в отличие от простых CLI, которые принимают аргументы, выполняются и завершаются
  • Node.js 22 предоставляет основные примитивы, такие как raw mode, события изменения размера и обработка потоков для создания терминальных интерфейсов
  • Ink привносит компонентную модель React в терминалы, что делает его идеальным для разработчиков, знакомых с JSX
  • neo-blessed продолжает наследие blessed для традиционных виджетных макетов с поддержкой мыши
  • Комбинируйте CLI-фреймворки вроде oclif с TUI-библиотеками для создания организованных, многофункциональных инструментов командной строки

Что отличает TUI от простых CLI

CLI принимает аргументы, выполняется и завершается. TUI поддерживает постоянное интерактивное отображение. Сравните htop и ls.

TUI имеют смысл, когда вам нужно:

  • Визуализация данных в реальном времени (панели мониторинга, отслеживание прогресса)
  • Сложная навигация (многопанельные макеты, прокручиваемые списки)
  • Постоянное состояние во время взаимодействия с пользователем
  • Богатая обратная связь помимо последовательного текстового вывода

Для разработки TUI на Node.js 22 понимание базовых примитивов помогает выбрать правильный уровень абстракции.

Основные терминальные примитивы в Node.js 22

stdin, stdout и Raw Mode

Node.js предоставляет process.stdin и process.stdout как потоки. Для TUI обычно включают raw mode на stdin:

import * as readline from  'node:readline'

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

Raw mode отправляет каждое нажатие клавиши немедленно, а не ждёт Enter. Это обеспечивает обработку ввода с клавиатуры в реальном времени — необходимое условие для любого интерактивного интерфейса.

ANSI Escape-последовательности

Терминалы интерпретируют специальные последовательности символов для стилизации и управления курсором. Перемещение курсора, очистка строк и применение цветов — всё использует 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">Статус: Работает</Text>
  </Box>
)

render(<App />)

Окружающий инструментарий усиливает позицию Ink:

  • @inkjs/ui предоставляет готовые компоненты (спиннеры, поля выбора, прогресс-бары)
  • create-ink-app создаёт каркас новых проектов
  • Pastel предлагает фреймворк-слой для больших Ink-приложений

Если вы знакомы с React, Ink покажется сразу понятным.

Семейство Blessed: панели управления neo-blessed

Оригинальная библиотека blessed стала пионером богатых терминальных UI на Node.js с виджетами, макетами и поддержкой мыши. Сейчас она практически не поддерживается.

neo-blessed и reblessed продолжают разработку. Эти форки получают периодические обновления и исправляют проблемы совместимости с современными версиями Node.

С панелями управления neo-blessed вы получаете:

  • Макеты Box, списки, таблицы и формы
  • Поддержку мыши
  • Прокрутку и управление фокусом
  • Виджеты blessed-contrib (графики, датчики, карты)

Выбирайте библиотеки семейства blessed, когда вам нужны традиционные виджетные макеты, а не декларативная модель React.

Сочетание TUI-слоёв с CLI-фреймворками

Создание Node.js CLI с oclif даёт вам парсинг аргументов, организацию команд и архитектуру плагинов. Но 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
Структура многокомандного CLIoclif + TUI-слой
Только простые подсказкиInquirer или чистый readline

Заключение

Начните с примитивов — разберитесь с raw mode и обработкой изменения размера. Затем выберите абстракцию, которая соответствует вашей ментальной модели: Ink для React-разработчиков, neo-blessed для виджетного мышления.

Терминал — это не ограничение. С современными API Node.js 22 и этими фреймворками вы можете создавать интерфейсы, которые соперничают с графическими инструментами, сохраняя при этом эффективность командной строки.

Часто задаваемые вопросы

Могу ли я использовать Ink с TypeScript?

Да, Ink имеет полную поддержку TypeScript. Библиотека поставляется с определениями типов, а create-ink-app может создавать каркас TypeScript-проектов напрямую. Большинство пакетов экосистемы Ink, таких как @inkjs/ui, также включают TypeScript-типы из коробки.

Как обрабатывать корректное завершение в TUI-приложении?

Слушайте сигналы SIGINT и SIGTERM на объекте process. В Ink вызовите функцию unmount, возвращаемую render(), перед выходом. Для neo-blessed вызовите screen.destroy(). Всегда восстанавливайте состояние терминала, отключая raw mode и очищая альтернативный буфер экрана.

Будет ли мой TUI работать через SSH-соединения?

В целом да, но с оговорками. SSH-сессии могут иметь ограниченную поддержку цветов или другие размеры терминала. Всегда проверяйте process.stdout.isTTY и переменную окружения TERM. Тестируйте с распространёнными SSH-клиентами и рассмотрите возможность предоставления упрощённого запасного режима для ограниченных окружений.

Могу ли я комбинировать Ink и neo-blessed в одном проекте?

Хотя технически это возможно, это не рекомендуется. Обе библиотеки управляют состоянием терминала по-разному и могут конфликтовать при рендеринге. Выбирайте один подход для каждой команды или интерфейса. Если вам нужны возможности обеих библиотек, рассмотрите использование 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.