跳到主要内容

包管理工具

前置概念​

模块(Module)​

文件即模块,人口文件称为 「入口模块或主模块」

库(Library,简称「lib」)​

一个或多个模块组成的一个功能块

包(Package)​

有元数据的库,元数据有:名称、描述、git 仓库、作者、依赖等,为库提供信息的

关系​

包管理(NPM)​

NPM 全称 Node Package Manager,是 Node 的包管理器,运行在 Node 环境,为包提供文件系统的能力。npm 是前端包管理工具的基础设施,在 npm 的基础上可以去自定义包管理模型

NPM 不能运行在浏览器的环境,因为浏览器提供的能力是有限的,再加上浏览器还有种种限制,所以 NPM 运行在 Node 端更合适,可以充分利用 Node 的能力。

NPM 的出现解决了,包管理的一些痛点:

  • 可以直接下载指定版本的包,而不需要去 github 手动下载某个版本,以及拷贝到本地工作目录等一些列繁琐的操作
  • 自动下载依赖的包,不需要人为的下载
  • 更新库通过版本控制,省去了自己去服务器管理的成本
  • 如何复用

NPM 的出现解决了 Node 包管理的缺陷,后被纳入到 Node 安装环境中,使得 NPM 安装更方便

组成​

由三部分组成:

  • 官网:提供包的查询能力,以及包的用户信息管理能力
  • Register:包的仓库,类似 Docker Hub,存储所有开发的第三方包,开发者可直接从仓库读取下载需要的包
  • CLI:Command Line Interface 命令行接口,可以使用命令行来使用 NPM 的能力

包的安装​

NPM 安装的包,在 Node 环境被称为「第三方包」,安装也很简单,可以直接使用 NPM CLI 安装

  • 本地安装
    • 命令:npm i [包名@版本号] [option],option 不是全局就行
    • 本地安装会将包安装在当前目录的 node_modules 下。
    • 若第三方包也存在 CLI,NPM 会创建该包的软链接到 node_modules/.bin 目录下,这时可以使用 npx [命令名] 来执行包提供的 CLI 能力
  • 全局安装
    • 命令:npm i [包名@版本号] [option],option 是 -g/--global
    • 全局的包一般都有 CLI 脚本,版本稳定,大部分包都会用到,比如:nodemon、http-server、typescript 等

包配置​

NPM 包管理需要在包的「根目录」创建一个 package.json 配置文件,用来描述包的配置信息。

package.json 包含的主要配置项:

  • 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 --yes或npm init -y可以在生成配置文件时自动填充默认配置

package.json 另一个重要作用就是,记录当前 NPM 工程包的依赖

  • dependencies:生产环境的依赖包
  • devDependencies:仅开发环境的依赖包

可以使用以下命令来安装依赖包到该工程中

## 本地安装所有依赖 dependencies + devDependencies
npm install
npm i

## 仅安装生产环境的依赖 dependencies
npm install --production

## 安装依赖到生产环境
npm i 包名
npm i --save 包名
npm i -S 包名

## 安装依赖到开发环境
npm i --save-dev 包名
npm i -D 包名

包的使用​

在 Node 环境下,可以通过 require 函数加载模块,如果 require 参数不是一个相对路径,Node 就认为该模块是一个「第三方模块」,会到项目的 node_modules 目录下查找模块的入口文件。

查找有以下规则:

  • 先对 require 参数 加「文件后缀」,去匹配「文件」,匹配到了,就去执行文件,并返回 module.exports 内容
  • 上一步匹配失败,就去匹配「目录」
    • 匹配到目录,读取该目录下 package.json 文件的 main 属性
      • 存在 main 值对应的文件,就执行文件,并返回 module.exports 内容。若 main 对应的文件不存在,Node 会给一个 DeprecationWarning 提示信息,返回一个空对象
      • 不存在 main,默认查找目录下的 index.js 文件:存在 index.js 文件,就执行文件,并返回 module.exports 内容;不存在 index.js 文件,就报错 Error: Cannot find module 'xxxx'
    • 没有匹配到目录,就在当前项目的「上级目录」下,查找是否存在 node_modules 目录:存在就重复上述步骤;否则就往上级目录依次继续查找 node_modules 目录,若最终在顶级目录依然没找到模块,Node 就会报错

在 Node 中,引入一个 json 文件,会被转为 js 对象

依赖包的版本​

版本规范:主版本号.次版本号.补丁版本号

  • 主版本号:仅当程序发生了重大变化时才会增长,如新增了重要功能、新增了大量的API、技术架构发生了重大变化
  • 次版本号:仅当程序发生了一些小变化时才会增长,如新增了一些小功能、新增了一些辅助型的API
  • 补丁版本号:仅当解决了一些 bug 或 进行了一些局部优化时更新,如修复了某个函数的 bug、提升了某个函数的运行效率

package.json 记录依赖版本号的意义:

符号描述示例示例描述
>大于某个版本>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
*最新版本*始终安装最新版本

NPM 脚本​

位置:paekage.json -> scripts 对象

特点:scripts 对象 的 key 是脚本的名称,value 是具体要在命令行执行的脚本

执行:使用 npm run 脚本名称 来执行脚本。脚本省略了 npx 关键字,所以要运行本地环境的 CLI(node_modules/.bin),可不写 npx

小细节:

  • 若脚本名称是 start、stop、test ,可以省略 run
  • NPM 默认内置了一个 start 的脚本,值为 node server.js

配置 Node 的环境变量​

位置:process.env 包含了计算机中所有的系统变量

配置:在 NPM 脚本中配置环境变量,windows 环境使用 set,例如: set NODE_ENV=test&&npm run dev 注意 && 符号不能带空格,否则会出现错误,Mac 可以使用 export,例如: export NODE_ENV=test && npm run dev,Mac 下 && 可加空格

兼容法处理:使用 cross-env,例如:cross-env NODE_ENV=test npm run dev

NPM 的一些命令​

安装​

  1. 精确安装最新版本
npm install --save-exact 包名 
npm install -E 包名
  1. 安装指定版本
npm install 包名@版本号

查询​

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

更新​

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

卸载包​

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

npm 配置​

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

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

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

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

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

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

  1. 获取某个配置项
npm config get 配置项
  1. 设置某个配置项
npm config set 配置项=值
  1. 移除某个配置项,恢复为默认配置
npm config delete 配置项

包发布​

步骤:

  1. 将 register 配置为官方源
  2. 注册一个账号
  3. 登录,使用 npm login 登录,使用 npm whoami 查看当前登录的账号,使用 npm logout 登出,
  4. 发布,使用 npm publish 发布包

包信息:

{
"name": "testonviwn293", // 包名称
"version": "1.0.3", // 版本号,每次发布,版本号不可重复
"description": "this is test package", // 包说明
"main": "index.js", // 包的入口文件
"types": "index.d.ts", // 包的类型文件
"keywords": [ // 关键字,用于搜索包
"test"
],
"repository": { // 代码仓库地址
"type": "git",
"url": "git+https://github.com/xx/xx.git"
},
"homepage": "https://github.com/xx/xx#readme", // 包的主页 url
"bugs": {
"url" : "https://github.com/xx/xx/issues",
"email" : "project@hostname.com"
},
"author": "xiaoliuing <2303686241@qq.com>", // 作者信息,格式 "用户名 <邮箱>"
"license": "MIT", // 开源协议类型
"files": [], // 哪些文件或者文件夹跟着一起发布出去
"private": true, // 为 true,npm 会禁止将包发布出去
"bin": { // 定义包的 CLI,名称为 "my-cli",脚本内容是 ./bin/cli.js
// 他人安装后,cli 会被「软链」到 node_modules/.bin/my-cli 文件
"my-cli": "./bin/cli.js"
},
"engines": { // 指定 node/npm 的版本
"node" : ">=0.10.3 <0.12"
},
"os": ['darwin'], // 指定包在哪些操作系统可以使用
}

package.json 的详细配置

其他包管理工具​

cnpm​

出现的背景:早请 NPM 并不支持修改安装源 registry,所以淘宝基于 NPM 仓库建立一个「淘宝源仓库」,并自制了一个 cnpm cli 工具

作用: 让开发者可以安装「淘宝源」的包,其他和 NPM 每什么区别。后来 npm 支持修改 registry 了,所以 cnpm 作用不大

同步:每 10 分钟会和 NPM 官方的 registry 同步一次

yarn​

谁开发的:yarn 是由Facebook、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具,它仍然使用 npm 的registry,不过提供了全新 CLI 来对包进行管理

出现的背景:为了解决和优化 NPM 的一些问题

在过去 NPM 有以下问题:

  • 依赖目录嵌套层次深
  • 串行下载依赖包,所以会很慢
  • 依赖包的重复下载,每个包的依赖置灰存在当前包的 node_modules 中
  • 安装包是打印信息繁杂,每个包都会到引出详细信息,可读性差
  • 没有依赖锁的东西,所有会导致包的移植出现问题

Yarn 则天生就解决了上面的问题

  • 扁平化管理依赖目录,最多只有两级
  • 并行下载依赖
  • 本都缓存依赖包
  • 简洁输出包信息
  • 使用 yarn-lock 精确包的版本号,保证移植后依赖版本固定

Yarn 还有自己的一套 CLI,语义化更好。

后来面对 Yarn 的巨大压力,Npm 也做了相应的优化和改进,增加了 package-lock 来锁依赖版本,内置了 npx 命名,可启动本地 CLI。npm6 之后,可以说 npm 已经和 yarn 非常接近,都是比较成熟的包管理工具了

常用命令:

  1. 初始化

初始化:yarn init [--yes/-y]

  1. 安装

添加指定包:yarn [global] add package-name [--dev/-D] [--exact/-E]

安装package.json中的所有依赖:yarn install [--production/--prod]

  1. 脚本和本地CLI

运行脚本:yarn run 脚本名

start、stop、test可以省略run

运行本地安装的CLI:yarn run CLI名

  1. 查询

查看bin目录:yarn [global] bin

查询包信息:yarn info 包名 [子字段]

列举已安装的依赖:yarn [global] list [--depth=依赖深度]

yarn的list命令和npm的list不同,yarn输出的信息更加丰富,包括顶级目录结构、每个包的依赖版本号

  1. 更新

列举需要更新的包:yarn outdated

更新包:yarn [global] upgrade [包名]

  1. 卸载

卸载包:yarn remove 包名

  1. yarn check

使用yarn check命令,可以验证package.json文件的依赖记录和lock文件是否一致

这对于防止篡改非常有用

  1. yarn audit

使用yarn audit命令,可以检查本地安装的包有哪些已知漏洞,以表格的形式列出,漏洞级别分为以下几种:

  • INFO:信息级别
  • LOW: 低级别
  • MODERATE:中级别
  • HIGH:高级别
  • CRITICAL:关键级别
  1. yarn why

使用yarn why 包名命令,可以在控制台打印出为什么安装了这个包,哪些包会用到它

  1. yarn create

非常有趣的命令

今后,我们会学习一些脚手架,所谓脚手架,就是使用一个命令来搭建一个工程结构

过去,我们都是使用如下的做法:

  • 全局安装脚手架工具

  • 使用全局命令搭建脚手架

由于大部分脚手架工具都是以create-xxx的方式命名的,比如react的官方脚手架名称为create-react-app

因此,可以使用yarn create命令来一步完成安装和搭建

例如:

yarn create react-app my-app
# 等同于下面的两条命令
yarn global add create-react-app
create-react-app my-app

pnpm​

下一篇建