平时工作中,像npm、cnpm、yarn等一些工具都是经常经常用的,但可能对里面的一些细节都没太在意,所以这篇就来总结一下加深印象和理解。另外还有pnpm的使用,以及它的优势
1. npm包管理工具
包管理工具npm
- Node Package Manager,也就是Node包管理器
- 但是目前已经不仅仅是Node包管理器了,在前端项目中我们也使用它来管理依赖的包
- 比如:vue、vue-router、vuex、express、koa、axios等等
如何下载和安装npm工具
- npm属于node的一个管理工具,所以我们需要先安装Node
- node管理工具:https://nodejs.org/en/ ,安装Node的过程会自动安装npm工具
npm管理的包查看搜索<官网>
- https://www.npmjs.com/
- 这是我么安装相关的npm包的官网
npm管理的包存放位置
- 我们发布自己的包其实是发布到registry上面的
- 当我们安装一个包时,其实是从registry上面下载的包
npm的配置文件
- 事实上,我们每个项目都会有一个对应的配置文件,无论是前端项目(Vue、React)还是后端项目(Node等)
- 这个配置文件会记录着你项目的名称、版本号、项目描述
- 也会记录着项目中所依赖的其他库的信息和依赖库的版本号
- 这个配置文件就是package.json
2. package.json配置文件
首先这个文件如何得到
- 方式一:就是手动从零创建项目,npm init -y
- 方式二:通过脚手架创建项目,脚手架会帮助我们生成package.json,并且里面有相关的配置信息
常见的属性
- name是项目的名称
- version是当前项目的版本号
- description是描述信息,很多时候是作为项目的基本描述
- author是作者相关的信息(发布时用到)
- license是开源协议(发布时用到)
- private是记录当前项目是否为私有的,当值为true时,npm是不能发布它的,这是防止私有项目或模块发布出去的方式
main属性
- 设置程序的入口
- 比如我们使用axios模块的时候,const axios = require('axios')(或者使用import一样的)
- 它会先去node_modules下找到axios的包下的package.json文件中的main属性来进行查找文件,如果没有main属性再去找index
scripts属性
- scripts属性用于配置一些脚本命令,以键值对的形式存在
- 配置后我们可以通过npm run 命令的key来执行这个命令
- npm run statr 和 npm start的区别是什么
他们是等价的;
对于常用的start、test、stop、restart可以省略掉run直接通过npm start等方式运行
dependencies属性
- dependencies属性是指无论开发环境还是生产环境都需要依赖的包
- 通常是我们项目实际开发用到的一些库模块vue、vue-router、vuex、axios等等
- 与之对应的是devDependencies属性
devDependencies属性
- 一些包在生产环境下是不需要的,比如webpack,babel等
- 这个时候我们可以通过npm install webpack --save-dev(npm i webpack -D),将它安装到 devDependencies属性中
peerDependencies属性
- 这种表示项目依赖关系是对等依赖,也就是你依赖的一个包,它必须是以另外一个宿主包为前提的;
- 比如:element-plus依赖于Vue3.x
依赖的版本管理
我们会发现在package.json安装的依赖版本中出现:^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永远安装最新的版本
3. package-lock.json文件
除了package.json配置文件,我们发现还有个package-lock.json文件。这个文件也是自动生成的,就是相当于我们的缓存文件,一般是不需要我们自己维护的,里面记录着我们安装的每个依赖的确定版本,我们先npm install安装依赖,下载下来压缩包然后解压到node_modules下,然后再生成package-lock.json文件,记录着每个依赖具体的版本号
pack-lock.json文件解析
- name:项目的名称
- version:项目的版本
- lockfileVersion:lock文件的版本(更新了几次package-lock.json文件)
- requires:追踪模块的依赖关系
- dependencies:项目的依赖
- integrity:用来从缓存中获取索引,再通过索引去获取压缩包文件
我们安装的依赖都是有缓存的,那么在什么地方呢,我们可以通过以下命令来获取缓存的位置
npm config get cache
4. npm install 原理图
5. npm 其他命令
这里再介绍一些其他常用的命令
卸载某个依赖包
npm uninstall package
npm uninstall package --save-dev
npm uninstall package -D
强制重新build
npm rebuild
清除缓存
npm cache clean
更多命令可查阅官方文档
6. yarn工具
另一个包管理工具
- yarn是有Facebook、Google、Exponent和Tilde联合推出了一个新的JS包管理工具
- yarn是为了弥补 早期npm的一些缺陷而出现的
- 早期的npm存在很多的缺陷,比如安装依赖速度很慢、版本依赖混乱等等一系列问题
- 虽然从npm5版本开始,进行了很多的升级和改进,但是依然很多人喜欢使用yarn
其实使用起来都是一样的,跟npm一样,不要把它想象的很高大上 ,yarn也属于npm下的一个库所以也是通过npm来安装yarn如下:
npm i -g yarn
Npm | Yarn |
npm install | yarn install |
npm install [package] | yarn add [package] |
npm install --save [package] | yarn add [package] |
npm install --save-dev [package] | yarn add [package] [--save-dev] |
npm rebuild | yarn install --force |
npm uninstall [package] | yarn remove [package] |
npm uninstall --save [package] | yarn remove [package] |
npm uninstall --save-dev [package] | yarn remove [package] |
npm uninstall --save-optional [package] | yarn remove [package] |
npm cache clean | yarn cache clean |
rm -rf node_modules && npm install | yarn upgrade |
7. cnpm工具
由于某些特殊原因,某些情况下我们可能没办法从 https://registry.npmjs.org上下载下来一些需要的包,就像github似的,我们有时候可以访问,有时候却进不去,道理一样,原因有很多。所以这时候就有了cnpm工具,淘宝有个镜像服务器,它会定时(好像是10分钟一次,具体也不太清除了)从国外的registry同步到国内来,我们使用cnpm就可以直接从国内下载了,速度会提升很多,但是也有弊端,使用cnpm下载的包有可能不是最新的
本身npm是有镜像的, 默认就是https://registry.npmjs.org/
我可以通过npm config set registry https://registry.npm.taobao.org修改npm的镜像,让它指向国内,但是大多数人都不会去修改npm自身的镜像,而是去下载cnpm
查看npm镜像
npm config get registry //https://registry.npmjs.org/
我们可以直接设置npm的镜像 (不推荐)
npm config set registry https://registry.npm.taobao.org
不太希望随意修改npm原本从官方下来包的渠道
防止以后改来改去的混乱
这个时候,我们可以使用cnpm,并且将cnpm设置为淘宝的镜像
npm install -g cnpm --registry=https://registry.npm.taobao.org
查看cnpm的镜像
cnpm config get registry
8. npm发布自己的包
注册npm账号
- https://www.npmjs.com/
- 选择sign up
在命令行登录
npm login
修改package.json配置文件
发布到npm registry
npm publish
更新仓库
- 修改版本号(最好遵循semver规范)
- 重新 npm publish 发布
删除发布的包
npm unpublish
让发布的包过期
npm deprecate
9. npx的使用
这里跟大家举个例子,我们在全局安装了 yarn或babel或less或其他的一些工具等,然后我们在某个项目下打开终端又在局部安装了一下yarn或babel或less(跟全局安装的一样),但是版本有所差别,比如全局安装的版本是 5.x.x,而在局部安装的是 3.x.x.,这里假设安装的是babel,那么当我们在该项目下执行babel --version的时候是用的全局的?还是用的局部的呢?答案是全局的,这时候npx就派上用场了,通过npx babel 就可以以局部版本为准。
其他的一些工具包等都是如此,但webpack 却是个例外,我们使用webpack命令的时候,他会优先从项目中去找,也就是项目下的node_modules/webpack/bin 下,如果找到了就直接用该版本,找不到就使用全局的
10. pnpm的使用
pnpm是后来又新出的包管理工具,还是满强大的。我们要知道,每个新技术的出现到流行,都是为了解决原来技术的痛点的。那么pnpm的优势在哪?核心应该分为两点
1. 首先,我们每个人的电脑上肯定都会又很多的项目,几十个甚至几百个几千个都是有可能的,有时候我们自己写个小demo都会新建一个项目,每个项目我们都得安装一次依赖,但是像依赖包vue、vue-router、vuex、axios、pinia、element等等这些都是特别常用的依赖库,我们都要每个项目安装一次,即便是和其他项目依赖的库一样,我们也还得安装一次,同样的依赖包我们要重复安装无限次,随着时间的累积,这些包的大小将会变得超级大,占用了很多没必要的磁盘,有人说没用的时候删掉就可以了,当然是可以的,但是那么多的项目,一个个的小demo,说实话我自己都不知道也不确定哪个将来一定用不到,这个时候,pnpm就诞生了,它就可以帮助解决我们这个问题,我们使用pnpm,它就相当于有个专门的地方存储我们的依赖包,而这个地方的依赖包不会重复,也就是每个依赖包都只会安装一次,这样多个项目用到同一个依赖包的时候,它其实会直接硬链接到我们的pnpm Store中去的,如果是用到同一个依赖包,但是版本不一样,他们pnpm只会去下载一些版本之间不同的文件。
2. 还有个就是,在早期的时候,咱们安装依赖的时候,会将依赖包安装到node_modules下,是非扁平化的,比如我们安装依赖包A,A又依赖于B、C,这个时候我们有需要一个依赖包D,而D也同样依赖C,因为是非扁平化,D拿不到A中的包C,只能再去下载,这样导致同一项目中的依赖包C等等很多被重复下载,造成包体积变大,所以才有了现在npm、yarn、cnpm都是扁平化的,不会去下载重复的包,可以重复利用,但是也有弊端,比如我们我们安装了包A,A又依赖于B、C,那么B、C也会在node_modules下,我们 const B = require("B")也是可以使用B的,但是我们压根就没下载B,我们如果将来把包A卸载,那么B也用不了了,严格来将这也是有点儿问题的,所以现在出了pnpm,它也是创建的非扁平化的,但是跟原来的大不相同,我们pnpm安装的时候,也确实是会在node_modules下的,但是该包实则不在这里,它会软连接到我们.pnpm Store中去的。
pnpm官方解释
- 我们可以理解成performant npm缩写
pnpm 速度快、节省磁盘空间的软件包管理器
- 快速:pnpm比其他包管理器快2倍
- 高效:node_modules中的文件链接自特定的内容寻址存储库
- 支持monorepos:pnpm内置支持单仓多包
- 严格:pnpm默认创建了一个非平铺的node_modules,因此代码无法访问任意包
软链接和硬链接的概念
先通俗的跟大家说一下,首先我们的copy,我们copy一个文件之后,我们修改两个文件之间任一个文件都不会影响到另一个文件
然后是硬链接,就是我们硬链接一个文件之后,看似和copy差不多,但实则他们两个的数据源还是同一个,也就是我们修改一个文件同样另一个文件也会跟着改的
然后是软链接,相信大家对发送到桌面快捷方式都不陌生吧,我们下载一个工具,然后会发送快捷方式到桌面,会有一个小的箭头符号,这个其实就相当于软链接,我们点击的是桌面上的,但实则他会软链接到我们的下载的路径去找的,鼠标右键打开文件所在路径,也会去我们对应的磁盘的位置,这其实就是软链接
硬链接(hard link)
- 硬链接是电脑文件系统中的多个文件平等的共享同一个文件存储单元
- 删除一个文件名字后,还可以用其他名字继续访问该文件
符号链接(软链接、soft link、Symbolic link)
- 符号链接是一类特殊的文件
- 其包含一条以绝对路径或者相对路径的形式指向其他文件或者目录的引用
pnpm到底做了什么
当使用 npm 或者 Yarn 是,如果你有100个项目,并且所有的项目都有一个相同的依赖包,那么,你在硬盘上就需要保存10份相同依赖包的副本
如果是使用的pnpm,依赖包将被存放在一个统一的位置,因此:
- 如果你对同一依赖包使用相同的版本,那么磁盘上只有这个依赖包的一份文件
- 如果你对同一依赖包需要使用不同的版本,则仅有 版本之间不同的文件会被存储起来
- 所有文件都保存在硬盘的统一的位置
当安装软件包时,其包含的所有文件都会硬链接到此位置,而不会占用额外的硬盘空间
这让你可以在项目之间方便的共享相同版本的依赖包
pnpm创建非扁平的node_modules目录
当使用 npm 或 Yarn Classic安装依赖包时,所有软件包都将被提升到node_modules的根目录下,其结果就是,源码可以访问本不属于当前项目所设定的依赖包
pnpm的安装和使用
官网提供了很多方式来安装pnpm:https://www.pnpm.cn/installation
使用npm安装
npm install -g pnpm
npm 与 pnpm 等价对照表
npm | pnpm |
npm install | pnpm install |
npm install <package> | pnpm add <package> |
npm uninstall <package> | pnpm remove <package> |
npm run <cmd> | pnpm <cmd> |
更多命令和用法可以参考pnpm官网: https://pnpm.io/zh/
pnpm的存储store
在pnpm7.0之前,统一存储位置时 ~/.pnpm-score中的
在pnpm7.0之后,统一存储位置进行了更改
我们可以通过一些终端命令来获取这个目录(获取当前活跃的store目录)
pnpm store path
另外一个非常重要的store命令是prune(修建):
从 store 中删除当前未被引用的包来释放store的空间
pnpm store prune