Сегодня мы публикуем четвёртую часть перевода руководства по Node.js. В этом материале мы начнём разговор об npm а также рассмотрим особенности файлов package.json и package-lock.json.




Основы npm


Npm (node package manager) — это менеджер пакетов Node.js. В первой части этого материала мы уже упоминали о том, что сейчас в npm имеется более полумиллиона пакетов, что делает его самым большим в мире репозиторием кода, написанного на одном языке. Это позволяет говорить о том, что в npm можно найти пакеты, предназначенные для решения практически любых задач.

Изначально npm создавался как система управления пакетами для Node.js, но в наши дни он используется и при разработке фронтенд-проектов на JavaScript. Для взаимодействия с реестром npm используется одноимённая команда, которая даёт разработчику огромное количество возможностей.

▍Загрузка пакетов


С помощью команды npm можно загружать пакеты из реестра. Ниже мы рассмотрим примеры её использования.

▍Установка всех зависимостей проекта


Если в проекте имеется файл package.json, то установить все зависимости этого проекта можно такой командой:

npm install

Эта команда загрузит всё, что нужно проекту, и поместит эти материалы в папку node_modules, создав её в том случае, если она не существует в директории проекта.

▍Установка отдельного пакета


Отдельный можно установить следующей командой:

npm install <package-name>

Часто можно видеть, как эту команду используют не в таком вот простом виде, а с некоторыми флагами. Рассмотрим их:

  • Флаг --save позволяет установить пакет и добавить запись о нём в раздел dependencies файла package.json, который описывает зависимости проекта. Эти зависимости используются проектом для реализации его основного функционала, они устанавливаются в ходе его развёртывания на сервере (после выхода npm 5 записи об устанавливаемых пакетах в разделе зависимостей делаются автоматически, и без использования этого флага).
  • Флаг --save-dev позволяет установить пакет и добавить запись о нём в раздел, содержащий перечень зависимостей разработки (то есть — пакетов, которые нужны в ходе разработки проекта, вроде библиотек для тестирования, но не требуются для его работы) файла package.json, который называется devDependencies.

▍Обновление пакетов


Для обновления пакетов служит следующая команда:

npm update

Получив эту команду, npm проверит все пакеты на наличие их новых версий, и, если найдёт их новые в��рсии, соответствующие ограничениям на версии пакетов, заданным в package.json, установит их.

Обновить можно и отдельный пакет:

npm update <package-name>

▍Загрузка пакетов определённых версий


В дополнение к стандартной загрузке пакетов, npm поддерживает и загрузку их определённых версий. В частности, можно заметить, что некоторые библиотеки совместимы лишь с некими крупными релизами других библиотек, то есть, если бы зависимости таких библиотек устанавливались бы без учёта версий, это могло бы нарушить их работу. Возможность установить определённую версию некоего пакета полезна и в ситуациях, когда, например, вам вполне подходит самый свежий релиз этого пакета, но оказывается, что в нём имеется ошибка. Ожидая выхода исправленной версии пакета, можно воспользоваться и его более старым но стабильным релизом.

Возможность задавать конкретные версии необходимых проекту библиотек полезна в командной разработке, когда все члены команды пользуются в точности одними и теми же библиотеками. Переход на их новые версии так же осуществляется централизованно, путём внесения изменений в файл проекта package.json.

Во всех этих случаях возможность указания версий пакетов, необходимых проекту, чрезвычайно полезна. Npm следует стандарту семантического версионирования (semver).

▍Запуск скриптов


Файл package.json поддерживает возможность описания команд (скриптов), запускать которые можно с помощью такой конструкции:

npm <task-name>

Например, вот как выглядят перечень скриптов, имеющийся в соответствующем разделе файла:

{
  "scripts": {
    "start-dev": "node lib/server-development",
    "start": "node lib/server-production"
  }
}

Весьма распространено использование этой возможности для запуска Webpack:

{
  "scripts": {
    "watch": "webpack --watch --progress --colors --config webpack.conf.js",
    "dev": "webpack --progress --colors --config webpack.conf.js",
    "prod": "NODE_ENV=production webpack -p --config webpack.conf.js",
  }
}

Такой подход даёт возможность заменить ввод длинных команд, чреватый ошибками, следующими простыми конструкциями:

$ npm watch
$ npm dev
$ npm prod

▍Куда npm устанавливает пакеты?


При установке пакетов с использованием npm (или yarn) доступны два варианта устан��вки: локальная и глобальная.

По умолчанию, когда для установки пакета используют команду наподобие npm install lodash, пакет оказывается в папке node_modules, расположенной в папке проекта. Кроме того, если была выполнена вышеописанная команда, npm также добавит запись о библиотеке lodash в раздел dependencies файла package.json, который имеется в текущей директории.

Глобальная установка пакетов выполняется с использованием флага -g:

npm install -g lodash

Выполняя такую команду, npm не устанавливает пакет в локальную папку проекта. Вместо этого он копирует файлы пакета в некое глобальное расположение. Куда именно попадают эти файлы?

Для того чтобы это узнать, воспользуйтесь следующей командой:

npm root -g

В macOS или Linux файлы пакетов могут оказаться в директории /usr/local/lib/node_modules. В Windows это может быть нечто вроде C:\Users\YOU\AppData\Roaming\npm\node_modules.

Однако если вы используете для управления версиями Node.js nvm, путь к папке с глобальными пакетами может измениться.

Я, например, использую nvm, и вышеописанная команда сообщает мне о том, что глобальные пакеты устанавливаются по такому адресу: /Users/flavio/.nvm/versions/node/v8.9.0/lib/node_modules.

▍Использование и выполнение пакетов, установленных с помощью npm


Как использовать модули, установленные с помощью npm, локально или глобально, попадающие в папки node_modules? Предположим, вы установили популярную библиотеку lodash, содержащую множество вспомогательных функций, используемых в JavaScript-разработке:

npm install lodash

Такая команда установит библиотеку в локальную папку проекта node_modules.

Для того чтобы использовать её в своём коде, достаточно импортировать её с применением команды require:

const _ = require('lodash')

Как быть, если пакет представляет собой исполняемый файл?

В таком случае исполняемый файл попадёт в папку node_modules/.bin/ folder.

Посмотреть на то, как выглядит работа этого механизма можно, установив пакет cowsay. Он представляет собой шуточную программу, написанную для командной строки. Если передать этому пакету какой-нибудь текст, в консоли, в стиле ASCII-арта, будет выведено изображение коровы, которая «произносит» соответствующий текст. «Озвучивать» текст могут и другие существа.

Итак, после установки пакета с использованием команды npm install cowsay, он, вместе со своими зависимостями, попадёт в node_modules. А в скрытую папку .bin будут записаны символические ссылки на бинарные файлы cowsay.

Как их выполнять?

Конечно, можно, для вызова программы, ввести в терминале нечто вроде ./node_modules/.bin/cowsay, это рабочий подход, но гораздо лучше воспользоваться npx, средством для запуска исполняемых файлов npm-пакетов, включаемым в npm начиная с версии 5.2. А именно, в нашем случае понадобится такая команда:

npx cowsay

Путь к пакету npx найдёт автоматически.

Файл package.json


Файл package.json является важнейшим элеме��тов множества проектов, основанных на экосистеме Node.js. Если вы программировали на JavaScript, была ли это серверная или клиентская разработка, то вы, наверняка, уже встречались с этим файлом. Зачем он нужен? Что вам следует о нём знать и какие возможности он вам даёт?

Package.json представляет собой нечто вроде файла-манифеста для проекта. Он даёт в распоряжение разработчика множество разноплановых возможностей. Например, он представляет собой центральный репозиторий настроек для инструментальных средств, используемых в проекте. Кроме того, он является тем местом, куда npm и yarn записывают сведения об именах и версиях установленных пакетов.

▍Структура файла


Вот пример простейшего файла package.json:

{
}

Как видите, он пуст. Нет жёстких требований, касающихся того, что должно присутствовать в подобном файле для некоего приложения. Единственное требование к структуре файла заключается в том, что она должна следовать правилам формата JSON. В противном случае этот файл не сможет быть прочитан программами, которые попытаются получить доступ к его содержимому.

Если вы создаёте Node.js-пакет, который собираетесь распространять через npm, то всё радикальным образом меняется, и в вашем package.json должен быть набор свойств, которые помогут другим людям пользоваться пакетом. Подробнее мы поговорим об этом позже.

Вот ещё один пример package.json:

{
  "name": "test-project"
}

В нём задано свойство name, значением которого является имя приложения или пакета, материалы которого содержатся в той же папке, где находится этот файл.

Вот пример посложнее, который я взял из приложения-примера, написанного с использованием Vue.js:

{
  "name": "test-project",
  "version": "1.0.0",
  "description": "A Vue.js project",
  "main": "src/main.js",
  "private": true,
  "scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "unit": "jest --config test/unit/jest.conf.js --coverage",
    "test": "npm run unit",
    "lint": "eslint --ext .js,.vue src test/unit",
    "build": "node build/build.js"
  },
  "dependencies": {
    "vue": "^2.5.2"
  },
  "devDependencies": {
    "autoprefixer": "^7.1.2",
    "babel-core": "^6.22.1",
    "babel-eslint": "^8.2.1",
    "babel-helper-vue-jsx-merge-props": "^2.0.3",
    "babel-jest": "^21.0.2",
    "babel-loader": "^7.1.1",
    "babel-plugin-dynamic-import-node": "^1.2.0",
    "babel-plugin-syntax-jsx": "^6.18.0",
    "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
    "babel-plugin-transform-runtime": "^6.22.0",
    "babel-plugin-transform-vue-jsx": "^3.5.0",
    "babel-preset-env": "^1.3.2",
    "babel-preset-stage-2": "^6.22.0",
    "chalk": "^2.0.1",
    "copy-webpack-plugin": "^4.0.1",
    "css-loader": "^0.28.0",
    "eslint": "^4.15.0",
    "eslint-config-airbnb-base": "^11.3.0",
    "eslint-friendly-formatter": "^3.0.0",
    "eslint-import-resolver-webpack": "^0.8.3",
    "eslint-loader": "^1.7.1",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-vue": "^4.0.0",
    "extract-text-webpack-plugin": "^3.0.0",
    "file-loader": "^1.1.4",
    "friendly-errors-webpack-plugin": "^1.6.1",
    "html-webpack-plugin": "^2.30.1",
    "jest": "^22.0.4",
    "jest-serializer-vue": "^0.3.0",
    "node-notifier": "^5.1.2",
    "optimize-css-assets-webpack-plugin": "^3.2.0",
    "ora": "^1.2.0",
    "portfinder": "^1.0.13",
    "postcss-import": "^11.0.0",
    "postcss-loader": "^2.0.8",
    "postcss-url": "^7.2.1",
    "rimraf": "^2.6.0",
    "semver": "^5.3.0",
    "shelljs": "^0.7.6",
    "uglifyjs-webpack-plugin": "^1.1.1",
    "url-loader": "^0.5.8",
    "vue-jest": "^1.0.2",
    "vue-loader": "^13.3.0",
    "vue-style-loader": "^3.0.1",
    "vue-template-compiler": "^2.5.2",
    "webpack": "^3.6.0",
    "webpack-bundle-analyzer": "^2.9.0",
    "webpack-dev-server": "^2.9.1",
    "webpack-merge": "^4.1.0"
  },
  "engines": {
    "node": ">= 6.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}

Как видите, тут прямо-таки немеряно всего интересного. А именно, здесь можно выделить следующие свойства:

  • name — задаёт имя приложения (пакета).
  • version — содержит сведения о текущей версии приложения.
  • description — краткое описание приложения.
  • main — задаёт точку входа в приложение.
  • private — если данное свойство установлено в true, это позволяет предотвратить случайную публикацию пакета в npm.
  • scripts — задаёт набор Node.js-скриптов, которые можно запускать.
  • dependencies — содержит список npm-пакетов, от которых зависит приложение.
  • devDependencies — содержит список npm-пакетов, используемых при разработке проекта, но не при его реальной работе.
  • engines — задаёт список версий Node.js, на которых работает приложение.
  • browserlist — используется для хранения списка браузеров (и их версий), которые должно поддерживать приложение.

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

▍Свойства, используемые в package.json


Поговорим о свойствах, которые можно использовать в package.json. Здесь мы будем использовать термин «пакет», но всё, что сказано о пакетах, справедливо и для локальных приложений, которые не планируется использовать в роли пакетов.

Большинство свойств, которые мы опишем, используются лишь для нужд репозитория npm, некоторые используются программами, которые взаимодействуют с кодом, вроде того же npm.

Свойство name


Свойство name задаёт имя пакета:

"name": "test-project"

Имя должно быть короче 214 символов, не должно включать в себя пробелы, должно состоять только из прописных букв, дефисов (-) и символов подчёркивания (_).

Подобные ограничения существуют из-за того, что когда пакет публикуется в npm, его имя используется для формирования URL страницы пакета.

Если вы публиковали код пакета на GitHub, в общем доступе, то хорошим вариантом имени пакета является имя соответствующего GitHub-репозитория.

Свойство author


Свойство author содержит сведения об авторе пакета:

{
  "author": "Flavio Copes <flavio@flaviocopes.com> (https://flaviocopes.com)"
}

Оно может быть представлено и в таком формате:

{
  "author": {
    "name": "Flavio Copes",
    "email": "flavio@flaviocopes.com",
    "url": "https://flaviocopes.com"
  }
}

Свойство contributors


Свойство contributors содержит массив со сведениями о людях, внёсших вклад в проект:

{
  "contributors": [
    "Flavio Copes <flavio@flaviocopes.com> (https://flaviocopes.com)"
  ]
}

Это свойство может выглядеть и так:

{
  "contributors": [
    {
      "name": "Flavio Copes",
      "email": "flavio@flaviocopes.com",
      "url": "https://flaviocopes.com"
    }
  ]
}

Свойство bugs


В свойстве bugs содержится ссылка на баг-трекер проекта, весьма вероятно то, что такая ссылка будет вести на страницу системы отслеживания ошибок GitHub:

{
  "bugs": "https://github.com/flaviocopes/package/issues"
}

Свойство homepage


Свойство homepage позволяет задать домашнюю страницу пакета:

{
  "homepage": "https://flaviocopes.com/package"
}

Свойство version


Свойство version содержит сведения о текущей версии пакета:

"version": "1.0.0"

При формировании значения этого свойства нужно следовать правилам семантического версионирования. Это означает, в частности, что номер версии всегда представлен тремя цифрами: x.x.x.

Первое число — это мажорная версия пакета, второе — минорная версия, третье — патч-версия.

Изменение этих чисел несёт в себе определённый смысл. Так, релиз пакета, в котором лишь исправляются ошибки, приводит к увеличению значения патч-версии. Если выходит релиз пакета, изменения, внесённые в который, отличаются обратной совместимостью с предыдущим релизом — то меняется минорная версия. В мажорных версиях пакетов могут присутствовать изменения, которые делают эти пакеты несовместимыми с пакетами предыдущих мажорных версий.

Свойство license


Свойство license содержит сведения о лицензии пакета:

"license": "MIT"

Свойство keywords


Свойство keywords содержит массив ключевых слов, имеющих отношение к функционалу пакета:

"keywords": [
  "email",
  "machine learning",
  "ai"
]

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

Свойство description


Свойство description содержит краткое описание пакета:

"description": "A package to work with strings"

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

Свойство repository


Свойство repository указывает на то, где находится репозиторий пакета:

"repository": "github:flaviocopes/testing",

Обратите внимание, что у значения этого свойства имеется префикс github. Npm поддерживает префиксы и для некоторых других популярных сервисов подобного рода:

"repository": "gitlab:flaviocopes/testing",
"repository": "bitbucket:flaviocopes/testing",

Используемую при разработке пакета систему контроля версий можно задать и в явном виде:

"repository": {
  "type": "git",
  "url": "https://github.com/flaviocopes/testing.git"
}

Один и тот же пакет может использовать разные системы контроля версий:

"repository": {
  "type": "svn",
  "url": "..."
}

Свойство main


Свойство main задаёт точку входа в пакет:

"main": "src/main.js"

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

Сво��ство private


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

"private": true

Свойство scripts


Свойство scripts задаёт список скриптов или утилит, которые можно запускать средствами npm:

"scripts": {
  "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
  "start": "npm run dev",
  "unit": "jest --config test/unit/jest.conf.js --coverage",
  "test": "npm run unit",
  "lint": "eslint --ext .js,.vue src test/unit",
  "build": "node build/build.js"
}

Эти скрипты являются приложениями командной строки. Запускать их можно с помощью npm или yarn, выполняя, соответственно, команды вида npm run XXXX или yarn XXXX, где XXXX — имя скрипта. Например, выглядеть это может так:

npm run dev

Скрипты можно называть так, как вам хочется, делать они могут практически всё, чего может пожелать разработчик.

Свойство dependencies


Свойство dependencies содержит список npm-пакетов, установленных в виде зависимостей пакета:

"dependencies": {
  "vue": "^2.5.2"
}

При установке пакета с использованиеме npm или yarn используются команды такого вида:

npm install <PACKAGENAME>
yarn add <PACKAGENAME>

Эти пакеты автоматически добавляются в список зависимостей разрабатываемого пакета.

Свойство devDependencies


Свойство devDependencies содержит список npm-пакетов, установленных как зависимости разработки:

"devDependencies": {
  "autoprefixer": "^7.1.2",
  "babel-core": "^6.22.1"
}

Этот список отличается от того, который хранится в свойстве dependencies, так как имеющиеся в нём пакеты устанавливаются лишь в системе разработчика пакета, при практическом использовании пакета они не применяются.

Пакеты попадают в этот список при их установке с помощью npm или yarn, выполняемой следующим образом:

npm install --dev <PACKAGENAME>
yarn add --dev <PACKAGENAME>

Свойство engines


Свойство engines указывает, какие версии Node.js и других программных продуктов используются для обеспечения работы пакета:

"engines": {
  "node": ">= 6.0.0",
  "npm": ">= 3.0.0",
  "yarn": "^0.13.0"
}

Свойство browserlist


Свойство browserlist позволяет сообщить о том, какие браузеры (и их версии) собирается поддерживать разработчик пакета:

"browserslist": [
  "> 1%",
  "last 2 versions",
  "not ie <= 8"
]

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

Показанное здесь в качестве примера значение свойства browserlist означает, что вы хотите поддерживать как минимум 2 мажорные версии всех браузеров с как минимум 1% использования (эти данные берутся с ресурса CanIUse.com), за исключением IE 8 и более старых версий этого браузера (подробнее об этом можно узнать на странице пакета browserlists).

▍Хранение в package.json настроек для различных программных инструментов


В package.json можно хранить настройки для различных вспомогательных инструментов вроде Babel или ESLint.

Каждому из таких инструментов соответствует особое свойство, наподобие eslintConfig или babel. Подробности об использовании подобных свойств можно найти в документации соответствующих проектов.

▍О версиях пакетов и семантическом версионировании


В вышеприведённых примерах вы могли видеть, что номера версий пакетов задаются не только в виде обычных чисел, разделённых точками, но и с использованием неких специальных символов. Например, в виде ~3.0.0 или ^0.13.0. Здесь использованы так называемые спецификаторы версий, которые определяют диапазон версий пакетов, подходящих для использования в нашем пакете.

Учитывая то, что при использовании семантического версионирования все номера версий пакетов состоят из последовательностей, представляющих собой три числа, о смысле которых мы говорили выше, опишем следующие правила использования спецификаторов версий:

  • ~: если вы задаёте версию в виде ~0.13.0 это означает, что вас интересуют лишь патч-релизы пакета. То есть, пакет 0.13.1 вам подойдёт, а 0.14.0 — нет.
  • ^: если номер версии задан в виде ^0.13.0, это означает, что вам подходят новые патч-версии и минорные версии пакета. То есть, вас устроят версии пакета 0.13.1, 0.14.0, и так далее.
  • *: воспользовавшись этим символом, вы сообщаете системе, что вас устроят любые свежие версии пакета, в том числе — его новые мажорные релизы.
  • >: подходят любые версии пакета, которые больше заданной.
  • >=: подходят любые версии пакета, которые равны или больше заданной.
  • <=: вас устроят пакеты, версии которых равны заданной или меньше её.
  • <: вас интересуют пакеты, версии которых меньше заданной.
  • =: вам нужна только заданная версия пакета.
  • -: используется для указания диапазона подходящих версий, например — 2.1.0 - 2.6.2.
  • ||: позволяет комбинировать наборы условий, касающихся пакетов. Например это может выглядеть как < 2.1 || > 2.6.

Есть и ещё некоторые правила:

  • отсутствие дополнительных символов: если используется номер версии пакета без дополнительных символов, это значит, что вашему пакету нужна только заданная версия пакета-зависимости и никакая другая.
  • latest: указывает на то, что вам требуется самая свежая версия некоего пакета.

Большинство вышеописанных спецификаторов можно комбинировать, например, задавая диапазоны подходящих версий пакетов-зависимостей. Скажем, конструкция вида 1.0.0 || >=1.1.0 <1.2.0 указывает на то, что планируется использовать либо версию пакета 1.0.0, либо версию, номер которой больше или равен 1.1.0, но меньше 1.2.0.

Файл package-lock.json


Файл package-lock.json используется с момента появления npm версии 5. Он создаётся автоматически при установке Node.js-пакетов. Что это за файл? Возможно, вы не знакомы с ним даже если знали о package.json, который существует гораздо дольше него.

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

Этот файл решает весьма специфическую проблему, которая не решается средствами package.json. В package.json можно указать, какие обновления некоего пакета вам подходят (патч-версии или минорные версии) с использованием вышеописанных спецификаторов версий.

В Git не коммитят папку node_modules, так как обычно она имеет огромные размеры. Когда вы пытаетесь воссоздать проект на другом компьютере, то использование команды npm install приведёт к тому, что, если, при использовании спецификатора ~ в применении к версии некоего пакета, вышел его патч-релиз, установлен будет не тот пакет, который использовался при разработке, а именно этот патч-релиз.

То же самое касается и спецификатора ^. Если же при указании версии пакета спецификаторы не использовались, то будет установлена именно его указанная версия и проблема, о которой идёт речь, окажется в такой ситуации неактуальной.

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

Файл package-lock.json хранит в неизменном виде сведения о версии каждого установленного пакета и npm будет использовать именно эти версии пакетов при выполнении команды npm install.

Эта концепция не нова, менеджеры пакетов, применяемые в других языках программирования (вроде менеджера Composer в PHP) используют похожую систему многие годы.

Файл package-lock.json нужно отправить в Git-репозиторий, что позволит другим людям скачать его в том случае, если проект является общедоступным, или тогда, когда его разработкой занимается команда программистов, или если вы используете Git для развёртывания проекта.

Версии зависимостей будут обновлены в package-lock.json после выполнения команды npm update.

▍Пример файла package-lock.json


В этом примере продемонстрирована структура файла package-lock.json, который входит в состав пакет cowsay, устанавливаемого в пустой папке командой npm install cowsay:

{
  "requires": true,
  "lockfileVersion": 1,
  "dependencies": {
    "ansi-regex": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.
0.0.tgz",
      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
    },
    "cowsay": {
      "version": "1.3.1",
      "resolved": "https://registry.npmjs.org/cowsay/-/cowsay-1.3.1.tgz"
,
      "integrity": "sha512-3PVFe6FePVtPj1HTeLin9v8WyLl+VmM1l1H/5P+BTTDkM
Ajufp+0F9eLjzRnOHzVAYeIYFF5po5NjRrgefnRMQ==",
      "requires": {
        "get-stdin": "^5.0.1",
        "optimist": "~0.6.1",
        "string-width": "~2.1.1",
        "strip-eof": "^1.0.0"
      }
    },
    "get-stdin": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.
1.tgz",
      "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g="
    },
    "is-fullwidth-code-point": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/
is-fullwidth-code-point-2.0.0.tgz",
      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
    },
    "minimist": {
      "version": "0.0.10",
      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10
.tgz",
      "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
    },
    "optimist": {
      "version": "0.6.1",
      "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
      "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
      "requires": {
        "minimist": "~0.0.1",
        "wordwrap": "~0.0.2"
      }
    },
    "string-width": {
      "version": "2.1.1",
      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
      "requires": {
        "is-fullwidth-code-point": "^2.0.0",
        "strip-ansi": "^4.0.0"
      }
    },
    "strip-ansi": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
      "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
      "requires": {
        "ansi-regex": "^3.0.0"
      }
    },
    "strip-eof": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
      "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
    },
    "wordwrap": {
      "version": "0.0.3",
      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
      "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
    }
  }
}

Разберём этот файл. Мы устанавливаем пакет cowsay, который зависит от следующих пакетов:

  • get-stdin
  • optimist
  • string-width
  • strip-eof

Эти пакеты, в свою очередь, зависят от других пакетов, сведения о которых мы можем почерпнуть из свойств requires, которые имеются у некоторых из них:

  • ansi-regex
  • is-fullwidth-code-point
  • minimist
  • wordwrap
  • strip-eof

Они добавляются в файл в алфавитном порядке, у каждого есть поле version, есть поле resolved, указывающее на расположение пакета, и строковое свойство integrity, которое можно использовать для проверки целостности пакета.

Итоги


Сегодня мы начали разговор об npm и разобрались со структурой и назначением файлов package.json и package-lock.json. В следующий раз продолжим разбирать возможности npm и коснёмся использования npx.

Уважаемые читатели! Какой менеджер пакетов вы предпочитаете — npm или yarn?