前端三大包管理器你知道多少?npm、yarn、pnpm

🧑‍💻 写在开头

点赞 + 收藏 === 学会🤣🤣🤣

上一篇手把手带你搭建前端项目:react18、ts5、lint四剑客、webpack、storybook【保姆级教程四】我们引入了storybook编写组件、使用rollup打包组件、本地测试开发的组件,本篇我们将介绍最常用的npm,安装机制、如何打tag、如何发包

🥑 你能学到什么?

希望在你阅读本篇文章之后,不会觉得浪费了时间。如果你跟着读下来,你将会学到:

  • npm、yarn、pnpm基本介绍
  • npm、yarn、pnpm的安装机制
  • 如何打tag
  • 如何发布、更新、撤回包

🍎 系列文章

🍐 npm

1.npm简介

npm是JavaScript世界的包管理工具,是 Node.js 的一个模块,负责管理项目中的依赖包。npm 的功能很强大,可以安装、卸载、更新包。它允许我们在代码中引用项目需要的依赖包,并确保项目的依赖结构良好。

2.依赖管理原理&npm install发生了什么?

2.1 早期npm版本【递归】

早期版本如npm1,npm2等,使用的是递归的方式,按照包依赖的树形结构递归遍历安装,每个包和它依赖的包都将全部安装到本地的node_modules下。

如下的树状结构:

java 复制代码
node_modules
└─ A@x.x.x
   ├─ index.js
   ├─ package.json
   └─ node_modules
      └─ B@x.x.x
         ├─ index.js
         ├─ node_modules
         └─ package.json
         C@x.x.x
         ├─ index.js
         ├─ node_modules
         └─ package.json

2.2 后续的npm版本npm3+【扁平化】

将包安装在项目顶层的node_modules中。当安装到相同模块时,判断已安装的模块版本是否符合新模块的版本范围,如果符合则跳过,不符合则在当前模块的node_modules下安装该模块。

如下D包的安装方式:

kotlin 复制代码
├── node_modules
│   ├── A@x.0.0
│   │    ├─ index.js
│   │    ├─ node_modules
│   │    │  ├─ D@1.0.0
│   │    │        ├─ index.js
│   │    │        ├─ node_modules
│   │    │        └─ package.json
│   │    └─ package.json
│   ├── B@x.0.0
│   │    ├─ index.js
│   │    ├─ node_modules
│   │    └─ package.json
│   ├── C@x.0.0
│   │    ├─ index.js
│   │    ├─ node_modules
│   │    └─ package.json
│   └── D@2.0.0
│        ├─ index.js
│        ├─ node_modules
│        └─ package.json

3.优缺缺点

3.1 递归

优点:

  • 层级结构清晰
  • 不存在兼容问题
  • 统一了操作行为和结构

缺点:

  • 相同模块大量冗余
  • 依赖包目录创建结构很深

3.2 扁平

扁平方式并没有完全解决模块重复的问题,如果每个模块依赖的D模块始终都和顶层node_modules中不一致,还是会一直安装重复的模块,

优点:

  • 层级嵌套较浅
  • 减小了磁盘占用

缺点:

  • 还是存在相同模块重复的情况
  • 依赖结构不清晰
  • 项目可以非法访问没有声明过的包
  • 比如:如果 A 依赖 B, B 依赖 C,那么 A 就算没有声明 C 的依赖,由于有依赖提升的存在,C 被装到了 A 的node_modules里面,那我在 A 里面用 C。在B更新后,可能存在使用新的C,不需要C,都会报错。

4.package-lock.json的诞生

项目可以非法访问没有声明过的包就是package-lock.json文件诞生的原因之一

  • 确定性版本控制
    • package-lock.json 文件可以确保项目在不同环境中安装的依赖包版本是一致的,从而实现确定性版本控制。
  • 避免意外升级
    • 避免由于依赖包版本不固定导致的意外升级问题,保证在多人协作或多个环境中安装相同的依赖版本。
  • 减少不必要的冲突
    • 可以减少因依赖包版本冲突而导致的问题,通过锁定每个依赖包的确切版本,避免潜在的冲突。
  • 优化安装速度
    • package-lock.json 文件提供了依赖包的详细信息,可以减少依赖包的下载和安装时间,因为 npm 可以直接使用锁定文件中的缓存信息。
  • 依赖树扁平化
    • 通过 package-lock.json,npm 可以更好地管理依赖树的结构,采用更加扁平化的安装方式,避免重复安装相同依赖的不同版本。
  • 增加安全性
    • package-lock.json 可以帮助检测和防止依赖包的潜在安全漏洞,因为每个包及其依赖项的具体版本都会被记录下来。

🍎 yarn

1.yarn简介

Yarn是由Facebook、Google等公司联合推出的新一代JavaScript包管理工具,针对npm的一些缺点进行了改进,提供了更快、更安全的包管理体验。

2.依赖管理原理&yarn install发生了什么?

使用扁平化的安装模式跟上面后期的npm一致,

3.相对于npm,yarn有什么不同?

这些不同大部分都被后续npm的更新给覆盖了,但是并行下载的效率yarn还是要高一些

  • 安装速度优化 :Yarn 通过并行安装,即同时下载和安装多个依赖包,以及并行构建依赖树,从而加快了安装过程的速度。

  • 可预测性 : Yarn 使用 yarn.lock 文件来确保每次安装的依赖包版本一致,根据该文件精确地确定要安装的依赖版本,从而提高了项目的可重现性。

  • 依赖解析和版本管理 : Yarn 改进了依赖解析算法,有效地减少了依赖树的深度和宽度,优化了依赖包的冲突解决和版本管理,保证了依赖关系的稳定性。

  • 缓存机制 : Yarn 使用全局缓存目录,将重复下载的依赖包存储在本地,减少了网络请求,节省了时间和网络带宽。

  • 更好的用户体验 : Yarn 提供详细的日志信息,包括进度条、警告和错误信息,使开发者能够更方便地了解安装过程,定位和解决问题,提高了用户体验。

  • 离线模式 : Yarn 支持离线模式,通过预先下载依赖包并缓存它们,可以在没有网络连接的情况下仍然能够进行依赖包的安装,提供了更好的灵活性。

  • Workspaces支持 : Yarn 的 Workspaces 功能允许开发者将多个相关的包一起管理,通过一次安装来处理多个包的依赖关系,简化了多包项目的管理流程。

4.优缺点

优点

  • npm扁平化的优点
  • 并行下载和本地缓存效率较高

缺点:

  • 还是存在幽灵依赖的问题
  • 并没有根本上解决npm的问题,仅提供了体验上的优化

🍑 pnpm

1.pnpm简介

pnpm是另一个流行的包管理器,其核心特点在于共享依赖,以及更加高效地管理依赖项。并且支持monorepo,使用硬链接的方式从根本上解决了幽灵依赖的问题。

2.硬链接&软连接

硬链接

  • 硬链接是文件系统中的一种链接方式,它将一个文件与另一个文件的数据块连接在一起。
  • 硬链接指向文件的inode节点(在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(Inode Index)),因此原始文件和硬链接文件都指向相同的数据块。
  • 对一个文件的硬链接进行修改会影响其他所有硬链接,因为它们实际共享同一份数据。
  • 硬链接不能跨越文件系统,只能在同一个文件系统中创建。
  • 硬链接在文件系统中的应用可以节省存储空间,因为数据块不需要多次复制,而是在需要时被多个文件共享。当删除一个硬链接时,只有当所有相关的硬链接被删除后,文件的数据块才会真正释放,否则数据仍然存在于存储介质上。

软链接(符号链接)

  • 软链接是一种特殊的文件,其中存储了指向另一个文件的路径。
  • 软链接本身是一个独立的文件,它的内容是指向另一个文件的路径。如果原始文件更改位置或被删除,软链接就会失效。
  • 软链接可以跨越文件系统,因为它只存储目标文件的路径信息。

主要区别:

  • 数据共享:硬链接共享相同的数据块,而软链接指向另一个文件。

  • 删除文件:删除原始文件后,硬链接仍然可以访问数据,而软链接失效。

  • 跨文件系统:硬链接不能跨文件系统,软链接可以在不同文件系统间创建链接。

3.依赖管理原理&pnpm install发生了什么?

pnpm安装的时候将包和包的依赖全都放置在同一个node_module下面,示例如下,硬连接就是同一个文件的不同引用,而软链接是新建一个文件,文件内容指向另一个路径,等于说就是我在某个全局的地方存储了所有包和依赖硬链接到了.pnpm下,然后我用link软链接去连接所有的包,构成原始的依赖结构。

kotlin 复制代码
├── node_modules
│   ├── A@x.0.0
│   │    ├─ index.js
│   │    ├─ node_modules
│   │    └─ package.json
│   ├── B@x.0.0
│   │    ├─ index.js
│   │    ├─ node_modules
│   │    └─ package.json
│   ├── C@x.0.0
│   │    ├─ index.js
│   │    ├─ node_modules
│   │    └─ package.json
│   ├── D@2.0.0
│   │     ├─ index.js
│   │     ├─ node_modules
│   │     └─ package.json
│   └── D@2.0.0
│        ├─ index.js
│        ├─ node_modules
│        └─ package.json

4.相对于yarn、npmpnpm又优化了什么?

  • 节省磁盘空间
  • 解决了幽灵依赖当然lock文件也解决了这个问题。
  • 并且通过链接而不是复制的方式,更快。

5.缺点

没有在pageage.json中的包是不会被下载的,这导致使用某些第三方包的时候,如果在pageage.json未声明过,则不会下载,你会发现npm|yarn能跑,pnpm不能跑

🥝 npm工程管理

1.项目版本号管理

bash 复制代码
npm version (v)1.0.0  # 显示设置版本号为 1.0.0, v可要可不要
npm version major  # 大版本号加 1,其余版本号归 0
npm version minor  # 小版本号加 1,修订号归 0
npm version patch  # 修订号加 1

# 当前版本号为 1.0.0
npm version prepatch  # 版本号变为 1.0.0-0,也就是 1.0.0 版本的第一个预发布版本
npm version preminor  # 版本号变为 1.1.0-0,也就是 1.1.0 版本的第一个预发布版本
npm version premajor  # 版本号变为 2.0.0-0,也就是 2.0.0 版本的第一个预发布版本
npm version prerelease  # 版本号变为 2.0.0-1,也就是使预发布版本号加一

2.模块 tag 管理

在npm中,tag 是用于标记软件包版本的一种机制。每个发布的软件包都可以分配一个或多个标签,以便用户可以轻松地选择要安装的版本。默认情况下,npm会将latest标签分配给最新发布的版本,但用户也可以为特定版本分配自定义标签,例如betaalpha等。

通过使用标签,开发人员可以在软件包的不同版本之间进行区分,同时也可以为测试版或预发布版分配特定的标签,以便用户知道这些版本可能不稳定或仍在开发中。标签还可以用于指定软件包的稳定版本和特定功能版本,让用户更容易地了解要安装的软件包版本。

基本操作 在npm中,可以使用以下命令来管理软件包的标签:

  • 为软件包发布时指定标签:

    css 复制代码
    npm publish --tag <tagname>

    这会将发布的软件包版本分配给指定的标签。

  • 查看已发布版本的标签:

    bash 复制代码
    npm dist-tag ls <package-name>

    这会列出指定软件包的所有已发布版本及其标签。

  • 添加或更新标签:

    xml 复制代码
    npm dist-tag add <package-name>@<version> <tagname>

    这会为指定软件包的特定版本添加或更新标签。

  • 移除标签:

    xml 复制代码
    npm dist-tag rm <package-name> <tagname>

    这会移除指定软件包的标签。

  • 安装指定标签的软件包:

    xml 复制代码
    npm install <package-name>@<tagname>

    这会安装指定标签的软件包版本。

  • 将软件包标签为最新版本:

    xml 复制代码
    npm dist-tag add <package-name>@<version> latest

    这会将指定版本标记为latest,使其成为默认安装版本。

通过这些操作,开发人员可以更灵活地管理软件包的发布版本,并使用户能够方便地选择要安装的版本。

bash 复制代码
npm dist-tag ls 包名 # 查看包的tag

# 当前版本为1.0.1 
npm version prerelease # 1.0.2-0 
npm publish --tag beta 
npm dist-tag ls xxx # # beta: 1.0.2-0 
npm install xxx@beta # 下载beta版本 1.0.2-0
# 当`prerelease`版本已经稳定了,可以将`prerelease`版本设置为稳定版本:
npm dist-tag add xxx@1.0.2-0 latest
npm dist-tag ls xxx  # latest: 1.0.2-0

🍒 我们来发布一下之前创建的组件库模板

1.发布

先验证下npm是否已经登陆

bash 复制代码
npm who am i

如果没有登陆输入,根据提示输入用户名、密码、邮箱验证。

复制代码
npm login

登录完成后我们配置需要上传到npm的文件,你可以选择在pageage.json文件中设置file字段,也可以配置.npmignore文件指定不需要发布的文件。

json 复制代码
"files": [
	"dist"
],

.npmignore文件指定不需要发布的文件

复制代码
node_modules

我们这里选择,files的配置方式。

先给我们的组件库模板设置一个版本号

发布并设置tag

css 复制代码
npm publish --tag beta

我们去npm看一下,新发布的包是没办法搜到的,但是可以在个人中心查看。

2.安装测试组件库包

新建一个react项目

lua 复制代码
npx create-react-app --template typescript comp_test

安装一下我们的组件库包

css 复制代码
npm i lint_demo

更改一下App.tsx,在引入的时候发现有报错,是因为我们忘记打包了

重新打包然后发布一下,重新安装。

css 复制代码
npm i lint_demo@1.0.2-0   

App.tsx更改如下:

tsx 复制代码
import React from 'react';
import logo from './logo.svg';
import './App.css';
import {Button} from 'lint_demo';
function App() {
  return (
    <div className="App">
      <Button label='Hello World'></Button>
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

yarn start效果如下

🍋 写在最后

如果您看到这里了,并且觉得这篇文章对您有所帮助,希望您能够点赞👍和收藏⭐支持一下作者🙇🙇🙇,感谢🍺🍺!如果文中有任何不准确之处,也欢迎您指正,共同进步。感谢您的阅读,期待您的点赞👍和收藏⭐!

感兴趣的同学可以关注下我的公众号ObjectX前端实验室

🌟 少走弯路 | ObjectX前端实验室 🛠️「精选资源|实战经验|技术洞见」

相关推荐
mldong1 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排2 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60612 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角3 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!4 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰4 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi5 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen6 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马7 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒7 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端