npm

NPM CLI

v7

Posted by huangqing on August 28, 2021

npm cli mindmap

npm mindmap

npm CLI,CLI 就是 Command Line Interface,也就是我们说的命令行接口,具体可以参考npm CLI commands

npm help

npm help 是个好命令。就像我用git --help一样,对于有些比较模糊的命令,用 help 来查一下。

npm init

npm init 命令用来初始化一个简单的 package.json 文件,执行该命令后终端会依次询问 name, version, description 等字段。

npm init
# 直接生成默认配置的package.json
npm init --yes

npm 提供了名称空间策略 scope,scope 包包名格式:@scope-name/pkg-name

npm init --scope org
{
  "name": "@org/name"
}

为 scope 绑定一个仓储

npm login --registry=http://reg.example.com --scope=@org
npm config set @org:registry http://reg.example.com

这样凡是碰到 scope@org 的包,npm 将自动切换作业仓储到 scope 绑定的仓储,这提供了一种多仓储策略

npm publish @org:registry http://reg.example.com

npm init xxx

比如npm init @vitejs/app,是用来创建应用的,其背后是调用了npx @vitejs/create-app,其实就是在执行一个create-app脚本。

这也就是说,如果你想让别人通过npm init xxx命令调用你的包,就必须提供一个create-xxx脚本。

npx

npx 用来运行本地或远程 npm 包的一个命令。比如前面提到的npx @vitejs/create-app

如果 npx 请求的包(比如@vitejs/create-app)没有出现在本地项目的依赖中,npm 就会把@vitejs/create-app安装到全局的 npm cache 目录下。

接着会执行create-app脚本,而这个脚本需要定义在package.jsonbin配置项下。

npm init xxxnpx create-xxx也是一般 CLI 工具的常用套路。

npm config

npm config是用来管理配置文件的,我们平时用的最多的是设置 npm 的源。

# 默认源为 https://registry.npmjs.org/
npm config set registry https://registry.npm.taobao.org

查看 npm 的所有配置,包括默认配置:

 npm config ls -l

.npmrc 文件

除了使用 CLI 的 npm config 命令显示更改 npm 配置,还可以通过 npmrc 文件直接修改配置。

这样的 npmrc 文件优先级由高到低包括:

  • 工程内配置文件: /path/to/my/project/.npmrc
  • 用户级配置文件: ~/.npmrc
  • 全局配置文件: $PREFIX/etc/npmrc (即 npm config get globalconfig 输出的路径)
  • npm 内置配置文件:/path/to/npm/npmrc

npm install/uninstall

npm install 不指定包时,会将 package.json 列出的依赖安装到 node_modules 中,如果指定包名,则安装指定的包。主要注意:

  • -g是全局安装;

  • 如果指定了 --production ,或者 NODE_ENV 是 production,就不会安装 devDependencies 中的依赖。

  • --save 等价于 -S,安装的依赖包信息保存到 package.json 中的 dependencies,这些依赖(比如 vue, react)如果有进入 bundler (比如 webpack )的 Dependency Graph(依赖关系图),会被打包到项目的构建结果中;npm install vue会默认执行-S 的行为,但是建议显示给出-S,给人的感觉会比较清晰。

  • --save-dev 等价于-D,安装的依赖包信息保存到 devDependencies 中,这些依赖一般是开发环境的工具,比如 eslint, webpack, babel 之类的,这些依赖一般不会被打包工具处理到构建结果中。

但是,如果你使用npm install -D vue安装了 vue,并且在项目中引用了 vue 依赖,那么 webpack 的 Dependency Graph 中也会有 vue,最终 vue 也会体现到构建结果中;webpack 不关心一个依赖是dependencies还是devDependencies,只要进入 webpack 的 Dependency Graph,就会打包到结果中。

实质上,我们在开发一个 Vue 组件时,仅仅需要把 vue 作为 devDependencies 即可。

npm start

npm start是一个语义化的命令。通常我们会在 scripts 中自定义 start 脚本,比如:

"start": "npm run dev"

如果没有指定自定义的 start 脚本,npm start默认会执行:

node server.js

npm run

npm run用来运行我们定义的scripts,命令后直接跟脚本名称就行。在npm run时,我们可以调用一些特殊路径下的可执行文件或脚本,这些路径包括环境变量PATH定义的路径,也包括当前项目node_modules中的./bin

npm version

从语义上看,npm version会修改package.json中的version字段,用来管理包的版本号。

一个版本号包含三个部分: MAJOR.MINOR.PATCH :

  • MAJOR 表示主版本号,当你做了不兼容的 API 修改;
  • MINOR 表示次版本号,当你做了向下兼容的功能性新增;
  • PATCH 表示修订号,当你做了向下兼容的问题修正;
# 升级补丁版本号
npm version patch
# 升级小版本号
npm version minor
# 升级大版本号
npm version major
# 升级版本并添加备注
npm version major -m "reason for upgrade"

major/minor/patch三选一,分别代表主版本/次版本/补丁版本。当然也可以传其他的版本参数,具体参考npm-version

通常,我们还会定义一个自定义的 version 脚本,配合conventional-changelog用来自动生成CHANGELOG.md

{
  "scripts": {
    "version": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md"
  }
}

npm login/ npm adduser

发布一个 npm 包的流程并不复杂。首先你必须通过命令行登录 npm,这用到了npm adduser,别名是npm login

确保你的代理正确:有时候,考虑到国内环境,我们安装依赖时,会设置 npm 的源为淘宝镜像。但是在发布 npm 包之前,必须把源切回到 npm。

npm config set registry http://registry.npmjs.org/

npm publish

发布一个 npm 包,发布的界限是以 version 判断的,不能发布相同的 version。即便你只是改了一个 README,也必须修改 version 才能重新 npm publish

一个 node.js 模块是基于 CommonJS 模块化规范实现的,严格按照 CommonJS 规范,模块目录下除了必须包含包描述文件 package.json 以外,还需要包含以下目录:

  • bin:存放可执行二进制文件的目录
  • lib:存放 js 代码的目录
  • doc:存放文档的目录
  • test:存放单元测试用例代码的目录

registry

package.json 设置发布的地址:

"publishConfig": {
    "registry": "http://registry.npm.xxx.com/"
 }

也可以设置别名:

alias ynpm="npm --registry=http://registry.npm.xxx.com"
// 发布的时候
ynpm publish

权限相关

发布包需要验证你的账号权限,第一次执行 npm adduser ,后面就只需要执行 npm login

发布哪些文件

发布一个包,考虑到别人的下载速度,包体积肯定需要尽量小,所以源文件最好不包括,那如何控制只发哪些文件呢?

  1. 第一种方式是在 package.jsonfiles 字段来控制, files 字段的值是一个数组,你可以写具体文件名,也可以写目录,还支持 glob 模式。

  2. 第二种就是使用 .npmignore 配置文件,他类似于 .gitignore 文件,其实如果没有 .npmignore ,会使用 .gitignore 来取代他的功能。在包的根目录下, .npmignore 不会覆盖 files 字段,但在子目录中会覆盖。

有些文件不能无法通过配置排除或者包含:

package.json
README
CHANGES / CHANGELOG / HISTORY
LICENSE / LICENCE
NOTICE
main字段中的文件

以上文件无法忽略。

.git
CVS
.svn
.DS_Store
._*

以上文件无法发布到 npm 。

版本管理

npm 的发包需要遵循语义化版本,一个版本号包含三个部分: MAJOR.MINOR.PATCH.

使用 npm version 命令来自动修改版本号

// version = v1.0.0
npm version patch
// v1.0.1
npm version prepatch
// v1.0.2-0
npm version minor
// v1.1.0
npm version major
// v2.0.0

一般来说还有测试版本先行版本 等,他们这样命名:

  • 3.1.0-beta.0
  • 3.1.0-alpha.0

如果发布先行版本, npm version prepatch 命令得出的版本号好像就不够规范,可以使用 --preid 参数:

npm version prerelease --preid=alpha

其他情况使用指定版本号:

npm version 1.1.0-alpha.1

Changelog

包发布了很多次后,使用者升级就需要知道他是否需要升级,需要查看文档看看有哪些不兼容性改动,所以需要一个 Changelog 来记录每次发布改了些什么。如果收到的维护肯定会有忘记的时候,所以需要使用工具来自动生成,可以使用 standard-version 这个包来生成,这个包的作用是自动更新版本和生成 CHANGELOG 。

使用 commitlint 搭配 husky 来校验你commit的信息是否符合标准

Tag

git的tag

在使用 npm version prepatch 的时候就会默认执行一次 git tag version .

也可以手动打一个标签 git tag -a <tag名> -m <注释文字> ,通过 git push — tags origin master 将标签推到远程。

npm的tag

通过 npm dist-tag ls [<pkg>] 来查看一个包的tag,一般来说我们至少会有三种类型的标签:

  • latest:最后版本,npm install的就是这个
  • beta:测试版本,一般内测使用,需要指定版本号install,例如3.1.0-beta.0
  • next: 先行版本,npm install foo@next安装,例如3.0.2-alpha.0

如果需要发布一个测试版本,在发布的时候需要执行:

npm publish --tag beta

如果直接执行 npm publish ,那么即使你的版本号是 -beta.n ,默认会打上 latest 的标签,别人install的时候也会下载到。这个时候需要我们只要改一下tag

# 不小心发错了
latest: 1.0.1-beta.0
# 将1.0.1-beta.0设置为beta
npm dist-tag add my-package@1.0.1-beta.0 beta
npm dist-tag add my-package@1.0.0 latest

npm unpublish

与发包对应的就是移除已发布的包。你可以选择移除整个已发布的包,也可以针对性地下架某个版本。

npm pack

将 package 打包成 tgz 格式

npm link用于创建一个符号链接,类似于 Linux 软链接(ln -s)的效果。

首先需要在待创建 link 的包目录(比如 vue-x)下运行 npm link,这会在 npm 全局文件夹下创建一个 symlink

npm prefix -g指向 npm 全局文件夹

npm link后,C:\Users\Tusi\AppData\Roaming\npm\node_modules\中就有一个 link 的目录了,其实是一个快捷方式。

同时,如果 vue-x 中有配置 bin 文件,也会被 link 到全局。

要用到 vue-x 的地方可以通过 npm link vue-x 安装它,也会安装到 node_modules 下,不过是一个全量的 vue-x,而非 npm publish 后的 vue-x。

npm link 适合在本地对两个及以上的包做调试用,这样就不用每次调试问题时,还要重新 npm run build, npm publish,省去了很多事。

脚本传入参数

#!/usr/bin/env node
"use strict";
var pkg = require("./package.json");
var osName = require("./");
// 获取脚本传入参数
var argv = process.argv.slice(2);

process.argv 属性返回一个数组,数组包含了启动 node 进程时的命令行参数。第一个元素为启动 node 进程的可执行文件的绝对路径名 process.execPath,第二个元素为当前执行的 javascript 文件路径。剩余的元素为其他命令行参数

如下 script 例子:

"scripts":{
  "serve": "vue-cli-service serve --mode=dev --mobile -config build/example.js"
}

当我们执行 npm run server 命令的时候,process.argv 的具体内容为:

[
  "/usr/local/Cellar/node/12.14.1/bin/node",
  "/Users/mac/Vue-projects/hao-cli/node_modules/.bin/vue-cli-service",
  "serve",
  "--mode=dev",
  "--mobile",
  "-config",
  "build/example.js",
];

执行顺序

npm 脚本执行多任务分为两种情况

并行任务(同时的平行执行),使用&符号

npm run script1.js & npm run script2.js

串行任务(前一个任务成功,才执行下一个任务),使用 && 符号

npm run script1.js && npm run script2.js

参考