# npm 是什么

npm 是 Node.js 的包管理工具,Node.js package manger,通过 npm Node.js 可以方便地使用第三方开发的开源模块,同时也可以把自己的模块发布到 npm 供其它开发者使用。

npm 主要由三部分组成:

  1. npm website:https://npmjs.com,开发者查找发现 package 的站点
  2. CLI(命令行):开发者可以使用命令行工具和 npm 进行交互,对 package 进行安装、更新、删除等操作
  3. registry(注册表):package 及其元信息存储的数据库

注册表是一个巨大的数据库,保存了每个包(package)的信息。
例如我们要查询 vue 包的信息,可以访问 https://registry.npmjs.org/vue,就会看到 vue 模块所有版本的信息。
模块名后面,还可以跟上版本号或者标签,用来查询某个具体版本的信息,例如:https://registry.npmjs.org/vue/3.0.0 查看 vue 3.0.0 版本的信息
具体用法就是, https://registry.npmjs.org/模块名/版本号

# yarn

yarn 是 Facebook 2017 年推出的和 npm 功能类似的包管理工具,主要解决当时 npm 的几个核心问题

  1. 安装包不够快速与稳定
  2. 存在安全隐患

同时 yarn 的 cli 工具提供了更简单的命令,当然面对 yarn 带来的压力,npm 在 5.0 后提供了类似的改进,两者现在差距不再巨大,开发者可以根据个人习惯和项目规范自由选择(我个人更喜欢使用 yarn)

# npx

npm 从 5.2 版本开始,增加了 npx 命令,npx 想要解决的主要问题,就是调用项目内部安装的模块。原理很简单,就是运行的时候,会到 node_modules/.bin 路径和环境变量 $PATH 里面,检查命令是否存在;如果存在,则执行;不存在,则进行临时安装,然后执行,执行完毕后将包删除。

对 npx 的详细介绍见 npx 使用教程

# package.json

npm 通过 Node.js 模块根目录的 package.json 文件获取模块元数据和依赖关系等,例如 react 的 package.json 包含如下信息

可以通过 npm init -y 或者 yarn init -y 生成一份默认的 package.json 配置

react 的 package.json
{
  "name": "react",
  "description": "React is a JavaScript library for building user interfaces.",
  "keywords": [
    "react"
  ],
  "version": "17.0.3",
  "homepage": "https://reactjs.org/",
  "bugs": "https://github.com/facebook/react/issues",
  "license": "MIT",
  "files": [
    "LICENSE",
    "README.md",
    "build-info.json",
    "index.js",
    "cjs/",
    "umd/",
    "jsx-runtime.js",
    "jsx-dev-runtime.js",
    "unstable-shared-subset.js"
  ],
  "main": "index.js",
  "exports": {
    ".": {
      "react-server": "./unstable-shared-subset.js",
      "default": "./index.js"
    },
    "./index": {
      "react-server": "./unstable-shared-subset.js",
      "default": "./index.js"
    },
    "./build-info.json": "./build-info.json",
    "./jsx-runtime": "./jsx-runtime.js",
    "./jsx-dev-runtime": "./jsx-dev-runtime.js",
    "./": "./"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/facebook/react.git",
    "directory": "packages/react"
  },
  "engines": {
    "node": ">=0.10.0"
  },
  "dependencies": {
    "loose-envify": "^1.1.0",
    "object-assign": "^4.1.1"
  },
  "browserify": {
    "transform": [
      "loose-envify"
    ]
  }
}

# name

name 是模块的唯一标识,安装、使用模块都需要使用模块的 name,可以使用字母(只能使用小写字母)、数字、 _-. ,例如安装和使用 vue 需要用到如下命令

yarn add vue
import {inject, Ref} from 'vue'

可以通过 scope 组织具有相关性的模块,模块名义 @ 开头的包就是一个 scoped package,scope 就是 @/ 之间的内容

@scope/project-name

例如 @antv/g2plot

# version

版本号遵从语义化版本规范,使用 x.y.z 形式,对应 主版本.次版本.修订版本 ,版本号递增规则如下:

  1. 主版本(major):当你做了不兼容的 API 修改,一般改动很大,不兼容低版本
  2. 次版本(minor):当你做了向下兼容的功能性新增,兼容同一个大版本的 API 和用法
  3. 修订版本(patch):当你做了向下兼容的问题修正,一般用来修复 bug

# 先行版本

x.y.z 格式是模块正式版本,重要模块为了保证稳定,会在放出正式版本之前提供先行版本

  • alpha: 内部版本
  • beta: 公测版本
  • rc: Release candidate,正式版本的候选版本
  • stable: 稳定版
  • csp

例:npm 上 vue 部分版本记录

这种特殊版本除非开发者精确声明使用,例如 npm install vue@3.0.0-rc.13 ,否则 npm install 不会自动安装对应版本内容

# 快捷命令

npm 提供了快捷升级命令

  • 升级主版本号: npm version major
  • 升级次版本号: npm version minor
  • 升级修订版本号: npm version patch
  • 设置版本号为指定的版本号: npm version 版本号
  • 升级先行版本号: npm version prerelease
  • 升级先行版本号并指定先行版本的名字: npm version prerelease --preid=<prerelease-id>

示例:

# 假定现在的版本号是 1.1.1
npm version major  # 2.0.0
npm version minor  # 1.2.0
npm version patch  # 1.1.2
npm version prerelease # 1.1.2-0
npm version prerelease --preid=alpha # 1.1.2-alpha.0
npm version 4.1.2  # 4.1.2

执行 npm version 修改完版本号之后,还会默认执行 git add -> git commit -> git tag 操作,commit 的信息和为 tag 均为版本号,且该步骤应在 npm publish 之前进行。

# tag

npm 中的 tag 类似于 git 中的 branch ,发布者可以在指定的 tag 上进行发版,使用者可以选择指定 tag 来安装,默认的 tag 是 latest 。这对于我们日常开发非常有用,很多时候我们想要发布版本来进行验证功能,但是又不想影响正在使用的人,我们就可以利用 tag 和先行版本来进行发包。

npm publish --tag alpha  # 发版到名为 alpha 的 tag 上
npm i <package>@<tag>    # 从指定 tag 上安装包

# dependencies & devDependencies

dependencies 和 devDependencies 字段用来表示模块的依赖和开发环境依赖,模块依赖的版本号有些几种不同写法,来保证安装的时候使用对应的版本

  1. x.y.z 使用精确版本号
  2. * 任意版本,第一次安装会使用模块最新版本
  3. ^x.y.z x 位锁死,y、z 位使用最新版本
  4. 3.x^3.0.0 含义相同,x 位使用指定版本,y、z 位使用最新
  5. ~x.y.z x、y 锁定,z 位使用最新版本

npm 提供了快捷命令,可以在安装的时候就自动把对应内容写到 package.json 中

npm install <package_name> --save # 安装模块并写入 dependencies
npm install <package_name> --save-dev # 安装模块并写入 devDependencies

# peerDependencies

有时候模块需要与宿主模块共享依赖,也就是有可能会用到某个模块,但自己不安装,希望宿主环境安装的时候使用 peerDependencies 声明,比如 react-dom 的 package.json 的使用

"dependencies": {
  "loose-envify": "^1.1.0",
  "object-assign": "^4.1.1",
  "scheduler": "^0.20.1"
},
"peerDependencies": {
  "react": "17.0.3"
}

# repository

repository 用来指定模块源代码信息

"repository": {
  "type": "git",
  "url": "https://github.com/facebook/react.git",
  "directory": "packages/react"
}

# main 字段

main 字段用来标识模块的默认入口文件,比如 react main: "index.js" ,下面两句写法含义相同

const react = require('react');
const react = require('react/index.js');

# 发布 package

  1. npmjs.com 上注册账号
  2. 命令行使用 npm login 登录
  3. 使用 npm publish 进行发布

在进行 npm publish 操作前,请确认使用的是 npm 官方源,如果当前使用的是非官方源,可以使用 npm config set registry https://registry.npmjs.org 或者 nrm 切换至 npm 官方源

# Reference

  • 那些我们必须掌握的 npm 知识
  • NPM & package.json
更新于