Npm — это инструмент управления пакетами, широко используемый фронтенд-разработчиками. Проект использует package.json для управления конфигурацией пакетов npm, от которых зависит проект. package.json — это файл json. Помимо возможности описания зависимостей пакетов проекта, он позволяет нам использовать «семантические правила версии» для указания версии зависимых пакетов вашего проекта, чтобы вашей сборкой можно было лучше поделиться с другими разработчиками и повторно использовать.

Эта статья в основном начинается с недавней практики в сочетании с последними версиями npm и node, представляет некоторые общие конфигурации в package.json и как написать стандартизированный package.json.

  • пакет.json
  • общие свойства package.json
  • Свойства, связанные со средой package.json
  • Свойства, связанные с зависимостями package.json
  • Трехсторонний атрибут package.json

пакет.json

Введение в package.json

В проекте nodejs package.json — это файл конфигурации, который управляет его зависимостями. Обычно, когда мы инициализируем проект nodejs, мы передаем:

npm init

Затем в вашем каталоге будут созданы 3 каталога/файла: node_modules, package.json и package.lock.json. Содержимое package.json:

{
    "name": "Your project name",
    "version": "1.0.0",
    "description": "Your project description",
    "main": "app.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
    },
    "author": "Author name",
    "license": "ISC",
    "dependencies": {
        "dependency1": "^1.4.0",
        "dependency2": "^1.5.2"
    }
}

Как видно из вышеизложенного, package.json содержит метаданные самого проекта, а также информацию о зависимостях проекта (например, зависимости и т. д.).

пакет-lock.json

Мы обнаружили, что при инициализации npm генерируется не только файл package.json, но и файл package-lock.json. Так почему же необходимо генерировать файл package-lock.json, когда package.json очищен? По сути, файл package-lock.json предназначен для блокировки версии. Пакет sub-npm, указанный в package.json, например: react: «¹⁶.0.0», в фактической установке, если версия выше, чем react, удовлетворяет требованиям package.json. Таким образом, в соответствии с одним и тем же файлом package.json, не может быть гарантирована согласованность версий зависимостей двух установок.

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

{
    "name": "Your project name",
    "version": "1.0.0",
    "lockfileVersion": 1,
    "requires": true,
    "dependencies": {
        "dependency1": {
            "version": "1.4.0",
            "resolved": 
"https://registry.npmjs.org/dependency1/-/dependency1-1.4.0.tgz",
            "integrity": 
"sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="
        },
        "dependency2": {
            "version": "1.5.2",
            "resolved": 
"https://registry.npmjs.org/dependency2/-/dependency2-1.5.2.tgz",
            "integrity": 
"sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ=="
        }
    }
}

общие свойства package.json

В этой главе мы поговорим о часто используемых атрибутах конфигурации в package.json. Такие атрибуты, как имя и версия, слишком просты, чтобы вводить их по одному. В этой главе в основном представлены атрибуты script, bin и workspaces.

сценарий

Используйте теги сценариев в npm для определения сценариев. Всякий раз, когда указан запуск npm, сценарий оболочки будет создан автоматически. Здесь следует отметить, что новая оболочка, созданная с помощью npm run, сохранит подкаталог node_modules/.bin локального каталога. Добавьте переменную PATH.

Это означает, что все скрипты в подкаталоге node_modules/.bin текущего каталога могут вызываться напрямую с именем скрипта без добавления пути. Например, если в зависимостях текущего проекта есть esbuild, просто напишите напрямую esbuild xxx.

{
  // ...
  "scripts": {
    "build": "esbuild index.js",
  }
}
{
  // ...
  "scripts": {
    "build": "./node_modules/.bin/esbuild index.js" 
  }
}

Вышеупомянутые два способа написания эквивалентны.

мусорные ведра

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

For example, the npm package of \@bytepack/cli:
"bin": {
    "bytepack": "./bin/index.js"
 },

После глобальной установки @bytepack/cli вы можете выполнять соответствующие команды непосредственно через bytepack, например

bytepack -v
//show 1.11.0

Если он не установлен глобально, он будет автоматически подключен к каталогу node_module/.bin проекта. В соответствии с тем, что было сказано в теге script, представленном ранее, его можно использовать непосредственно с псевдонимом.

рабочие пространства

Когда проект слишком велик, монорепозиторий в последнее время становится все более популярным. Когда дело доходит до монорепозитория, мы не хотим смотреть на рабочие пространства. В первые дни мы использовали рабочие области пряжи. Теперь npm официально поддерживает рабочие пространства. Workspaces решает проблему управления несколькими подпакетами в корневом пакете верхнего уровня в локальной файловой системе. В каталоге объявления рабочих областей пакет будет связан с node_modules корневого пакета верхнего уровня.
Непосредственно используйте пример официального веб-сайта, чтобы проиллюстрировать:

{
  "name": "my-project",
  "workspaces": [
    "packages/a"
  ]
}

В пакете npm с именем my-project есть каталог конфигурации рабочих пространств.

.
+-- package.json
+-- index.js
`-- packages
   +-- a
   |  `-- package.json

И самый верхний корневой пакет с именем my-project имеет пакеты/подпакет. На этом этапе, если мы устанавливаем npm, то пакет npm a, установленный в node_modules в корневом пакете, указывает на локальный package/a.

.
+-- node_modules
|  `-- packages/a -> ../packages/a
+-- package-lock.json
+-- package.json
`-- packages
   +-- a
   |   `-- package.json

вышеупомянутый

-- packages/a -> ../packages/a

Относится к программной ссылке из ссылки в node_modules на локальный пакет npm.

Свойства, связанные со средой package.json

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

  • Среда браузера: например, есть некоторые глобальные переменные, которые существуют только в браузере, такие как окно, документ и т. д.
  • Среда узла: в исходном файле пакета npm есть некоторые переменные, встроенные пакеты и встроенные функции, которые существуют только в среде узла.

тип

Модульная спецификация js включает модули commonjs, CMD, UMD, AMD, ES и т. д. Самая ранняя поддержка в узле — это только поле commonjs, но, начиная с node13.2.0, узел официально поддерживает спецификацию модуля ES в пакете. В json поле типа можно использовать для объявления модульной спецификации, которой следует пакет npm.

//package.json
{
   name: "some package",
   type: "module"||"commonjs" 
}

нужно знать, это:

  • Если тип не указан, значением по умолчанию для типа является commonjs, но рекомендуется, чтобы все пакеты npm указывали тип
  • Когда заданное значение поля типа является модулем, принимается спецификация ESModule.
  • Когда указано поле типа, все файлы, заканчивающиеся суффиксом .js в каталоге, следуют модульной спецификации, указанной типом.
  • В дополнение к типу, который может указывать модульную спецификацию, модульная спецификация, которой следует файл, определяется суффиксом файла. Файл, заканчивающийся на .mjs, является используемой спецификацией ESModule, а файл, заканчивающийся на .cjs, соответствует спецификации commonjs.

основной и модуль и браузер

В дополнение к типу в package.json есть три поля: main, module и browser, для определения входного файла пакета npm.

  • main : определяет входной файл пакета npm, который можно использовать как в среде браузера, так и в среде узла.
  • модуль: входной файл спецификации ESM, который определяет пакет npm, можно использовать как среду браузера, так и среду узла.
  • browser : определите файл входа пакета npm в среде браузера.

Давайте посмотрим на сценарии использования этих 3 полей и приоритет, когда эти 3 поля существуют одновременно. Мы предполагаем, что есть пакет npm demo1,

----- dist
   |-- index.browser.js
   |-- index.browser.mjs
   |-- index.js
   |-- index.mjs

Три поля main, module и browser указаны в его package.json одновременно.

"main": "dist/index.js",  // main 
  "module": "dist/index.mjs", // module
// browser can be defined as a mapping object that corresponds to the main/module field one-to-one, or it can be directly defined as a string
  "browser": {
    "./dist/index.js": "./dist/index.browser.js", // browser+cjs
    "./dist/index.mjs": "./dist/index.browser.mjs"  // browser+mjs
  },
  // "browser": "./dist/index.browser.js" // browser

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

import demo from 'demo'

После сборки приведенного выше кода с помощью инструмента сборки последовательность загрузки модуля следующая: _ браузер+mjs › модуль › браузер+cjs › main _ Эта последовательность загрузки является последовательностью загрузки по умолчанию для большинства инструментов сборки, таких как как webapck, esbuild и т. д. Этот порядок загрузки можно изменить с помощью соответствующей конфигурации, но в большинстве случаев мы по-прежнему будем следовать порядку загрузки по умолчанию.

экспорт

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

{
  "name": "pkg",
  "exports": {
    ".": "./main.mjs",
    "./foo": "./foo.js"
  }
}
import { something } from "pkg"; // from "pkg/main.mjs"
const { something } = require("pkg/foo"); // require("pkg/foo.js")

В приведенном выше примере экспорт может определять экспорт различных путей. Если есть экспорты, ранее действующий файловый каталог будет недействителен везде, например, require(‘pkg/package.json’), так как он не указан в экспорте, он сообщит об ошибке. Еще одна важная особенность экспорта — условные ссылки. Например, мы можем указать пакеты npm для ссылки на разные файлы записей в соответствии с разными методами ссылок или модульными типами.

// package.json
{ 
  "name":"pkg",
  "main": "./main-require.cjs",
  "exports": {
    "import": "./main-module.js",
    "require": "./main-require.cjs"
  },
  "type": "module"
}

В приведенном выше примере, если мы передаем

const p = require('pkg')

Ссылка «./main-require.cjs». Если прошло:

import p from 'pkg'

Ссылка «./main-module.js». И последнее, на что следует обратить внимание: если есть атрибут экспорта, атрибут экспорта не только имеет более высокий приоритет, чем основной, но и более высокий, чем поля модуля и браузера.

Свойства, связанные с зависимостями package.json

Свойства конфигурации, связанные с зависимостями, в package.json включают зависимости, devDependencies, peerDependencies и peerDependenciesMeta.

Зависимости — это зависимости проекта, а devDependencies — это модули, необходимые для разработки, поэтому мы можем установить то, что нам нужно в процессе разработки, чтобы повысить эффективность нашей разработки. Здесь следует отметить, что вы должны использовать его как стандарт в своем собственном проекте, например, webpack, babel и т. д., которые являются зависимостями разработки, а не зависимостями самого проекта, и их не следует помещать в зависимости.

Помимо зависимостей и devDependencies, в этой статье основное внимание уделяется peerDependencies и peerDependenciesMeta.

одноранговые зависимости

peerDependencies — это зависимость в package.json, которая может решить проблему многократной загрузки основной библиотеки и унификации версии основной библиотеки.

//package/pkg
----- node_modules
   |-- npm-a -> rely react,react-dom
   |-- npm-b -> rely react,react-dom
   |-- index.js

Например, в приведенном выше примере, если пакеты sub-npm a и b получены из react и react-dom, если мы объявим PeerDependencies в package.json пакетов sub-npm a и b, соответствующие зависимости не будут переустановлены. . Следует отметить два момента:

  • Для пакета sub-npm a в npm7, если sub-npm a установлен отдельно, будут установлены пакеты в его peerDependencies. Но это не будет работать до npm7.
  • Укажите стандартизированную и подробную конфигурацию PeerDependencies. Я вижу некоторые библиотеки компонентов реакции, которые не указывают реакцию и реакцию-дом в PeerDependencies или помещают реакцию и реакцию-дом в зависимости. Эти две нестандартные спецификации будут существовать. некоторые проблемы.
  • Во-вторых, правильно укажите версию пакета npm в PeerDependencies, react-focus-lock\@2.8.1[1] , peerDependencies укажите: «реагировать»: «¹⁶.8.0 || ^17.0.0 || ^ 18.0.0», но на самом деле этот react-focus-lock не поддерживает 18.x react

peerDependenciesMeta

Видеть «Мета» означает метаданные. Здесь peerDependenciesMeta предназначена для детального изменения peerDependencies. Например, в package.json в npm-пакете react-redux есть такой абзац:

"peerDependencies": {
    "react": "^16.8.3 || ^17 || ^18"
  },
 "peerDependenciesMeta": {
    "react-dom": {
      "optional": true
    },
    "react-native": {
      "optional": true
    }
  }

Здесь «react-dom» и «react-native» указаны в peerDependenciesMeta и являются необязательными, поэтому, если проект обнаружит, что «react-dom» и «react-native» не установлены, об ошибке не будет сообщено.

Стоит отметить, что через peerDependenciesMeta мы действительно сняли ограничение, но часто бывают сценарии, где используется либо A, либо B. Например, в приведенном выше примере нам нужны «react-dom» и «react-native». Его нужно установить, но на самом деле из-за приведенного выше утверждения мы не можем реализовать это приглашение.

Трехсторонний атрибут package.json

В package.json также есть много трехсторонних атрибутов, таких как типы, используемые в tsc, sideEffects, используемые в инструментах сборки, husky, используемый в git, eslintIgnore, используемый в eslint, эти расширенные конфигурации имеют значение для конкретных инструментов разработки. Не приводить примеры по одному. один









Дополнительные материалы на PlainEnglish.io.

Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .