Skip to content

包的安装 ​

首先,安装包之前,我们应该知道,npm 是国外的公司,所以其服务器自然也在国外,我们需要修改其镜像地址,一般使用淘宝的地址,我们可以使用 npm config get registry 来查看我们当前的 registry 地址,我们使用 npm config set registry https://registry.npmmirror.com/ 来将地址设置为淘宝镜像,这样可以大大加快我们的下载速度。

要使用 npm 安装一个包,分为两种安装方式,本地安装和全局安装。我们主要用本地安装。

本地安装 ​

使用 npm install packageName 进行安装,或者使用 npm i packageName 进行本地安装,本地安装的包会出现在 node_modules 文件夹中供我们使用,每一个包都会占用一个文件夹。从这里我们能看出,当我们要安装一个包,只需要提供包的名字即可。

这样的安装方式比起以前的方式简单很多,如果像以前的模式,需要去每个包的官网下载,然后复制到工程里面,然后用 require 函数引入,这非常麻烦。而这种方式就非常方便。

我们一个项目会依赖非常多的第三方库,而这些库都放在 node_modules 目录下,这会导致该目录变得非常大,文件非常多,一般来说,我们不会将 node_modules 这个目录进行传输,也就是说我如果要上传到 git,或者把这个项目分享给别人,我们不会将 node_modules 这个目录发出去,所以该目录其实只适用于本地。这里可能读者会有疑问,就是别人给我一个项目,这个项目里没有 node_modules 这个目录,也就是说没有把他依赖的这些第三方库给我传过来,但是这个项目确实又依赖了很多第三方库,没有这些第三方库的话项目也无法运行,那我如何把这些第三方库给还原回来呢?这里先不着急,我们确实可以很轻松地把这些第三方库重新下载下来,但这是后面的内容。

既然我们不会传输这个 node_modules 文件夹,所以在使用 git 的时候,我们一般都是给他忽略掉,在 .gitignore 文件中添加 node_modules,这样 git 就会将该目录忽略掉。

使用 npm 安装包还有一个很牛逼的功能,就是如果安装的包有其他依赖,那么这个包的依赖会被一并下载下来。

有的包里面也带有一些 CLI,也就是命令行的命令,npm 也会自动将他的 CLI 脚本文件放到 node_modules/.bin 目录下,我们可以使用 npx command 来调用这些命令。

对于本地安装的包,我们是不能直接使用命令行进行调用的,因为本地安装的包并不会修改环境变量,我们只能通过 npx 命令间接调用,如果我们希望直接调用,那么需要进行全局安装。

我们可以使用 npm i packageName1 packageName2 来安装多个包,如果我们要卸载一个包,可以使用 npm uninstall packageName 来实现。

全局安装 ​

我们可以使用 npm config get prefix 命令来查看我们全局安装的目录

我们可以使用 npm install --global packageName 就可以实现全局安装,实际上我们也可以看出,对比本地安装,全局安装就是加了一个 --global 参数。当然,npm i -g packageName,也算是一个简写,全局安装的包会自动安装到全局安装的目录中,也就是上一段中我们查看的那个目录。

那全局安装到底是什么东西呢,实际上,全局安装唯一的功能就是安装全局的 CLI 工具,一些包提供了一些 CLI 工具,也就是说给了一些命令行的指令,但是如果这个命令行工具在各个工程中使用的非常频繁,如果每次通过 npx 命令去调用显得太过繁琐,这个时候就需要使用全局安装,全局安装后,我们不需要使用 npx 也可以在系统中任何地方使用这些命令。

在绝大多数情况下,我们都不会使用全局安装

包的配置 ​

npm 将每个使用 npm 的工程本身都看做一个包,也就是说我们只要使用了 npm,那么我们这个项目就是一个包,我们通过这个包里面的 package.json 来对我们这个包进行配置。我们可以使用 npm init 命令创建这个文件。

配置文件中可以描述大量的信息,包括:

  • name:包的名称,该名称必须是英文单词字符,支持连接符
  • version:版本
    • 版本规范:主版本号. 次版本号. 补丁版本号
    • 主版本号:仅当程序发生了重大变化时才会增长,如新增了重要功能、新增了大量的 API、技术架构发生了重大变化
    • 次版本号:仅当程序发生了一些小变化时才会增长,如新增了一些小功能、新增了一些辅助型的 API
    • 补丁版本号:仅当解决了一些 bug 或进行了一些局部优化时更新,如修复了某个函数的 bug、提升了某个函数的运行效率
  • description:包的描述
  • homepage:官网地址
  • author:包的作者,必须是有效的 npm 账户名,书写规范是 account <mail>,例如:zhangsan <zhangsan@gmail.com>,不正确的账号和邮箱可能导致发布包时失败
  • repository:包的仓储地址,通常指 git 或 svn 的地址,它是一个对象
    • type:仓储类型,git 或 svn
    • url:地址
  • main:包的入口文件,使用包的人默认从该入口文件导入包的内容
  • keywords: 搜索关键字,发布包后,可以通过该数组中的关键字搜索到包

我们使用 npm init 的时候会让我们填写大量的配置信息,但是我们大多数时候不需要将我们的包进行发布,很多配置信息对我们来说毫无意义,所以我们可以使用 npm init --yes 或 npm init -y ,这个命令会让所有的配置都自动默认填充,不需要我们再手动去一个一个配置。

但是注意,虽然 package.json 记录了很多配置信息,由于我们不会把这个包打包发出去,但是这个文件依旧很重要,对我们来说,这个文件最重要的作用就是记录了当前工程的依赖信息。这个 JSON 中有两个属性,分别是 dependencies 和 devDependencies,这两个属性都是对象,其中 dependencies 记录了生产环境的依赖,devDependencies 记录了开发环境的依赖。这两个对象属性的格式为:依赖名:版本号。如果我们需要依赖最新版,那么就使用 latest 即可,但一般不会这么写。

生产环境依赖的内容开发环境一定会依赖,但是开发环境依赖的内容不一定要放到生产环境中,比如开发环境可能会依赖一些用于测试的包,这些用于测试的包是不可能放到生产环境中去的。

当我们配置好 package.json 文件之后,相当于我们已经告诉了 npm,我们这个项目需要哪些依赖,此时我们使用 npm instanll 或者 npm i,就可以根据 package.json 安装所有依赖。这个时候前面的问题就迎刃而解了,虽然我们传输备份的时候都不会传输 node_modules 这个文件夹,但是只要我们有了 package.json 这个文件,npm就可以知道我们这个项目需要哪些依赖,从而有能力自动将这些依赖从新下下来。

使用 npm install --production 可以仅还原生产环境的依赖

在目前,使用 npm install 命令安装包的时候,会自动修改 package.json 文件,我们不需要手动在 package.json 中配置,非常方便。同样,当我们使用 npm uninstall 命令卸载一个包的时候,也会自动修改 package.json,也非常方便。

在老版本的 npm 中,需要加上 --save 参数才可以实现上述的自动修改 package.json 的功能。

如果我要安装的东西是仅在开发环境中使用的,为了实现 package.json 的自动更新,就需要在安装的时候添加参数,就像这样安装:npm install --save-dev packageName,或者简写为 npm install -D packageName。

当然这里的 insatll 也可以简写为 i

自动保存的依赖版本在版本号之前会加上一个 ^,比如 ^1.1.1,这种在版本号前面加上 ^ 的版本号叫做语义版本号,这个放在后面介绍。

包的使用 ​

我们在 nodejs 中使用 npm 安装的包非常简单,我们只需要使用 require(packageName) 即可完成包的导入。

也就是说 require() 这个函数,如果填写的是一个以 ./ 或者 ../ 开头的东西,他会识别成一个路径,而如果不是的话,会自动识别为一个包名,然后自动去 node_modules 这个目录下去找对应的包,把他们的入口文件导入进来。寻找方式也很简单,比如 require("lodash"),此时会先从 node_modules 下面去找 lodash.js,如果没有,就会找 node_modules/lodash 这个文件夹下的入口文件,这个入口文件信息是存放在包的配置信息中的,也就是 package.json 文件中,这个配置信息中的 main 字段存储的就是入口文件,如果这个配置文件中没有写明入口文件配置信息,则使用默认的 index.js 作为入口文件。

如果还是找不到,会回到上级目录继续找,直到回到顶级的盘符目录,所以我们在子目录中也是可以直接使用 require 导入包的。

nodejs 给我们提供了很多自带的模块,类似于 WEBAPI,比如我们使用 require("fs"),此时这个 fs 模块是 nodejs 给我们提供的模块,所以此时他就不会从 node_modules 文件夹下面找,而是直接导入 nodejs 原生给我们提供的内置模块。

语义版本 ​

我们在配置依赖版本的时候,前面都是说的固定配置,也就是固定死版本号,比如我要求安装某个包的 1.2.3 这个版本号,那么就必须安装该版本。但很多时候我们并不希望这么做,我们更常见的做法是安装大于该版本的依赖,为什么呢?比如 1.2.5 版本发布了一个补丁,让这个依赖的性能得到了优化,但是由于这是一个补丁版本的更新,所以并不会出现任何兼容性的问题,所以我们是可以放心大胆安装的。

我们再来回顾一下版本号的三个数字含义:主版本号.次版本号.补丁版本号。这三个版本号中,主版本号是大型更新,是最有可能出现兼容性问题的,而次版本号则是一些功能性更新,一般是新增功能,一般不会导致兼容性问题,补丁版本号则是一些修复补丁,一定不会产生兼容性问题。

比如我依赖某个包的 1.2.3 版本进行开发的,但是我希望他是 1.2 这个版本的最高版本,也就是说我的主版本号和次版本号必须是 1.2,但是补丁版本号必须是最高,实际上我们经常这么干,如果我们有这样一个需求,就需要使用语义版本来描述版本号,常见语义版本号如下所示:

符号描述示例示例描述
>大于某个版本>1.2.1大于1.2.1版本
>=大于等于某个版本>=1.2.1大于等于1.2.1版本
<小于某个版本<1.2.1小于1.2.1版本
<=小于等于某个版本<=1.2.1小于等于1.2.1版本
-介于两个版本之间1.2.1 - 1.4.5介于1.2.1和1.4.5之间
x不固定的版本号1.3.x只要保证主版本号是1,次版本号是3即可
~补丁版本号可增~1.3.4保证主版本号是1,次版本号是3,补丁版本号大于等于4
^此版本和补丁版本可增^1.3.4保证主版本号是1,次版本号可以大于等于3,补丁版本号可以大于等于4
*最新版本*始终安装最新版本

避免还原差异

版本还原始终是一个两难的问题,这很难作出取舍,假如我项目依赖某个包的 1.2.3 版本号,如果我固定死这个版本,那么可以得到最好的稳定性。如果我允许版本更新,例如使用 ^1.2.3,可以修复一些 bug,或者带来一些性能上的提升,但同样可能带来一些新的 bug,甚至更高的版本的包其依赖关系也会发生变化,这些都是新的风险。所以实际上,允许版本增加这种操作虽然带来了灵活性,但是本身是带有一定风险的。
npm 最早忽略了这个问题,后来意识到后,学习了 yarn 的处理方式,在安装包的时候自动生成了 package-lock.json 这个文件夹,这个文件下记录了安装时的所有确切的依赖关系,当我们移植包的时候,如果包含了 package-lock.json 这个文件,那么会优先按照该文件进行还原,而非 package.json。

npm 脚本 ​

在使用 npm 安装依赖时,某些依赖会带上一些 CLI 命令,随着我们项目的依赖不断增多,这些 CLI 命令可能会非常多,并且不同的 CLI 命令还支持一些不同的参数,传入不同的参数还会导致不同的效果。

基于此,npm 为我们提供了脚本功能,我们可以在 package.json 文件中配置 script 属性,从而配置脚本,script 属性可以配置一个对象,这个对象的每一个属性就是一个 npm 脚本,属性名为脚本名,属性值为脚本。

json
script:{
	"start":"node index.js";
}

如上所示,我配置了一个脚本,脚本名为 start,脚本为 node index.js。我们可以使用 npm run 脚本名 来运行脚本,例如我使用 npm run start,他就会自动执行 node index.js,是不是非常简单。

例如 nodemon 包,他会提供一个 CLI 命令,即 nodemon 命令,我们可以使用该命令来运行脚本,由于该包不是全局安装,所以需要使用 npx nodemon ./index.js 来使用 nodemon 运行。如果我给了如下配置:

json
script:{
	"start":"npx nodemon ./index.js"
}

当我使用 npm run start,就会自动运行 npx nodemon ./index.js。这种脚本在 CLI 非常多的情况下很有用。

npm 脚本支持控制台的所有命令,也就是说哪怕你配置一个 dir 他也可以支持。

对于一些脚本名称,由于太常用的,所以 npm 进行了简化,npm 对以下脚本名称进行了简化:

  • start
  • stop
  • test

当使用上面几个脚本的时候,不需要使用 run,比如我要使用 npm run start,由于脚本名是 start,我们可以简写为 npm start。

如果脚本以 npx 开头,那么可以省略 npx
start 脚本如果不配置,存在默认值:node server.js

运行环境配置 ​

我们的代码可能在三个环境下运行

  • 开发环境:项目开发时运行的环境
  • 生产环境:项目上线后运行的环境
  • 测试环境:用一些测试工具来测试代码

这三个环境中,项目的运行基本是相同的,这点毫无疑问,毕竟我们肯定都希望上线后达到我们开发所实现的效果嘛。

但也有一些个别情况,我希望在 node 代码中,针对不同的情况做不同的处理,也就是说在 nodejs 代码中,根据不同的环境做一些不同的处理。这里的问题是 nodejs 如何知道我们的代码运行在哪一个环境下。

node 中有一个全局对象 global,类似于浏览器环境的 window,这个 globa 对象包含了当前运行 node 程序的计算机中的很多信息,其中一个属性是 process,这个属性保存了计算机的很多信息,其中有一个叫做 env,是一个对象,这个对象上就是当前系统中所有的环境变量。

通常情况下,我们使用 global.process.env.NODE_ENV 属性来判断当前环境,也就是说我们给系统的环境变量上添加一个 NODE_ENV 属性,从而判断 node 程序运行在哪一个环境。

global 作为 nodejs 的全局对象,它上面的属性也是可以直接使用的,例如 global.process,可以直接使用 process,这一点和浏览器环境下的 window 一样。

我们这个系统变量是永久生效的,所以这种配置方式我们可以称为永久配置,这种永久配置并不是常见的做法,我们更常见的是临时设置,即在 npm 脚本中,让代码执行之前临时设置一下环境变量。

shell
set NODE_ENV=development&&node index.js

只需要将上面的配置为一个脚本,就可以使用脚本来运行项目,此时环境变量就会被临时修改。同样,对于生产环境,测试环境,我们都可以给他写一个脚本,从而快速完成环境切换。

以上使用的是 windows 的环境变量设置方式,但是程序不一定运行在 windows 上,我们可以使用 cross-env 这个第三方库来完成环境变量的设置,以消除不同系统之间环境变量设置的差异。安装好后,使用 npx cross-env NODE_ENV=development node index.js 即可。

其他 npm 命令 ​

安装 ​

  1. 精确安装最新版本(在 package. json 文件内也是精确版本)
shell
npm install --save-exact 包名 
npm install -E 包名
  1. 安装指定版本
shell
npm install 包名@版本号

查询 ​

  1. 查询包安装路径
shell
npm root [-g]
  1. 查看包信息
shell
npm view 包名 [子信息]
## view aliases:v info show
  1. 查询安装包
shell
npm list [-g] [--depth=依赖深度]
## list aliases: ls  la  ll

更新 ​

  1. 检查有哪些包需要更新
shell
npm outdated
  1. 更新包
shell
npm update [-g] [包名]
## update 别名(aliases):up、upgrade

可以使用 npm i -g npm 来安装最新版本的 npm,之后就可以使用和其他包一样的方式去更新 npm

卸载包 ​

shell
npm uninstall [-g] 包名
## uninstall aliases: remove, rm, r, un, unlink

npm 配置 ​

npm 的配置会对其他命令产生或多或少的影响

安装好 npm 之后,最终会产生两个配置文件,一个是用户配置,一个是系统配置,当两个文件的配置项有冲突的时候,用户配置会覆盖系统配置

通常,我们不关心具体的配置文件,而只关心最终生效的配置

通过下面的命令可以查询目前生效的各种配置

shell
npm config ls [-l] [--json]

另外,可以通过下面的命令操作配置

  1. 获取某个配置项
shell
npm config get 配置项
  1. 设置某个配置项
shell
npm config set 配置项=值
  1. 移除某个配置项
shell
npm config delete 配置项

发布包 ​

  1. 移除淘宝镜像源,还原为默认镜像源
  2. npm 官网注册账号,完成邮箱认证
  3. 本地使用 npm login 命令进行登录
    1. 使用 npm whoami 查看当前登录的用户
    2. 使用 npm logout 退出登录
  4. 创建工程目录
  5. 使用 npm init 初始化目录
    1. 包名必须是小写字母、下划线、横杠、数字
    2. 其他的该怎么配置怎么配置
    3. 作者格式:npm账号名 <邮箱地址>
  6. 添加协议说明,文件名为 LICENSE,协议说明的内容自行百度
  7. 开发程序
  8. 确定版本
  9. 使用 npm publish 完成发布

开源协议:

2019-12-18-16-03-02

以笔记为镜,可以知得失