Бинарные скрипты: поле bin

Назначение бинарных скриптов

Бинарные скрипты в Node.js-пакетах представляют собой исполняемые файлы, которые становятся доступными как команды в терминале после установки пакета. Они используются для создания CLI-инструментов, автоматизации задач, генераторов кода и сборщиков.

Ключевая идея заключается в том, что пакет может экспортировать не только программный API для использования в коде, но и отдельную точку входа, запускаемую из командной строки.

Поле bin в package.json

Поле bin описывает сопоставление между командой, доступной в терминале, и файлом, который будет выполнен при её вызове.

Существует два основных варианта объявления.

Один исполняемый файл

{
  "name": "my-tool",
  "version": "1.0.0",
  "bin": "./cli.js"
}

В этом случае имя команды автоматически совпадает с именем пакета (my-tool), а выполнение будет перенаправлено на файл cli.js.

Несколько команд

{
  "name": "my-tool",
  "version": "1.0.0",
  "bin": {
    "my-tool": "./dist/cli.js",
    "my-tool-init": "./dist/init.js"
  }
}

Здесь создаются две независимые команды:

  • my-tool
  • my-tool-init

Каждая указывает на отдельный исполняемый файл.


Механизм установки бинарных файлов

При установке пакета через npm или yarn происходит автоматическое создание ссылок на исполняемые файлы.

Процесс включает следующие шаги:

  1. Чтение поля bin в package.json
  2. Определение имени команды
  3. Создание символьной ссылки в директории node_modules/.bin
  4. Добавление этой директории в PATH во время выполнения npm-скриптов

Таким образом, команда становится доступной без глобальной установки пакета.


Связь с node_modules/.bin

Каталог node_modules/.bin играет ключевую роль в механизме CLI-инструментов.

При установке пакета с bin-полем туда добавляются исполняемые ссылки:

node_modules/
  .bin/
    my-tool -> ../my-tool/cli.js

Во время выполнения npm-скриптов эта директория автоматически добавляется в переменную окружения PATH, что позволяет вызывать команды напрямую:

npm run build

Если внутри build используется my-tool, он будет найден автоматически.


Shebang и запуск исполняемых файлов

Чтобы файл мог запускаться как CLI-утилита, в начале используется shebang:

#!/usr/bin/env node

console.log("CLI запущен");

Shebang сообщает операционной системе, что файл должен выполняться через Node.js интерпретатор.

Без этого строки файл не будет корректно исполняться как команда.


Роль прав доступа

В Unix-подобных системах файл должен иметь право на выполнение:

chmod +x cli.js

Однако при установке через npm это обычно обрабатывается автоматически.


Связь с Parcel как CLI-инструментом

Parcel использует механизм bin для предоставления команды parcel.

Внутри пакета Parcel определён исполняемый файл, который становится точкой входа CLI:

{
  "name": "parcel",
  "bin": {
    "parcel": "./lib/cli.js"
  }
}

После установки:

npm install parcel

становится доступной команда:

parcel build index.html

CLI-слой Parcel отвечает за:

  • разбор аргументов командной строки
  • инициализацию сборки
  • выбор режима (dev/build/watch)
  • передачу управления внутреннему API сборщика

Разделение CLI и ядра сборщика

Архитектура Parcel и подобных инструментов обычно разделяет:

  • CLI-слой (через bin)
  • ядро сборки (JavaScript API)

CLI файл обычно выполняет минимальную работу:

#!/usr/bin/env node

import { run } from "@parcel/core";

run(process.argv.slice(2));

Такой подход позволяет:

  • использовать Parcel как библиотеку
  • тестировать ядро без CLI
  • переиспользовать логику в других инструментах

Глобальная и локальная установка бинарных команд

Локальная установка

npm install parcel

Команда доступна только внутри проекта:

npx parcel index.html

или через npm scripts:

{
  "scripts": {
    "dev": "parcel index.html"
  }
}

Глобальная установка

npm install -g parcel

Команда доступна во всей системе:

parcel index.html

Однако в современных проектах предпочтение отдаётся локальной установке с npx, чтобы фиксировать версии.


Использование npx и выполнение бинарников

npx ищет бинарные команды в:

  1. локальном node_modules/.bin
  2. кэше npm
  3. удалённом реестре (если пакет не установлен)

Пример:

npx parcel build index.html

Запускает бинарник Parcel без глобальной установки.


Множественные бинарники и CLI-инструменты

Пакеты могут предоставлять несколько CLI-команд:

{
  "bin": {
    "parcel": "./cli.js",
    "parcel-init": "./init.js",
    "parcel-analyze": "./analyze.js"
  }
}

Каждая команда может:

  • использовать общий код ядра
  • вызывать разные режимы работы
  • быть независимым entry point

Сборка TypeScript и поле bin

При использовании TypeScript исходный CLI обычно находится в src/cli.ts, но в bin указывается уже скомпилированный файл:

{
  "bin": {
    "my-tool": "./dist/cli.js"
  }
}

Критически важно:

  • не указывать .ts файл в bin
  • учитывать этап сборки перед публикацией

Monorepo и бинарные скрипты

В монорепозиториях бинарные команды часто проксируются через workspace-пакеты.

Пример структуры:

packages/
  cli/
    package.json (bin)
  core/

CLI пакет:

{
  "name": "@repo/cli",
  "bin": {
    "repo": "./dist/cli.js"
  }
}

Это позволяет запускать:

repo build

при этом логика находится в другом пакете.


Для разработки CLI-инструментов используется:

npm link

Процесс:

  1. создаётся глобальная символьная ссылка
  2. команда становится доступна в системе
  3. изменения в коде отражаются сразу

Это особенно важно при разработке инструментов вроде Parcel или его плагинов.


Внутреннее разрешение команд

При вызове команды:

parcel build

операционная система:

  1. ищет parcel в PATH
  2. находит ссылку в node_modules/.bin
  3. открывает файл CLI
  4. Node.js интерпретирует файл через shebang

Особенности кроссплатформенности

На Windows вместо символических ссылок используются shim-файлы (.cmd), создаваемые npm.

Например:

parcel
parcel.cmd
parcel.ps1

Это обеспечивает единообразие запуска CLI на всех платформах.


Типичные ошибки при работе с bin

Отсутствие shebang

Файл не запускается как команда.

Неправильный путь

"bin": "./src/cli.js"

если файл не попадает в npm-пакет, команда ломается.

Несоответствие сборки

TypeScript/ESBuild не сгенерировали dist.

Отсутствие прав доступа (Unix)

CLI не исполняется напрямую.


Роль bin в экосистеме инструментов сборки

Поле bin является фундаментом CLI-инструментов, включая сборщики, линтеры и генераторы кода. В случае Parcel оно обеспечивает:

  • запуск сборки из терминала
  • интеграцию с npm scripts
  • переносимость между средами
  • унификацию интерфейса команд

Механизм остаётся одинаковым для всех версий Node.js-инструментов, что делает его базовым строительным блоком CLI-экосистемы JavaScript.