目录
- 全文概要
- 概念介绍
- npm
- cnpm
- yarn
-
- [yarn 介绍](#yarn 介绍)
- [yarn 特点](#yarn 特点)
- [yarn 安装](#yarn 安装)
- [yarn 常用命令](#yarn 常用命令)
- [yarn 配置淘宝镜像](#yarn 配置淘宝镜像)
- [npm 和 yarn 选择](#npm 和 yarn 选择)
- 包发布流程
- npx工具
- pnpm
-
- 硬连接和软连接的概念
- pnpm到底做了什么
- [pnpm创建非扁平的 node_modules 目录](#pnpm创建非扁平的 node_modules 目录)
- pnpm的安装和使用
- pnpm的存储store
- 扩展内容
全文概要
包管理工具总结:
这一章,主要讲解了包管理工具,包括对于包、包管理工具
**包:**一组特定功能的源码合集
**包管理工具:**通过包管理工具对包进行管理,包括下载、更新、删除包等等。常见的前端包管理工具有npm、yarn、cnpm、pnpm这些。
npm的使用:
jsx
// 初始化包
npm init -y
// 下载包
npm install
package.json
:
作用:记录项目详细信息的配置文件,包括项目版本信息,以及项目所依赖的库信息等。
常见属性:name、version、description
重要属性:
main:用于设置程序的入口,比如 index.js
scripts:用于配置一些脚本命令,比如 start
、serve
、 dev
、build
、等等
package-lock.json
:
作用:
1-记录项目依赖包的固定版本
package.json
中记录的包的版本相对宽松,package-lock.json
则记录的较为固定,针对当前项目的包做记录。
2-查找包的缓存
比如可以通过package-lock.json
的 Intergrity 来查找包对应的缓存
注意:
npm install
原理
结合例子来说明一整个流程:
比如我们安装 axios
,通过 npm install axios
:
npm会判断 lock 文件,如果没有:
首先,构建包的依赖关系,判断 axios 所依赖的各项包
然后,通过 registry仓库 下载压缩包
其次,npm对拿到的包进行缓存处理
接着,将压缩包解压到 node_modules
中
最后,生成 package-lock.json 文件。
如果有:
首先,会检测包的依赖一致性,比如下载的 axios
包以及依赖包的版本是多少,是否是最新的,还是需要按照一定特定的版本来处理,这些问题需要在依赖分析环节处理好。
然后,npm 会查找缓存,如果有对应依赖包的话,就会进行下一步,如果没有的话,就会从 registry仓库进行压缩包的下载。
其次,npm对拿到的包进行缓存处理。
接着,将压缩包解压到 node_modules
中。
最后,生成 package-lock.json 文件。
cnpm、yarn
cnpm:由 淘宝 构建的npm的完整镜像,由于服务部署在国内的阿里云上,所以包的下载速度很快
yarn:由 Facebook 出品,特点就是速度特别快,然后安全且可靠。
包的发布过程
创建 index.js 文件,通过 module.exports
暴露所需的属性与方法。
采用npm init
初始化包,
npm包的发布过程:
1-包构建:创建文件夹,并创建文件 index.js, 在文件中声明函数,使用 module.exports 暴露
2-初始化:npm init
工具包,package.json 填写包的信息 (包的名字是唯一的)
3-登陆:在命令行登陆 npm login
4-发布:npm publish
发布到 npm registry
上
5-更新仓库:1.修改版本号(最好符合semver规范) 2.重新发布
在 package.json 中进行修改,然后再发布
npx
作用:主要用于调用项目中的某个模块的指令。
比如现在我想要使用项目的webpack,而非全局的webpack。我可以有几种做法,
比如我可以在 node_module 下去执行 webpack ---version
这个命令,也可以去在 package.json 文件中去设定 script 脚本来执行 webpack ---version
命令,那最终呢,其实都是为了查看当前项目的webpack的版本。
那其实,还有一种最合适的方式,就是通过 npx webpack ---version
来执行,它会自动项目目录的 node_modules/bin
目录下查找对应的命令。
pnpm
概念:高性能的npm
特点:
1-节省空间:
- 依赖包统一存储在硬盘的指定位置,通过 .pnpm store 连接到此
- 同一依赖包磁盘上只存储一份,若需要使用不同版本,则对版本间不同的文件进行分开存储。
2-包的扁平化管理:旨在解决包的引用问题
- 通过软硬连接解决包重复依赖问题
举例:
1-项目中引用包 axios
2-axios包会引用 node_modules/axios
,它是个软连接,并引向 .pnpm/axios@1.7.7
,它是硬连接,指向 .pnpm store
3-.pnpm store
指向磁盘
常用命令:
jsx
// 项目中已经有 package.json 后,通过 install 来安装
pnpm install
// 新增 包
pnpm add <pkg>
概念介绍
代码共享方案
1-通过官网或者Github来下载,并通过
问题:需要手动引入,并且需要长期自己去维护版本。
2-通过包管理工具来进行包管理
优点:通过 npm install 来维护版本包即可
包是什么
概念:『包』英文单词是 package ,代表了一组特定功能的源码集合
包管理工具
管理『包』的应用软件,可以对「包」进行 下载,安装 ,更新,删除,上传 等操作
借助包管理工具,可以快速开发项目,提升开发效率 。同时,其他程序员也可以直接通过工具来安装、升级、删除我们的工具代码。
包管理工具是一个通用的概念,很多编程语言都有包管理工具,所以 掌握好包管理工具非常重要。
常用的包管理工具
下面列举了前端常用的包管理工具
- npm
- yarn
- cnpm
npm
**概念:**npm 全称 Node Package Manager ,翻译为中文意思是『Node 的包管理工具』
npm 是 node.js 官方内置的包管理工具,是 必须要掌握住的工具
包存放位置:
我们发布自己的包其实是发布到registry上面的;
当我们安装一个包时其实是从registry上面下载的包;
npm 的安装
node.js 在安装时会 自动安装 npm ,所以如果你已经安装了 node.js,可以直接使用 npm
可以通过 npm -v 查看版本号测试,如果显示版本号说明安装成功,反之安装失败
查看版本时可能与上图版本号不一样,不过不影响正常使用
npm 基本使用
初始化
创建一个空目录,然后以此目录作为工作目录 启动命令行工具 ,执行 npm init
npm init
命令的作用是将文件夹初始化为一个『包』, 交互式创建 package.json
文件
package.json
是包的配置文件,每个包都必须要有 package.json
配置文件
配置文件: package.json
项目的配置文件记录你项目的名称、版本号、项目描述等,以及项目所依赖的其他库的信息和依赖库的版本号。
配置文件获取方式:
方式一:手动从零创建项目,npm init --y
注意:-y
表示所有都是yes
方式二:通过脚手架创建项目,脚手架会帮助我们生成package.json
,并且里面有相关的配置。
常见的配置文件:
了解:我们可以通过框架的脚手架来创建一个项目,省去npm install
一堆文件的烦恼
**必须填写的属性:**name、version
- name是项目的名称
- version是当前项目的版本号
- description是描述信息,很多时候是作为项目的基本描述
- author是作者相关信息(发布时用到)
- license是开源协议(发布时用到)
private属性:
- private属性记录当前的项目是否是私有的
- 当值为true时,npm是不能发布它的,这是防止私有项目或模块发布出去的方式
main属性:
- 设置程序的入口
理解:我们可以通过包的 package.json
文件来设置 main
属性,从而设定包的程序入口
案例:
比如我们使用 axios
模块 const axios = require('axios');
通过 axios
的 package.json
文件可以查看到 main
属性,那最终我们可以通过 main
属性来找到 axios
包的程序入口
scripts属性:
- scripts属性用于配置一些脚本命令,以键值对的形式存在;
- 配置后我们可以通过 npm run 命令的key来执行这个命令;
- npm start和npm run start的区别是什么?
- 它们是等价的;
- 对于常用的 start、 test、stop、restart可以省略掉run直接通过 npm start等方式运行;
dependencies属性:
- dependencies属性是指定无论开发环境还是生成环境都需要依赖的包;
- 通常是我们项目实际开发用到的一些库模块vue、vuex、vue-router、react、react-dom、axios等等;
- 与之对应的是devDependencies;
devDependencies属性:
- 一些包在生成环境是不需要的,比如webpack、babel等;
- 这个时候我们会通过
npm install webpack --save-dev
,将它安装到devDependencies属性中;
peerDependencies属性:
- 还有一种项目依赖关系是对等依赖,也就是你依赖的一个包,它必须是以另外一个宿主包为前提的;
- 比如element-plus是依赖于vue3的,ant design是依赖于react、react-dom;
engines属性:
- engines属性用于指定Node和NPM的版本号;
- 在安装的过程中,会先检查对应的引擎版本,如果不符合就会报错;
- 事实上也可以指定所在的操作系统 "os" : [ "darwin", "linux" ],只是很少用到;
browserslist属性
- 用于配置打包后的JavaScript浏览器的兼容情况,参考;
- 否则我们需要手动的添加polyfills来让支持某些语法;
- 也就是说它是为webpack等打包工具服务的一个属性(这里不是详细讲解webpack等工具的工作原理,所以不再给出详情);
依赖的版本管理:
我们会发现安装的依赖版本出现:^2.0.3或~2.0.3,这是什么意思呢?
npm的包通常需要遵从semver版本规范:
semver:https://semver.org/lang/zh-CN/
npm semver:https://docs.npmjs.com/misc/semver
semver版本规范是X.Y.Z:
- X主版本号(major):当你做了不兼容的 API 修改(可能不兼容之前的版本);
- Y次版本号(minor):当你做了向下兼容的功能性新增(新功能增加,但是兼容之前的版本);
- Z修订号(patch):当你做了向下兼容的问题修正(没有新功能,修复了之前版本的bug);
我们这里解释一下 ^和~的区别:
- x.y.z:表示一个明确的版本号;
- ^x.y.z:表示x是保持不变的,y和z永远安装最新的版本;
- ~x.y.z:表示x和y保持不变的,z永远安装最新的版本;
package.json 内容示例:
jsx
{
"name": "01_npm",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
属性翻译
jsx
{
"name": "1-npm", #包的名字
"version": "1.0.0", #包的版本
"description": "", #包的描述
"main": "index.js", #包的入口文件
"scripts": { #脚本配置
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "", #作者
"license": "ISC" #开源证书
}
初始化的过程中还有一些注意事项:
1-package name ( 包名 ) 不能使用中文、大写,默认值是文件夹的名称,所以文件夹名称也不
能使用中文和大写
2-version ( 版本号 )要求 x.x.x 的形式定义, x 必须是数字,默认值是 1.0.0
3-ISC 证书与 MIT 证书功能上是相同的,关于开源证书扩展阅读 http://www.ruanyifeng.com/bl og/2011/05/how_to_choose_free_software_licenses.html
3-package.json 可以手动创建与修改
4-使用 npm init -y 或者 npm init --yes 极速创建 package.json
搜索包
搜索包的方式有两种
- 命令行 『npm s/search 关键字』
- 网站搜索 网址是 https://www.npmjs.com/
经常有同学问,『我怎样才能精准找到我需要的包?』 这个事儿需要大家在实践中不断的积累,通过看文章,看项目去学习去积累
下载安装包
安装npm包分两种情况:
- 全局安装(global install):
npm install webpack -g
- 项目(局部)安装(local install):
npm install webpack
对于全局安装的理解:
通常使用npm全局安装的包都是一些工具包:yarn、webpack等;
并不是类似于 axios、express、koa等库文件;
所以全局安装了之后并不能让我们在所有的项目中使用 axios 等库;
理解:
比如我们安装qq之后,可以把qq.exe添加到环境变量中,这样我们在命令行中敲入qq,就可以直接唤起qq应用程序。
再举一个例子,当敲入命令 npm install webpack -g
,这样webpack会被安装到一个node专门管理的目录,而且这个目录被添加到环境变量中。当webpack全局安装成功,我们就可以在命令行中敲入webpack的命令了。
运行之后文件夹下会增加两个资源
- node_modules 文件夹 存放下载的包
- package-lock.json 包的锁文件 ,用来锁定包的版本
安装 uniq 之后, uniq 就是当前这个包的一个 依赖包 ,有时会简称为 依赖
比如我们创建一个包名字为 A,A 中安装了包名字是 B,我们就说 B 是 A 的一个依赖包, 也会说 A依赖B
require 导入 npm 包基本流程
1-在当前文件夹下 node_modules 中寻找同名的文件夹
2-在上级目录中下的 node_modules 中寻找同名的文件夹,直至找到磁盘根目录
案例:
需求:自己手动创建包,并且引入
实现步骤:
1-文件 why
文件夹
2-设置 why
文件夹中的 index.js
文件
3-在 main.js
中通过 require
来引入创建的包
项目安装
生产环境与开发环境
开发环境是程序员 专门用来写代码 的环境,一般是指程序员的电脑,开发环境的项目一般 只能程序员自己访问
生产环境是项目 代码正式运行 的环境,一般是指正式的服务器电脑,生产环境的项目一般 每个客户都可以访问
生产依赖与开发依赖
我们可以在安装时设置选项来区分 依赖的类型 ,目前分为两类:
类型 | 命令 | 补充 |
---|---|---|
生产依赖 | npm i -S uniq | |
npm i --save uniq | -S 等效于 --save, -S 是默认选项 | |
包信息保存在 package.json 中 dependencies 属性 | ||
开发依赖 | npm i -D less | |
npm i --save-dev less | -D 等效于 --save-dev | |
包信息保存在 package.json 中 devDependencies 属性 |
举个例子方便大家理解,比如说做蛋炒饭需要 大米 , 油 , 葱 , 鸡蛋 , 锅 , 煤气 , 铲子 等
其中 锅 , 煤气 , 铲子 属于开发依赖,只在制作阶段使用
而 大米 , 油 , 葱 , 鸡蛋 属于生产依赖,在制作与最终食用都会用到
所以 开发依赖 是只在开发阶段使用的依赖包,而 生产依赖 是开发阶段和最终上线运行阶段都用到的依赖包
举例:
局部安装分为开发时依赖和生产时依赖:
jsx
# 默认安装开发和生产依赖
npm install axios
npm i axios
# 开发依赖
npm install webpack --save-dev
npm install webpack -D
npm i webpack --D
# 根据package.json中的依赖包
npm install
npm install 原理
问题:
- 执行 npm install 它背后帮助我们完成了什么操作?
- 我们会发现还有一个称之为package-lock.json的文件,它的作用是什么?
- 从npm5开始,npm支持缓存策略(来自yarn的压力),缓存有什么作用呢?
npm install 的原理图:
步骤:
1-查看是否有 lock 文件
2-npm install会检测是否有package-lock.json
文件:
没有lock文件
- 分析依赖关系,这是因为包可能会依赖其他的包,并且多个包之间会产生相同依赖的情况;
- 从registry仓库中下载压缩包(如果我们设置了镜像,那么会从镜像服务器下载压缩包);
- 获取到压缩包后会对压缩包进行缓存(从npm5开始有的);
- 将压缩包解压到项目的node_modules文件夹中(前面我们讲过,require的查找顺序会在该包下面查找)
有lock文件
检测lock中包的版本是否和package.json中一致(会按照semver版本规范检测);
: 不一致,那么会重新构建依赖关系,直接会走顶层的流程;
一致的情况下,会去优先查找缓存
: 没有找到,会从registry仓库下载,直接走顶层流程;
查找到,会获取缓存中的压缩文件,并且将压缩文件解压到node_modules文件夹中;
结合例子理解:
比如 npm install axios
首先会检测是否有 lock 文件,如果没有,则会构建依赖关系,然后从 registry 仓库中下载压缩包,并把获取到的压缩包进行缓存,最后把压缩包解压到项目的 node_modules
文件夹中。
在以上搞定之后,会生成 package-lock.json 文件
此时,如果我们把 node_modules 文件删除,再次通过 npm i axios
对axios进行安装:
首先会检测依赖文件的一致性,如果一致,则会查找缓存,若找到,会获取缓存中的压缩文件,并且将压缩文件解压到node_modules
文件夹中。
package-lock.json
作用:
1-查找包的缓存
2-检测依赖一致性
在查找缓存的过程中,如何确定包,比如确定是 axios
,需要标识符来确定,那就可以通过 package-lock.json 来确定,它里面保存了对应包的标识符,npm会根据这个标识符来查找对应的包
其次,不同项目使用的 axios
的版本可能会不一致,此时不同项目就可以通过 package-lock.json
来确定对应项目的包的版本。
package-lock.json文件解析:
-
name:项目的名称;
-
version:项目的版本;
-
lockfileVersion:lock文件的版本;
-
requires:使用requires来跟踪模块的依赖关系;
-
这个如果true的话,表示下面的dependencies中的包的依赖库,既可以是 requires,也可以是dependecies (早期的时候,包的依赖的库是用 requires)
-
-
dependencies:项目的依赖
当前项目依赖axios,但是axios依赖follow-redireacts;
比如axios中的属性如下:
- version表示实际安装的axios的版本;
- resolved用来记录下载的地址,registry仓库中的位置;
- requires/dependencies记录当前模块的依赖;
- integrity用来从缓存中获取索引,再通过索引去获取压缩包文件;
- 后面的数值表示一段通过算法生成的 标识,通过解析这个标识,能够生成对应的目录结构。npm会先从这个目录文件中去获取缓存文件,如拿不到,则会从对应的远程仓库中进行下载。
npm其他常用命令
卸载某个依赖包
jsx
npm uninstall package
npm uninstall package --save-dev
npm uninstall package -D
强制重新build
jsx
npm rebuild
清除缓存
jsx
npm cache clean
安装指定版本的包
项目中可能会遇到版本不匹配的情况,有时就需要安装指定版本的包,可以使用下面的命令的
jsx
## 格式
npm i <包名@版本号>
## 示例
npm i jquery@1.11.2
删除依赖
项目中可能需要删除某些不需要的包,可以使用下面的命令
jsx
## 局部删除
npm remove uniq
npm r uniq
## 全局删除
npm remove -g nodemon
npm的命令其实是非常多的:
https://docs.npmjs.com/cli-documentation/cli
更多的命令,可以根据需要查阅官方文档
配置命令别名
通过配置命令别名可以更简单地执行命令
配置 package.json 中的 scripts 属性
jsx
{
.
.
.
"scripts": {
"server": "node server.js",
"start": "node index.js",
},
.
.
}
配置完成之后,可以使用别名执行命令
jsx
npm run server
npm run start
不过 start 别名比较特别,使用时可以省略 run
jsx
npm start
补充说明:
- npm start是项目中常用的一个命令,一般用来启动项目
- npm run 有自动向上级目录查找的特性,跟 require 函数也一样
- 对于陌生的项目,我们可以通过查看 scripts 属性来参考项目的一些操作
拓展:windows全局安装
我们可以执行安装选项 -g 进行全局安装
jsx
npm i -g nodemon
全局安装完成之后就可以在命令行的任何位置运行 nodemon 命令
该命令的作用是 自动重启 node 应用程序
说明:
- 全局安装的命令不受工作目录位置影响
- 可以通过 npm root -g 可以查看全局安装包的位置
- 不是所有的包都适合全局安装 , 只有全局类的工具才适合,可以通过查看包的官方文档来确定安装方式,这里先不必太纠结
修改 windows 执行策略
windows 默认不允许 npm 全局命令执行脚本文件,所以需要修改执行策略
1-以 管理员身份 打开 powershell 命令行
2-键入命令 set-ExecutionPolicy remoteSigned
3-键入 A 然后敲回车 👌
4-如果不生效,可以尝试重启 vscode
环境变量 Path
Path 是操作系统的一个环境变量,可以设置一些文件夹的路径,在当前工作目录下找不到可执行文件 时,就会在环境变量 Path 的目录中挨个的查找,如果找到则执行,如果没有找到就会报错
补充说明:
- 如果希望某个程序在任何工作目录下都能正常运行,就应该将该程序的所在目录配置到环境 变量 Path 中
- windows 下查找命令的所在位置 cmd 命令行 中执行 where nodemon
- powershell命令行
- 执行get-command nodemon
cnpm
介绍
cnpm 是一个淘宝构建的 npmjs.com 的完整镜像,也称为『淘宝镜像』,网址https://npmmirror.com/
cnpm 服务部署在国内 阿里云服务器上 , 可以提高包的下载速度
官方也提供了一个全局工具包 cnpm ,操作命令与 npm 大体相同
安装
我们可以通过 npm 来安装 cnpm 工具
jsx
npm install -g cnpm --registry=https://registry.npmmirror.com
操作命令
功能 | 命令 |
---|---|
初始化 | cnpm init / cnpm init |
安装包 | cnpm i uniq |
cnpm i -S uniq | |
cnpm i -D uniq | |
cnpm i -g nodemon | |
安装项目依赖 | cnpm i |
删除 | cnpm r uniq |
npm 配置淘宝镜像
用 npm 也可以使用淘宝镜像,配置的方式有两种
- 直接配置
- 工具配置
直接配置
执行如下命令即可完成配置
jsx
npm config set registry https://registry.npmmirror.com/
工具配置
使用 nrm 配置 npm 的镜像地址 npm registry manager
1-安装 nrm
jsx
npm i -g nrm
2-修改镜像
jsx
nrm use taobao
3-检查是否配置成功(选做)
jsx
npm config list
检查 registry 地址是否为 https://registry.npmmirror.com/ , 如果 是 则表明成功
补充说明:
1-建议使用第二种方式 进行镜像配置,因为后续修改起来会比较方便
2-虽然 cnpm 可以提高速度,但是 npm 也可以通过淘宝镜像进行加速,所以 npm 的使用率还是高于 cnpm
yarn
yarn 介绍
yarn 是由 Facebook 在 2016 年推出的新的 Javascript 包管理工具,官方网址: https://yarnpkg.com/
yarn 特点
yarn 官方宣称的一些特点
- 速度超快:yarn 缓存了每个下载过的包,所以再次使用时无需重复下载。 同时利用并行下载以最大 化资源利用率,因此安装速度更快
- 超级安全:在执行代码之前,yarn 会通过算法校验每个安装包的完整性
- 超级可靠:使用详细、简洁的锁文件格式和明确的安装算法,yarn 能够保证在不同系统上无差异的 工作
yarn 安装
我们可以使用 npm 安装 yarn
jsx
npm i -g yarn
yarn 常用命令
功能 | 命令 |
---|---|
初始化 | yarn init / yarn init -y |
安装包 | yarn add uniq 生产依赖 |
yarn add less --dev 开发依赖 | |
yarn global add nodemon 全局安装 | |
删除包 | yarn remove uniq 删除项目依赖包 |
yarn global remove nodemon 全局删除包 | |
安装项目依赖 | yarn |
运行命令别名 | yarn <别名> # 不需要添加 run |
思考题:
这里有个小问题就是 全局安装的包不可用 ,yarn 全局安装包的位置可以通过 来查看,
那你有没有办法使 yarn 全局安装的包能够正常运行?
yarn 配置淘宝镜像
可以通过如下命令配置淘宝镜像
jsx
yarn config set registry https://registry.npmmirror.com/
可以通过 yarn config list 查看 yarn 的配置项
npm 和 yarn 选择
大家可以根据不同的场景进行选择
- 个人项目
- 如果是个人项目, 哪个工具都可以 ,可以根据自己的喜好来选择
- 公司项目
- 如果是公司要根据项目代码来选择,可以 通过锁文件判断 项目的包管理工具
- npm 的锁文件为 package-lock.json
- yarn 的锁文件为 yarn.lock
- 如果是公司要根据项目代码来选择,可以 通过锁文件判断 项目的包管理工具
包管理工具不要混着用,切记,切记,切记
包发布流程
创建与发布
我们可以将自己开发的工具包发布到 npm 服务上,方便自己和其他开发者使用,操作步骤如下:
准备工作:
npm账号注册:https://www.npmjs.com/signup
自定义npm包发布:
1-创建文件夹,并创建文件 index.js, 在文件中声明函数,使用 module.exports 暴露
2-npm 初始化工具包,package.json 填写包的信息 (包的名字是唯一的)
3-登陆:在命令行登陆 npm login
4-发布:npm publish
发布到 npm registry
上
5-更新仓库:1.修改版本号(最好符合semver规范) 2.重新发布
在 package.json 中进行修改,然后再发布
自定义npm包使用:
建议:可以在webpack环境下去使用,从而可以使用 ES Module
先下载 webpack
jsx
npm i webpack webpack-cli
然后执行 webpack 进行打包
jsx
npx webpack
最后,在 src/index.html 中加载打包后的代码
jsx
<script src="./dist/main.js"></script>
致此,即可完整使用自定义的包
一些命令:
删除发布的包:npm unpublish
让发布的包过期:npm deprecate
案例:
1-创建文件夹,并创建文件 index.js, 在文件中声明函数,使用 module.exports 暴露
2-npm 初始化工具包,package.json 填写包的信息 (包的名字是唯一的)
3-登陆:在命令行登陆 npm login
4-发布:npm publish
发布到 npm registry
上
更新包
后续可以对自己发布的包进行更新,操作步骤如下
- 更新包中的代码
- 测试代码是否可用
- 修改 package.json 中的版本号
- 发布更新
jsx
npm publish
删除包
执行如下命令删除包
jsx
npm unpublish --force
删除包需要满足一定的条件, https://docs.npmjs.com/policies/unpublish
- 你是包的作者
- 发布小于 24 小时
- 大于 24 小时后,没有其他包依赖,并且每周小于 300 下载量,并且只有一个维护者
npx工具
npx是npm5.2之后自带的一个命令。
npx的作用非常多,但是比较常见的是使用它来调用项目中的某个模块的指令。
我们以webpack为例:
全局安装的是webpack5.1.3
项目安装的是webpack3.6.0
如果我在终端执行 webpack --version使用的是哪一个命令呢?
- 显示结果会是 webpack 5.1.3,事实上使用的是全局的,为什么呢?
- 原因非常简单,在当前目录下找不到webpack时,就会去全局找,并且执行命令;
如何解决这个问题呢?
局部命令的执行
那么如何使用项目(局部)的webpack,常见的是两种方式:
方式一:明确查找到node_module下面的webpack
方式二:在 scripts定义脚本,来执行webpack;
方式一:在终端中使用如下命令(在项目根目录下)
./node_modules/.bin/webpack --version
jsx
nathanchen@192 test_npx % ./node_modules/.bin/webpack --version
3.6.0
方式二:修改package.json中的scripts
jsx
"scripts": {
"webpack": "webpack --version"
}
理解:如果我们在 package.json 的 script 中去执行某个命令,那么它优先会去 node_modules 下去查找对应的文件。
方式三:使用npx
npx webpack --version
npx的原理非常简单,它会到当前目录的node_modules/.bin目录下查找对应的命令;
pnpm
什么是pnpm呢?我们来看一下官方的解释:
pnpm:我们可以理解成是performant npm缩写;
解决的痛点:
1-解决多项目占据相同的包的问题,以节省大量空间。
2-包的扁平化管理
哪些公司在用呢?
包括Vue在内的很多公司或者开源项目的包管理工具都切换到了pnpm;
硬连接和软连接的概念
硬链接(hard link):
- 硬链接(英语:hard link)是电脑文件系统中的多个文件平等地共享同一个文件存储单元;
- 删除一个文件名字后,还可以用其它名字继续访问该文件;
理解:我们将mp4的数据存储到磁盘中。然后通过操作系统下的文件系统来找到这个存储位置。
比如,我们通过文件系统下的 test.mp4
来定位到磁盘中的 Data
。以上的连接的称之为硬连接。
符号链接(软链接soft link、Symbolic link):
- 符号链接(软链接、Symbolic link)是一类特殊的文件;
- 其包含有一条以绝对路径或者相对路径的形式指向其它文件或者目录的引用;
理解:软连接的本质是保存的文件的路径。比如我们在桌面创建一个名叫shortcut
的快捷方式,点击它可以链接访问到 test.mp4
。以上的连接称之为软连接。
参考用图:
硬链接和软连接的演练
文件的拷贝:文件的拷贝每个人都非常熟悉,会在硬盘中复制出来一份新的文件数据;
jsx
window: copy foo.js foo_copy.js
macos : cp foo.js foo_copy.js
文件的硬链接
jsx
window: mklink /H aaa_hard.js aaa.js
macos : ln foo.js foo_hard.js
文件的软连接:
jsx
window: mklink aaa_soft.js aaa.js
macos : ln -s foo.js foo_copy.js
pnpm到底做了什么
当使用 npm 或 Yarn 时,如果你有 100 个项目,并且所有项目都有一个相同的依赖包,那么, 你在硬盘上就需要保存 100 份该相同依赖包的副本。
如果是使用 pnpm,依赖包将被 存放在一个统一的位置,因此:
- 如果你对同一依赖包使用相同的版本,那么磁盘上只有这个依赖包的一份文件;
- 如果你对同一依赖包需要使用不同的版本,则仅有 版本之间不同的文件会被存储起来;
- 所有文件都保存在硬盘上的统一的位置:
- 当安装软件包时, 其包含的所有文件都会硬链接到此位置,而不会占用 额外的硬盘空间;
- 这让你可以在项目之间方便地共享相同版本的 依赖包;
理解:
比如现在通过 pnpm 来安装 axios,pnpm会在某地保存一份 axios 文件的硬连接,指向磁盘中 axios的实际存储位置。当 Project 1 需要使用 axios 时,只需要重新建立一次硬连接,指向磁盘中的 axios即可。
pnpm创建非扁平的 node_modules 目录
当使用 npm 或 Yarn Classic 安装依赖包时,所有软件包都将被提升到 node_modules 的 根目录下。其结果是,源码可以访问 本不属于当前项目所设定的依赖包;
简单总结一下:
1-项目中引用包 axios
2-axios包会引用 node_modules/axios
,它是个软连接,并引向 .pnpm/axios@1.7.7
,它是硬连接,指向 .pnpm store
3-.pnpm store
指向磁盘
理解:
早期的npm的包管理方式是非扁平的,比如 node_modules 下包含 webpack,然后 webpack 又包含对应所需的一些包,如此形成一个层层的结构。
jsx
node_modules
webpack
node_modules
ajv
anymatch
babel
node_modules
anymatch
问题是,比如现在有 babel,里面也包含 anymatch,就会导致它和 webpack 中 anymatch 的包重复。因此到后期,npm就开始变成扁平化。
jsx
node_modules
webpack
babel
ajv
anymatch
但是扁平化也会造成一定的问题。比如说,当我们在项目中引入 webpack 包,它会自动引入 anymatch,而在项目的 package.json 中并没有记录这个包。问题是,我们依然可以在项目中去引用这个包的内容,这就会导致当我们删除 webpack 后,项目中又需要使用 anymatch 包,但是删除的过程会顺带把 anymatch 删除,从而导致项目无法正常运行。
jsx
src
main.js
| const webpack = require("webpack")
| const anymatch = require("anymatch")
package.json
案例:
目标:练习使用 pnpm
步骤:
1-初始化 pnpm
jsx
nathanchen@192 pnpm_test % pnpm init
Wrote to /Users/nathanchen/Downloads/pnpm_test/package.json
{
"name": "pnpm_test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
nathanchen@192 pnpm_test % pnpm --version
8.6.11
2-加入 axios 包
jsx
nathanchen@192 pnpm_test % pnpm add axios
╭─────────────────────────────────────────────────────────────────╮
│ │
│ Update available! 8.6.11 → 9.9.0. │
│ Changelog: https://github.com/pnpm/pnpm/releases/tag/v9.9.0 │
│ Run "pnpm add -g pnpm" to update. │
│ │
│ Follow @pnpmjs for updates: https://twitter.com/pnpmjs │
│ │
╰─────────────────────────────────────────────────────────────────╯
Packages: +9
+++++++++
Packages are hard linked from the content-addressable store to the virtual store.
Content-addressable store is at: /Users/nathanchen/Library/pnpm/store/v3
Virtual store is at: node_modules/.pnpm
Progress: resolved 9, reused 7, downloaded 2, added 9, done
dependencies:
+ axios 1.7.7
Done in 2.2s
pnpm包的查找过程,以及处理包的扁平化问题:
index.js
通过 node_modules
下的 axios
软连接找到 .pnpm
下的 axios
,然后这里再通过硬连接连接到磁盘中 axios 真实存在的位置。
.pnpm/axios@1.7.7/node_modules/form-data
本身又是一个软连接,连接到 .pnpm/form-data@4.0.0
,然后在这里再通过硬连接连接到磁盘的真实位置。从而通过这种方式,来处理在index.js
中可能引用form-data
包的问题。
pnpm的安装和使用
那么我们应该如何安装pnpm呢?
- 官网提供了很多种方式来安装pnpm:https://www.pnpm.cn/installation
- 因为我们每个同学都要求安装过Node,Node中有npm,所以我们通过npm安装即可;
jsx
npm install -g pnpm
以下 是一个与 npm 等价命令的对照表,帮助你快速入门:
npm 命令 | pnpm 等价命令 | 备注 |
---|---|---|
npm install | pnpm install | 项目中已经有 package.json 后,通过 install 来安装 |
npm install | pnpm add | |
npm uninstall | pnpm remove | |
npm run | pnpm |
更多命令和用法可以参考pnpm的官网:https://pnpm.io/zh/
pnpm的存储store
在pnpm7.0之前,统一的存储位置是 ~/.pnpm-score中的;
在pnpm7.0之后,统一的存储位置进行了更改:/store
在 Linux 上,默认是 ~/.local/share/pnpm/store
在 Windows 上: %LOCALAPPDATA%/pnpm/store
在 macOS 上: ~/Library/pnpm/store
我们可以通过一些终端命令获取这个目录:获取当前活跃的store目录
jsx
pnpm store path
另外一个非常重要的store命令是prune(修剪):从store中删除当前未被引用的包来释放store的空间
jsx
pnpm store prune
扩展内容
在很多语言中都有包管理工具,比如:
语言 | 包管理工具 |
---|---|
PHP | composer |
Python | pip |
Java | maven |
Go | go mod |
JavaScript | npm/yarn/cnpm/other |
Ruby | rubyGems |
除了编程语言领域有包管理工具之外,操作系统层面也存在包管理工具,不过这个包指的是『 软件包 』
操作系统 | 包管理工具 | 网址 |
---|---|---|
Centos | yum | https://packages.debian.org/stable/ |
Ubuntu | apt | https://packages.ubuntu.com/ |
MacOS | homebrew | https://brew.sh/ |
Windows | chocolatey | https://chocolatey.org/ |