← Назад к вопросам

Выносил ли что-либо на проекте в отдельный npm пакет

1.0 Junior🔥 141 комментариев
#Инструменты и DevOps#Инструменты и DevOps

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как вынести код в отдельный npm пакет

Это частый вопрос на собеседованиях. Работодатель хочет понять, может ли разработчик организовать переиспользуемый код, управлять версиями и работать с package managers. Рассмотрим полный процесс.

Зачем выносить код в npm пакет?

1. Переиспользуемость

  • Один пакет используется в нескольких проектах
  • Нет необходимости копировать код
  • Единый источник истины

2. Версионирование

  • Контроль версий (semantic versioning)
  • Возможность обновлять разные проекты независимо
  • Breaking changes явно обозначены

3. Управление зависимостями

  • Пакет может иметь свои зависимости
  • Избегаем дублирования больших библиотек
  • Чётко определены peer dependencies

4. Масштабируемость

  • Отделяется от основного приложения
  • Может развиваться отдельно
  • Легче искать баги в изолированном коде

Пример 1: Простой утилити пакет

Предположим, у вас есть функции для работы с датами и форматирования, которые используются в 3 проектах.

Шаг 1: Создайте директорию для пакета

mkdir my-utils-package
cd my-utils-package
npm init -y

Шаг 2: Создайте структуру

my-utils-package/
  src/
    index.ts
    date.ts
    format.ts
  package.json
  tsconfig.json
  README.md

Шаг 3: Напишите код (src/date.ts)

export function formatDate(date: Date, format: string = 'dd.MM.yyyy'): string {
  const day = String(date.getDate()).padStart(2, '0');
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const year = date.getFullYear();
  
  return format
    .replace('dd', day)
    .replace('MM', month)
    .replace('yyyy', year);
}

export function addDays(date: Date, days: number): Date {
  const result = new Date(date);
  result.setDate(result.getDate() + days);
  return result;
}

Шаг 4: Создайте точку входа (src/index.ts)

export * from './date';
export * from './format';

Шаг 5: Обновите package.json

{
  "name": "@mycompany/utils",
  "version": "1.0.0",
  "description": "Common utilities for our projects",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "scripts": {
    "build": "tsc",
    "test": "jest",
    "publish": "npm run build && npm publish"
  },
  "keywords": ["utils", "date", "format"],
  "author": "My Company",
  "license": "MIT",
  "devDependencies": {
    "typescript": "^5.0.0",
    "jest": "^29.0.0"
  }
}

Шаг 6: Настройте TypeScript (tsconfig.json)

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "lib": ["ES2020"],
    "declaration": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

Шаг 7: Соберите пакет

npm run build

Пример 2: React компонент пакет

Если выносите React компоненты:

Структура:

my-components/
  src/
    Button/
      Button.tsx
      Button.test.tsx
      Button.css
      index.ts
    Input/
      Input.tsx
      Input.test.tsx
      index.ts
    index.ts
  package.json

src/Button/Button.tsx

import React from 'react';
import './Button.css';

interface ButtonProps {
  label: string;
  onClick: () => void;
  variant?: 'primary' | 'secondary';
}

export function Button({ label, onClick, variant = 'primary' }: ButtonProps) {
  return (
    <button 
      className={`btn btn-${variant}`}
      onClick={onClick}
    >
      {label}
    </button>
  );
}

package.json для React пакета

{
  "name": "@mycompany/components",
  "version": "1.0.0",
  "peerDependencies": {
    "react": ">=16.8.0",
    "react-dom": ">=16.8.0"
  },
  "devDependencies": {
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}

Как опубликовать пакет

Вариант 1: На npm публичный реестр

# Создайте аккаунт на npm.com
# Логинитесь
npm login

# Публикуйте
npm publish --access public

# После этого пакет будет доступен для установки
npm install @mycompany/utils

Вариант 2: На приватный реестр компании

# Настройка в .npmrc
npm config set registry https://npm.mycompany.com/
npm login --registry https://npm.mycompany.com/
npm publish

Вариант 3: GitHub Packages

# .npmrc в проекте
@mycompany:registry=https://npm.pkg.github.com

# Публикация
npm publish

Как использовать пакет в проектах

Установка

npm install @mycompany/utils

Использование в коде

import { formatDate, addDays } from '@mycompany/utils';

const today = new Date();
const tomorrow = addDays(today, 1);
console.log(formatDate(tomorrow));

Semantic Versioning

Важно правильно нумеровать версии:

Формат: MAJOR.MINOR.PATCH

  • MAJOR (1.0.0 -> 2.0.0): Breaking changes (удалили функцию, изменили сигнатуру)
  • MINOR (1.0.0 -> 1.1.0): Новая функциональность, обратно совместимо
  • PATCH (1.0.0 -> 1.0.1): Исправления багов
# Обновите версию
npm version patch   # 1.0.0 -> 1.0.1
npm version minor   # 1.0.0 -> 1.1.0
npm version major   # 1.0.0 -> 2.0.0

# Опубликуйте
npm publish

Лучшие практики

1. Документация

# My Utils Package

## Установка
npm install @mycompany/utils

## Использование
import { formatDate } from '@mycompany/utils';
const formatted = formatDate(new Date());

## API
### formatDate(date, format)
- date: Date
- format: string (dd.MM.yyyy)
- returns: string

2. Тестирование

npm run test

3. Минимизированный бандл

{
  "scripts": {
    "build": "tsc && esbuild src/index.ts --bundle --minify --outfile=dist/index.js"
  }
}

4. TypeScript типы

{
  "main": "dist/index.js",
  "types": "dist/index.d.ts"
}

На собеседовании

Если у вас нет реального опыта, ответьте:

"Я вынес X функциональность в отдельный пакет, потому что она использовалась в нескольких проектах. Я:

  1. Создал структуру пакета с src/, типами TypeScript
  2. Опубликовал на npm (или приватный реестр)
  3. Использовал semantic versioning для управления версиями
  4. Написал документацию и тесты
  5. Обновил зависимости в основных проектах

Это помогло избежать дублирования кода и облегчило поддержку."