Публикация библиотеки в npm

Публикация JavaScript-библиотеки в npm-экосистеме опирается на корректную структуру пакета, предсказуемую сборку и совместимость модулей. В связке с современными инструментами сборки используется Parcel, который обеспечивает автоматическую трансформацию кода, поддержку ESM/CJS и генерацию production-сборок без сложной конфигурации.

Базовая структура проекта библиотеки обычно включает:

  • src/ — исходный код
  • dist/ — итоговая сборка
  • package.json — описание пакета
  • README.md — документация
  • .npmignore или конфигурация files в package.json

Ключевой принцип: в npm публикуется только результат сборки, а не исходники.


Инициализация npm-пакета

Файл конфигурации пакета формируется через npm и описывает все аспекты публикации.

Базовая инициализация:

npm init

После создания package.json фиксируются основные поля:

{
  "name": "my-library",
  "version": "1.0.0",
  "main": "dist/index.cjs",
  "module": "dist/index.js",
  "source": "src/index.js",
  "type": "module",
  "files": [
    "dist"
  ]
}

Ключевые поля

  • name — уникальное имя пакета в npm
  • version — версия по semver
  • main — CommonJS вход
  • module — ESM вход
  • files — список того, что попадёт в публикацию
  • source — исходная точка входа для сборщика

Организация исходного кода

Исходный код библиотеки должен быть максимально чистым и не зависеть от окружения публикации.

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

src/
  index.js
  utils/
    format.js
    validate.js

Главный экспорт:

export { format } from "./utils/format.js";
export { validate } from "./utils/validate.js";

Parcel автоматически анализирует зависимости, формируя граф модулей.


Сборка библиотеки через Parcel

Parcel поддерживает сборку библиотек без конфигурационного файла. Достаточно указать входной файл.

Команда сборки:

parcel build src/index.js --dist-dir dist

Режим production

Parcel автоматически:

  • минифицирует код
  • удаляет dev-зависимости
  • оптимизирует граф модулей
  • генерирует source maps (при необходимости)

Для отключения source maps:

parcel build src/index.js --no-source-maps

Поддержка ESM и CommonJS

Современная библиотека должна поддерживать оба формата модулей.

Parcel позволяет генерировать несколько выходных файлов через поля package.json:

{
  "main": "dist/index.cjs",
  "module": "dist/index.js",
  "exports": {
    "import": "./dist/index.js",
    "require": "./dist/index.cjs"
  }
}

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

Часто используется две сборки:

  • ESM — для современных bundler’ов
  • CJS — для Node.js старых версий

Настройка публичного API библиотеки

Файл src/index.js определяет контракт библиотеки. Важно ограничить поверхность API:

export { parseDate } from "./date/parse.js";
export { formatDate } from "./date/format.js";

Не рекомендуется экспортировать внутренние утилиты напрямую, чтобы не фиксировать их как часть публичного API.


Работа с зависимостями

В package.json зависимости делятся на:

dependencies

Используются внутри библиотеки:

"dependencies": {
  "lodash-es": "^4.17.21"
}

peerDependencies

Обязательные внешние зависимости:

"peerDependencies": {
  "react": ">=18"
}

devDependencies

Инструменты разработки:

"devDependencies": {
  "parcel": "^2.0.0"
}

Parcel учитывает зависимости при построении графа модулей, исключая dev-зависимости из production-сборки.


Конфигурация package.json для публикации

Критически важные поля:

{
  "name": "my-library",
  "version": "1.0.0",
  "description": "Utility library",
  "license": "MIT",
  "files": ["dist"],
  "sideEffects": false
}

sideEffects

Флаг влияет на tree-shaking:

  • false — безопасное удаление неиспользуемого кода
  • массив — перечисление файлов с побочными эффектами

Игнорирование файлов при публикации

Для ограничения содержимого пакета используются:

.npmignore

src/
tests/
parcel-cache/

Альтернатива: files

Предпочтительный способ:

"files": ["dist", "README.md"]

Сборка перед публикацией

Типичный workflow:

parcel build src/index.js --dist-dir dist

Проверка результата:

dist/
  index.js
  index.cjs
  index.js.map

Подготовка к публикации в npm

Перед отправкой пакета в реестр npm выполняется аутентификация:

npm login

Публикация:

npm publish

Для scoped-пакетов:

npm publish --access public

Версионирование библиотеки

Используется semver:

  • MAJOR — несовместимые изменения
  • MINOR — новая функциональность
  • PATCH — исправления

Команды:

npm version patch
npm version minor
npm version major

Оптимизация структуры сборки

При использовании Parcel важно учитывать:

1. Разделение входных точек

"source": "src/index.js"

2. Изоляция внутренних модулей

Внутренние файлы не экспортируются напрямую наружу.

3. Минимизация API

Чем меньше публичных экспортов, тем стабильнее библиотека.


TypeScript-совместимость (при необходимости)

Хотя Parcel способен обрабатывать TypeScript, типы публикуются отдельно:

"types": "dist/index.d.ts"

Генерация типов выполняется отдельно от Parcel через tsc.


Поддержка sourcemaps

Sourcemaps обеспечивают отладку production-кода:

parcel build src/index.js --dist-dir dist --source-maps

Проверка пакета перед публикацией

Локальная проверка:

npm pack

Создаётся .tgz архив, идентичный публикации в npm.


Частые ошибки сборки и публикации

1. Публикация исходников

Причина: отсутствие files или .npmignore.

2. Неверный entry point

Причина: не синхронизированы main, module, exports.

3. Дублирование зависимостей

Причина: перенос runtime-библиотек в devDependencies.

4. Отсутствие tree-shaking

Причина: sideEffects не настроен.


Итоговая структура готовой библиотеки

project/
  src/
  dist/
  package.json
  README.md

Финальный package.json:

{
  "name": "my-library",
  "version": "1.0.0",
  "main": "dist/index.cjs",
  "module": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": ["dist"],
  "sideEffects": false
}

Сборка через Parcel формирует дистрибутив, готовый к публикации в экосистему npm с поддержкой современных модульных стандартов и оптимизаций.