包的安装
首先,安装包之前,我们应该知道,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 命令
安装
- 精确安装最新版本(在 package. json 文件内也是精确版本)
shell
npm install --save-exact 包名
npm install -E 包名- 安装指定版本
shell
npm install 包名@版本号查询
- 查询包安装路径
shell
npm root [-g]- 查看包信息
shell
npm view 包名 [子信息]
## view aliases:v info show- 查询安装包
shell
npm list [-g] [--depth=依赖深度]
## list aliases: ls la ll更新
- 检查有哪些包需要更新
shell
npm outdated- 更新包
shell
npm update [-g] [包名]
## update 别名(aliases):up、upgrade可以使用
npm i -g npm来安装最新版本的 npm,之后就可以使用和其他包一样的方式去更新 npm
卸载包
shell
npm uninstall [-g] 包名
## uninstall aliases: remove, rm, r, un, unlinknpm 配置
npm 的配置会对其他命令产生或多或少的影响
安装好 npm 之后,最终会产生两个配置文件,一个是用户配置,一个是系统配置,当两个文件的配置项有冲突的时候,用户配置会覆盖系统配置
通常,我们不关心具体的配置文件,而只关心最终生效的配置
通过下面的命令可以查询目前生效的各种配置
shell
npm config ls [-l] [--json]另外,可以通过下面的命令操作配置
- 获取某个配置项
shell
npm config get 配置项- 设置某个配置项
shell
npm config set 配置项=值- 移除某个配置项
shell
npm config delete 配置项发布包
- 移除淘宝镜像源,还原为默认镜像源
- npm 官网注册账号,完成邮箱认证
- 本地使用
npm login命令进行登录- 使用
npm whoami查看当前登录的用户 - 使用
npm logout退出登录
- 使用
- 创建工程目录
- 使用
npm init初始化目录- 包名必须是小写字母、下划线、横杠、数字
- 其他的该怎么配置怎么配置
- 作者格式:
npm账号名 <邮箱地址>
- 添加协议说明,文件名为
LICENSE,协议说明的内容自行百度 - 开发程序
- 确定版本
- 使用
npm publish完成发布
开源协议:
