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.json
的bin
配置项下。
npm init xxx
和npx 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
。
发布哪些文件
发布一个包,考虑到别人的下载速度,包体积肯定需要尽量小,所以源文件最好不包括,那如何控制只发哪些文件呢?
-
第一种方式是在
package.json
里files
字段来控制,files
字段的值是一个数组,你可以写具体文件名,也可以写目录,还支持glob
模式。 -
第二种就是使用
.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
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