Перейти к содержанию
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
exlends
Категории
  1. Главная
  2. Категории
  3. Языки программирования
  4. JavaScript
  5. NPM: Полный справочник для опытных разработчиков

NPM: Полный справочник для опытных разработчиков

Запланировано Прикреплена Закрыта Перенесена JavaScript
1 Сообщения 1 Постеры 54 Просмотры
  • Сначала старые
  • Сначала новые
  • По количеству голосов
Ответить
  • Ответить, создав новую тему
Авторизуйтесь, чтобы ответить
Эта тема была удалена. Только пользователи с правом управления темами могут её видеть.
  • AladdinA Не в сети
    AladdinA Не в сети
    Aladdin
    js
    написал отредактировано Aladdin
    #1

    Node Package Manager (npm) — это не просто инструмент для установки пакетов, а полнофункциональная экосистема управления зависимостями, публикации модулей и автоматизации рабочих процессов. Для опытного разработчика важно понимать не только базовые команды, но и тонкие механизмы версионирования, разрешения зависимостей, оптимизации и лучшие практики при разработке собственных библиотек.

    1. Архитектура и базовые концепции

    1.1 Структура реестра и локального хранилища

    npm состоит из трёх ключевых компонентов:

    • Реестр npm (registry.npmjs.org) — центральный репозиторий всех опубликованных пакетов с метаданными
    • npm CLI — локальный инструмент для взаимодействия с реестром и управления проектами
    • node_modules — локальное хранилище установленных пакетов в вашем проекте
    # Проверка текущего реестра
    npm config get registry
    
    # Изменение реестра (например, на зеркало)
    npm config set registry https://registry.yarnpkg.com
    

    1.2 Семантическое версионирование (semver)

    Версии пакетов следуют формату MAJOR.MINOR.PATCH:

    ^1.2.3  — совместимо с версиями 1.x.x (изменения в minor и patch)
    ~1.2.3  — совместимо с версиями 1.2.x (изменения только в patch)
    1.2.3   — точная версия
    >=1.2.3 — 1.2.3 и выше
    1.2.3 - 2.0.0 — диапазон версий
    

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

    2.1 Типы зависимостей в package.json

    {
      "dependencies": {
        "express": "^4.18.2"
      },
      "devDependencies": {
        "typescript": "^5.0.0",
        "jest": "^29.0.0"
      },
      "peerDependencies": {
        "react": ">=16.8.0",
        "react-dom": ">=16.8.0"
      },
      "optionalDependencies": {
        "bcrypt": "^5.0.0"
      },
      "bundledDependencies": [
        "lodash"
      ]
    }
    

    Ключевые отличия:

    • dependencies — необходимы в production
    • devDependencies — нужны только для разработки (не устанавливаются при npm install --production)
    • peerDependencies — указывают, какие версии других библиотек ожидаются в проекте-потребителе
    • optionalDependencies — пакеты, которые не должны ломать установку при ошибке
    • bundledDependencies — пакеты, которые включаются в распределение npm

    2.2 Алгоритм разрешения зависимостей

    npm использует flat tree algorithm (начиная с npm 3+):

    project/
    ├── node_modules/
    │   ├── express/ (версия 4.18.2)
    │   ├── body-parser/ (зависимость express)
    │   └── debug/ (зависимость body-parser)
    

    При конфликтах версий npm размещает дополнительные копии на уровне зависимостей:

    project/
    ├── node_modules/
    │   ├── packageA@1.0.0/
    │   │   └── node_modules/
    │   │       └── packageB@2.0.0/ (конфликт версии)
    │   └── packageB@1.0.0/
    

    2.3 Lock-файлы и воспроизводимость

    # package-lock.json — точная фиксация всех версий (npm)
    npm install
    
    # npm-shrinkwrap.json — публикуется вместе с пакетом
    npm shrinkwrap
    
    # Игнорирование lock-файла при установке
    npm install --no-save
    

    3. Установка пакетов из различных источников

    3.1 Установка из npm реестра

    # Последняя версия
    npm install express
    
    # Конкретная версия
    npm install express@4.17.1
    
    # Диапазон версий
    npm install "express@>=4.17.0 <5.0.0"
    
    # Последняя beta-версия
    npm install express@latest-beta
    
    # Dev-зависимость
    npm install --save-dev typescript
    
    # Global установка
    npm install -g pm2
    
    # Без сохранения в package.json
    npm install lodash --no-save
    

    3.2 Установка из GitHub

    # Из главной ветки репозитория
    npm install github:username/repository
    
    # Из определённой ветки
    npm install github:username/repository#branch-name
    
    # Из конкретного коммита
    npm install github:username/repository#commit-sha
    
    # С прямым URL на репозиторий
    npm install https://github.com/username/repository.git
    
    # Из приватного репозитория (требует токена)
    npm install git+https://github.com/username/private-repo.git
    

    Конфигурация для приватных репозиториев:

    # Глобально для github.com
    npm config set git+https://github.com/:_authToken YOUR_TOKEN
    
    # Или через .npmrc
    echo "//github.com/:_authToken=YOUR_TOKEN" >> ~/.npmrc
    

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

    # Установка из локальной папки (npm)
    npm install ../my-local-package
    
    # Через npm link (создаёт symlink)
    cd ~/my-library
    npm link
    cd ~/my-project
    npm link my-library
    
    # Прямой путь в package.json
    {
      "dependencies": {
        "my-package": "file:../my-local-package"
      }
    }
    
    # Установка из tar-архива
    npm install ./package.tar.gz
    
    # Установка из zip
    npm install ./package.zip
    

    Особенность npm link: создаёт глобальную symlink-ссылку, которая работает с различными проектами для локальной разработки.

    3.4 Установка с пользовательского реестра

    # Конкретный реестр для scoped-пакета
    npm config set @myorg:registry https://private-registry.example.com
    
    # Или в .npmrc
    @myorg:registry=https://private-registry.example.com
    //private-registry.example.com/:_authToken=TOKEN
    
    # Установка из приватного реестра
    npm install @myorg/private-package
    

    4. Жизненный цикл npm скриптов и хуки

    4.1 Полный жизненный цикл npm команд

    npm имеет систему хуков, которые выполняются на разных этапах выполнения команд. Это позволяет автоматизировать разработку и развертывание приложений.

    Общий порядок выполнения:

    pre<command> → <command> → post<command>
    

    Каждая npm команда может быть окружена pre и post скриптами, которые выполняются автоматически.

    4.2 Жизненный цикл install и postinstall

    postinstall — это один из самых важных и часто используемых хуков в npm. Он выполняется сразу после успешной установки зависимостей.

    Когда выполняется:

    1. После npm install (установка всех зависимостей)
    2. После npm ci (clean install)
    3. После любой операции, которая модифицирует node_modules (например, npm link)
    4. Для каждого пакета отдельно — если пакет имеет собственный postinstall, он выполняется при установке этого пакета

    Для чего нужен:

    • Компиляция нативных модулей (например, node-gyp для пакетов с C++ кодом)
    • Создание необходимых директорий и файлов конфигурации
    • Загрузка дополнительных ресурсов
    • Генерация типов TypeScript или документации
    • Инициализация пакета
    • Установка Git хуков (например, через husky)
    • Кэширование или оптимизация

    Пример использования в package.json:

    {
      "name": "my-app",
      "version": "1.0.0",
      "scripts": {
        "postinstall": "node scripts/setup.js && npm run build:types",
        "build:types": "tsc --emitDeclarationOnly"
      }
    }
    

    Практический пример — установка Git хуков через Husky:

    {
      "name": "my-project",
      "devDependencies": {
        "husky": "^8.0.0"
      },
      "scripts": {
        "postinstall": "husky install"
      }
    }
    

    При выполнении npm install будут автоматически установлены Git хуки.

    Пример — компиляция нативных модулей:

    Для пакетов типа node-sqlite3 или bcrypt, которые содержат нативный код:

    {
      "name": "sqlite3",
      "scripts": {
        "postinstall": "node-gyp rebuild"
      }
    }
    

    4.3 Полный цикл жизненных циклов npm команд

    Цикл для npm install:

    preinstall → install → postinstall
    

    Цикл для npm version:

    preversion → version → postversion
    

    Цикл для npm publish:

    prepublishOnly → prepare → prepublish → publish → postpublish
    

    Цикл для пользовательских скриптов:

    npm run build
    # Выполнится в этом порядке:
    # 1. prebuild (если существует)
    # 2. build
    # 3. postbuild (если существует)
    

    4.4 Другие важные хуки

    preinstall

    Выполняется перед установкой зависимостей. Используется редко.

    Для чего:

    • Проверка версии Node.js
    • Предварительная валидация окружения
    • Отказ в установке если не соблюдены требования
    {
      "scripts": {
        "preinstall": "node -v && npm -v"
      }
    }
    

    prepare

    Выполняется:

    • После npm install
    • После npm ci
    • Перед npm publish
    • Когда пакет устанавливается из Git репозитория

    Для чего:

    • Компиляция TypeScript в JavaScript
    • Генерация файлов
    • Подготовка пакета к публикации

    Часто используется вместо postinstall для более надёжного выполнения.

    {
      "scripts": {
        "prepare": "npm run build",
        "build": "tsc"
      }
    }
    

    prepublishOnly

    Выполняется только перед публикацией (npm publish), но не при локальной установке.

    Для чего:

    • Запуск тестов перед публикацией
    • Проверка версии
    • Очистка артефактов
    • Финальная валидация кода
    {
      "scripts": {
        "prepublishOnly": "npm run test && npm run lint && npm run build"
      }
    }
    

    Различие между prepare и prepublishOnly:

    Хук npm install npm ci npm publish Git install
    prepare ✅ ✅ ✅ ✅
    prepublishOnly ❌ ❌ ✅ ❌

    postversion

    Выполняется после обновления версии в package.json с помощью npm version.

    Для чего:

    • Автоматический коммит и тег в Git
    • Публикация пакета
    • Уведомление о новой версии
    {
      "scripts": {
        "postversion": "git push && git push --tags && npm publish"
      }
    }
    

    4.5 Цикл для глобальной установки пакетов

    Когда устанавливается глобальный пакет с npm install -g, хуки работают иначе:

    npm install -g my-cli-tool
    # Выполнится: preinstall → install → postinstall
    

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

    4.6 Практический пример комплексного использования хуков

    {
      "name": "@company/my-library",
      "version": "1.2.0",
      "scripts": {
        "preinstall": "node scripts/check-node-version.js",
        "postinstall": "husky install && npm run generate:types",
        "prepare": "npm run build",
        "prebuild": "npm run clean && npm run lint",
        "build": "tsc && esbuild src/index.ts --bundle --outfile=dist/index.js",
        "postbuild": "npm run test",
        "prepublishOnly": "npm run test:full && npm run audit",
        "postpublish": "npm run notify:slack",
        "postversion": "git push && git push --tags"
      }
    }
    

    Порядок выполнения при различных командах:

    При npm install:

    1. preinstall (проверка версии Node.js)
    2. postinstall (установка Git хуков и генерация типов)
    3. prepare (компиляция кода)
    

    При npm run build:

    1. prebuild (очистка, линтинг)
    2. build (основная компиляция)
    3. postbuild (запуск тестов)
    

    При npm publish:

    1. prepublishOnly (полное тестирование и аудит)
    2. prepare (компиляция)
    3. publish (публикация в npm)
    4. postpublish (уведомление в Slack)
    

    При npm version patch:

    1. preversion (проверки)
    2. version (обновление версии)
    3. postversion (Git push и публикация)
    

    5. Разработка и публикация собственных библиотек

    5.1 Инициализация и структура проекта

    npm init -y
    npm link
    

    Структура стандартной библиотеки:

    my-library/
    ├── package.json
    ├── package-lock.json
    ├── README.md
    ├── .npmignore                 # Что исключить из публикации
    ├── .gitignore
    ├── src/
    │   └── index.ts
    ├── dist/                      # Скомпилированный код
    ├── types/                     # TypeScript definitions
    ├── tests/
    └── .github/workflows/         # CI/CD
    

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

    {
      "name": "@username/my-library",
      "version": "1.0.0",
      "description": "Краткое описание",
      "main": "dist/index.js",
      "types": "types/index.d.ts",
      "exports": {
        ".": {
          "import": "./dist/index.mjs",
          "require": "./dist/index.js",
          "types": "./types/index.d.ts"
        },
        "./package.json": "./package.json"
      },
      "files": [
        "dist",
        "types",
        "README.md"
      ],
      "scripts": {
        "build": "tsc && esbuild src/index.ts --bundle --outfile=dist/index.js",
        "test": "jest",
        "prepublishOnly": "npm run build && npm run test",
        "version": "npm run format && git add -A src"
      },
      "keywords": [
        "useful",
        "keywords"
      ],
      "author": "Your Name",
      "license": "MIT",
      "peerDependencies": {
        "react": ">=16.8.0"
      },
      "repository": {
        "type": "git",
        "url": "https://github.com/username/my-library.git"
      },
      "bugs": {
        "url": "https://github.com/username/my-library/issues"
      },
      "homepage": "https://github.com/username/my-library#readme"
    }
    

    Критические поля:

    • main — entry point для CommonJS
    • types — путь к TypeScript definitions
    • exports — conditional exports для разных модульных систем
    • files — массив файлов/папок для включения в пакет
    • prepublishOnly — выполняется перед публикацией

    5.3 Настройка для ESM и CJS одновременно

    {
      "exports": {
        ".": {
          "types": "./dist/index.d.ts",
          "import": "./dist/index.mjs",
          "require": "./dist/index.js"
        },
        "./package.json": "./package.json"
      }
    }
    

    Скрипт build для обеих систем:

    # package.json scripts
    "build": "npm run build:cjs && npm run build:esm",
    "build:cjs": "tsc --module commonjs --outDir dist --declaration",
    "build:esm": "tsc --module es2020 --outDir dist --outFileExtension .mjs"
    

    5.4 Публикация в npm

    # Версионирование
    npm version major    # 1.0.0 → 2.0.0
    npm version minor    # 1.0.0 → 1.1.0
    npm version patch    # 1.0.0 → 1.0.1
    
    # Публикация (требует npm аккаунт)
    npm login
    npm publish
    
    # Публикация scoped-пакета как public
    npm publish --access public
    
    # Pre-release версия
    npm publish --tag beta
    npm install my-package@beta
    
    # Распубликование старой версии
    npm publish --force
    
    # Отмена публикации (только в первые 72 часа)
    npm unpublish my-package@1.0.0
    

    5.5 CI/CD для автоматической публикации

    .github/workflows/publish.yml:

    name: Publish to npm
    on:
      push:
        tags:
          - 'v*'
    jobs:
      publish:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
          - uses: actions/setup-node@v3
            with:
              node-version: '18'
              registry-url: 'https://registry.npmjs.org'
          - run: npm ci
          - run: npm run build
          - run: npm run test
          - run: npm publish
            env:
              NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
    

    6. Оптимизация и производительность

    6.1 Анализ размера bundle

    # Анализ зависимостей
    npm ls
    
    # Размер пакета перед публикацией
    npm pack
    
    # Отчёт об использовании диска
    npm ls --depth=0
    
    # Поиск дублирующихся версий
    npm dedupe
    

    6.2 Виртуальные зависимости и workspaces

    # Инициализация монорепозитория
    npm init -w ./packages/package-a
    npm init -w ./packages/package-b
    

    root package.json:

    {
      "name": "my-monorepo",
      "private": true,
      "workspaces": [
        "packages/*"
      ]
    }
    

    Команды для workspaces:

    # Установка для всех workspaces
    npm install
    
    # Запуск скрипта для конкретного workspace
    npm run build -w ./packages/package-a
    
    # Добавление зависимости в workspace
    npm install lodash -w ./packages/package-a
    
    # Линк между internal пакетами автоматический
    

    6.3 Снижение размера установки

    # Production-only установка (без devDependencies)
    npm install --production
    
    # Чистка кэша
    npm cache clean --force
    
    # Деструктивная оптимизация (удаление дублей)
    npm dedupe --force
    
    # Игнорирование опциональных зависимостей
    npm install --no-optional
    

    7. Продвинутые техники

    7.1 npm scripts и автоматизация

    {
      "scripts": {
        "test": "jest",
        "test:watch": "jest --watch",
        "test:coverage": "jest --coverage",
        "prebuild": "npm run clean",
        "build": "tsc",
        "postbuild": "npm run test",
        "start": "node dist/index.js",
        "dev": "ts-node src/index.ts",
        "lint": "eslint src --fix",
        "format": "prettier --write 'src/**/*'",
        "precommit": "npm run lint && npm run test"
      }
    }
    

    Жизненный цикл скриптов:

    • pre{script} — выполняется перед скриптом
    • {script} — сам скрипт
    • post{script} — выполняется после скрипта

    7.2 Переменные окружения и конфигурация

    # npm-переменные доступны в скриптах через process.env
    npm_package_name
    npm_package_version
    npm_package_main
    
    # Передача переменных
    npm run build -- --production
    
    # Конфигурация через .npmrc
    npm-auth-token=abc123
    registry=https://registry.npmjs.org
    

    7.3 Работа с приватными пакетами

    .npmrc для приватного реестра:

    @myorg:registry=https://npm.pkg.github.com
    //npm.pkg.github.com/:_authToken=github_token
    

    Или переменная окружения:

    export NPM_TOKEN=your_token
    echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
    

    7.4 Версионирование и теги

    # Публикация на конкретный тег
    npm publish --tag experimental
    npm install my-package@experimental
    
    # Перемещение тега
    npm dist-tag add my-package@1.0.0 latest
    npm dist-tag rm my-package experimental
    
    # Просмотр всех тегов пакета
    npm dist-tag ls my-package
    

    8. Отладка и диагностика

    8.1 Логирование и verbose-режим

    # Подробный лог всех операций
    npm install --verbose
    
    # Максимальный уровень логирования
    npm --loglevel verbose install
    
    # Очистка логов
    npm cache clean --force
    
    # Проверка целостности установки
    npm audit
    npm audit fix
    

    8.2 Разрешение проблем с зависимостями

    # Поиск конфликтов peer-зависимостей
    npm ls
    
    # Принудительное переустановление
    npm ci  # clean install с lock-файла
    
    # Очистка node_modules
    rm -rf node_modules package-lock.json
    npm install
    
    # Диагностика проблем с путями
    npm config get prefix
    npm list -g
    
    # Удаление осиротевших пакетов
    npm prune
    npm prune --production
    

    8.3 Отладка хуков и скриптов

    # Просмотр всех конфигурированных скриптов
    npm run
    
    # Выполнение скрипта с максимальным логированием
    npm run build --verbose
    
    # Проверка конкретного хука (без фактического выполнения)
    npm run --dry-run postinstall
    
    # Просмотр переменных окружения доступных в скриптах
    npm run env
    

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

    При разработке библиотек:

    • Используйте exports для условных импортов вместо main
    • Поставляйте TypeScript definitions или используйте @types
    • Регулярно запускайте npm audit для проверки уязвимостей
    • Поддерживайте peerDependencies в актуальном состоянии
    • Используйте semantic versioning строго
    • Документируйте breaking changes в CHANGELOG
    • Автоматизируйте публикацию через CI/CD
    • Используйте prepublishOnly для финальной валидации перед публикацией
    • Используйте postinstall для инициализации необходимых ресурсов (Git хуки, компиляция нативного кода)

    При работе с зависимостями:

    • Регулярно обновляйте пакеты: npm update
    • Проверяйте уязвимости: npm audit
    • Используйте lock-файлы в version control
    • Минимизируйте количество зависимостей
    • Проверяйте лицензии: npm ls --depth=0
    • Избегайте использования postinstall в публичных пакетах если это не критично (замедляет установку)

    При локальной разработке:

    • Используйте npm link для синхронной разработки нескольких пакетов
    • Настройте правильные .npmignore и files поля
    • Тестируйте локально через npm pack перед публикацией
    • Используйте workspaces для монорепозиториев
    • Проверяйте выполнение хуков локально перед коммитом
    • Используйте npm run --dry-run для тестирования скриптов

    При настройке хуков:

    • Всегда заканчивайте postinstall скрипты успешно (exit code 0)
    • Избегайте долгих операций в postinstall (замедляют установку)
    • Используйте prepare вместо postinstall для более надёжного выполнения в различных сценариях
    • Используйте prepublishOnly для критических проверок перед публикацией
    • Документируйте, что делают ваши хуки в README
    • Тестируйте хуки в CI/CD среде перед публикацией

    Заключение

    npm — это мощный инструмент, который выходит далеко за пределы простой установки пакетов. Понимание системы жизненного цикла и хуков (особенно postinstall и prepublishOnly) позволяет автоматизировать критические операции и обеспечивает надёжное развертывание приложений. Для опытного разработчика овладение механизмами разрешения зависимостей, публикации собственных библиотек, настройки хуков и оптимизации рабочих процессов — критически важно для создания надёжных и масштабируемых проектов. Глубокое знание npm позволяет избежать множества типичных ошибок и значительно ускоряет разработку.

    1 ответ Последний ответ
    0

    Категории

    • Главная
    • Новости
    • Фронтенд
    • Бекенд
    • Языки программирования

    Контакты

    • Сотрудничество
    • info@exlends.com
    • Наш чат
    • Наш ТГ канал

    © 2024 - 2025 ExLends, Inc. Все права защищены.

    Политика конфиденциальности
    • Войти

    • Нет учётной записи? Зарегистрироваться

    • Войдите или зарегистрируйтесь для поиска.
    • Первое сообщение
      Последнее сообщение
    0
    • Лента
    • Категории
    • Последние
    • Метки
    • Популярные
    • Пользователи
    • Группы