高效前端工程化:Monorepo、pnpm与Vue3集成实战指南

引言

在当今快速发展的前端开发领域,高效地管理和组织代码库成为提升开发效率的关键。随着项目规模的扩大,传统的单体仓库逐渐显露出局限性,而新兴的包管理工具如 PNPM、项目结构模式如 MonorepoTurborepo 开始受到广泛关注。将教会大家如何快速搭建 monorepo + pnpm + trborepo +vue3 + element-plus 项目架构。

pnpm:下一代包管理器

pnpm(Package Manager) 是一个快速、节省磁盘空间的 JavaScript 包管理器,它通过引入“链接”和“硬链接”的概念来优化 Node.js 项目的依赖管理。与 npmYarn 相比,pnpm 在安装依赖时,会创建依赖的唯一实例,并通过硬链接或符号链接的方式供各个项目共享,大大减少了磁盘占用和安装时间。此外,pnpm 的精确依赖解析机制能有效避免“dependency hell”,保障项目的稳定性和可复现性。

Monorepo:一统天下的仓库策略

Monorepo(单一仓库)是一种将多个相关项目的源代码存储在一个单一版本控制系统仓库中的策略。这种模式下,无论是微服务架构的后端服务,还是包含多个前端应用的大型项目,都可以共处一室,共享配置、依赖和工具链。Monorepo 的优势在于简化跨项目协作、代码复用、统一版本管理和 CI/CD 流程。然而,随之而来的是对版本控制系统的高效管理需求,以及如何处理大型仓库带来的构建速度问题。

Turborepo:为Monorepo加速

Turborepo 正是针对 Monorepo 模式下构建速度慢的问题提出的一种解决方案。它通过智能缓存、并行执行和增量构建等技术,显著加快了 Monorepo 中项目的构建和测试速度。Turborepo 能够识别出哪些文件或包没有变化,从而跳过不必要的工作,仅重新构建那些受影响的部分。这种优化对于大型组织而言尤为重要,它使得即使仓库包含成百上千个子项目,开发者也能获得接近即时的反馈循环,极大提升了开发效率。

单体仓库与上述方案的对比

相比之下,传统的单体仓库是指一个项目对应一个仓库的模式,适用于小型项目或初创阶段的项目。在单体仓库中,所有源代码、配置文件和依赖都紧密耦合在一起,便于管理但难以扩展。随着项目复杂度增加,代码库的维护成本和团队间的协调成本会迅速上升。

  • 可维护性与扩展性MonorepoTurborepo 由于支持跨项目共享和高效管理,明显优于单体仓库,尤其适合中大型项目和企业级应用。

  • 开发效率pnpm 通过优化依赖管理提升安装速度;Turborepo 则通过智能构建机制,解决了 Monorepo 的构建效率问题,两者共同推动了开发效率的飞跃。

  • 协作与代码复用Monorepo 鼓励跨项目代码共享,而 Turborepo 在此基础上进一步优化了协作体验,单体仓库在这方面则显得较为局限。

架构搭建

1.创建项目

新建文件夹自定义命名,暂且为 monorepo-demo,然后用VSCode编辑器打开,新建终端,操作如下:

2.利用 pnpm init 在根目录初始化

PS G:\wokespace\FullStackProjects\pnpm-monorepo-demo> pnpm init
Wrote to G:\wokespace\FullStackProjects\pnpm-monorepo-demo\package.json{"name": "pnpm-monorepo-demo","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC"
}
PS G:\wokespace\FullStackProjects\pnpm-monorepo-demo>

打开 package.json 文件,"private": true 加这个为防止我们意外地将私有项目发布。

3. 根据pnpm中的文档在根目录创建 pnpm-workspace.yaml 文件

根据自己项目需求创建合适的目录结构,示例如下:

4.在 packages 文件下创建存放 公共的UI组件 (ui) 和公共的工具函数 (utils) 两个项目

  • 新建 uiutils 文件夹,并利用 pnpm init 进行初始化。同时在各自的 package.json 文件中 新增属性 "private": true, 其中 name 属性值,可以自定义合适的名称。

ui 项目的名称这里自定义为 @repo/uiutils 项目的名称这里自定义为 @repo/utils

  • ui 项目下自定义新建 components 文件夹,用来存放公共的UI组件,暂时新建两个组件 FormatMoney.vueSlider.vue;然后同层级下新建 index.js 文件来导出组件提供外部访问。
  1. 利用 element-plus UI组件来开发公共UI组件,因此先安装依赖
pnpm i vue element-plus
  1. 编写 FormatMoney.vue, Slider.vue, index.js 文件

FormatMoney.vue

<template><el-formref="formRef"style="max-width: 600px":model="numberValidateForm"label-width="auto"class="demo-ruleForm"><el-form-itemlabel="金额"prop="money":rules="[{ required: true, message: '金额不能为空' },{ type: 'number', message: '金额是数字类型' },]"><el-inputv-model.number="numberValidateForm.money"type="text"autocomplete="off"/></el-form-item><el-form-itemlabel="格式化后的金额"prop="amount" ><el-inputv-model="numberValidateForm.amount"type="text"autocomplete="off"readonly/></el-form-item><el-form-item><el-button type="primary" @click="submitForm(formRef)">格式化</el-button><el-button @click="resetForm(formRef)">重置</el-button></el-form-item></el-form>
</template><script setup>
import "element-plus/dist/index.css";
import { ElForm, ElFormItem, ElInput, ElButton } from "element-plus";
import { reactive, ref } from 'vue'
import { formatMoney } from "repo-utils";console.log('formatMoney', formatMoney(2342113241, '$'));const formRef = ref()const numberValidateForm = reactive({money: '',amount: ''
})const submitForm = (formEl) => {if (!formEl) returnformEl.validate((valid) => {if (valid) {numberValidateForm.amount = formatMoney(numberValidateForm.money, '$');console.log('submit!')} else {console.log('error submit!')}})
}const resetForm = (formEl) => {if (!formEl) returnformEl.resetFields()
}
</script>

Slider.vue

<script setup>
import "element-plus/dist/index.css";
import { ElSlider } from "element-plus";
import { ref } from 'vue'const value1 = ref(0)
</script><template><div class="slider-demo-block"><span class="demonstration">默认值</span><el-slider v-model="value1" /></div>
</template><style scoped>
.slider-demo-block {max-width: 600px;display: flex;align-items: center;
}
.slider-demo-block .el-slider {margin-top: 0;margin-left: 12px;
}
.slider-demo-block .demonstration {font-size: 14px;color: black;width: 120px;padding: 10px;
}
</style>

index.js

import FormatMoney from './components/FormatMoney.vue'
import Slider from './components/Slider.vue'export {FormatMoney,Slider
}
  1. UI 项目最后的目录结构如下:

  • utils 项目下新建两个文件 fun.js (存放各种工具方法)index.js (提供对外访问的方法)

fun.js

// 弹窗提示
export const tips = (message, title = "提示") => {window.alert(`${title}: ${message}`)
}// 加运算
export const addOperation = (a, b) => {window.alert(`1加2的结果是${a + b}`);
}// 格式化金额
export const formatMoney = (money, symbol = "", decimals = 2) => {return (Math.round((parseFloat(money) + Number.EPSILON) * Math.pow(10, decimals)) / Math.pow(10, decimals)).toFixed(decimals).replace(/\B(?=(\d{3})+\b)/g, ",").replace(/^/, `${symbol}`)
};

index.js

export * from "./fun.js";

5. 利用 vite 工具在 apps 文件下创建各种子项目,暂且创建 docsweb 两个项目,操作如下:

pnpm create vite 

执行上面的命令,按照提示一步步根据自己需求创建两个项目,最终目录结构如下:

6.回到根目录,在根目录下全局安装 @repo/ui@repo/utils ,这样在任何子应用或者子包都可以相互使用。 如果要安装到根项目中(即全局项目中)那么可以在指令后面加上 -w

pnpm i -w @reop/ui @repo/utils

安装完毕后,可以在 package.json 文件中看到如下信息:

7.在子项目 docsweb 中使用

  • 进入 web 项目,将 App.vue 文件内容修改如下:
<script setup>
import { tips } from "repo-utils";
import { FormatMoney } from "repo-ui";
</script><template><h1>web项目</h1><FormatMoney></FormatMoney>
</template><style scoped>
h1 {margin-bottom: 50px;
}
</style>
  • 进入 docs 项目,将 App.vue 文件内容修改如下:
<script setup>
import { tips } from "repo-utils";
import { FormatMoney, Slider } from "repo-ui";
tips("我是docs项目");
</script><template><h1>docs项目</h1><Slider></Slider>
</template>
<style scoped>
h1 {margin-bottom: 50px;
}
</style>

分别启动项目,运行效果如下:

使用 Turborepo 构建打包

1.全局安装 Turborepo

pnpm i -g turbo# 检测是否安装成功
λ turbo --version
1.13.3

2.根目录新建文件 turbo.json, 默认内容如下:

{"$schema": "https://turbo.build/schema.json","globalDependencies": ["**/.env.*local"],"pipeline": {"build": {"dependsOn": ["^build"],"outputs": [".next/**", "!.next/cache/**", "dist/**"]},"lint": {"dependsOn": ["^lint"]},"dev": {"cache": false,"persistent": true}}
}

3.在根目录下修改 package.json 文件,添加执行命令脚本, 具体如下:

4. 进入各个子项目或者子包中,修改 .gitignore 文件,增加如下内容:

.turbo
build/
dist/
.next/

5.根目录执行 pnpm devpnpm build,会对子项目全量启动或打包,具体如下:

  • 全量启动项目
λ pnpm dev> monorepo-demo@1.0.0 dev G:\wokespace\FullStackProjects\pnpm-monorepo-demo
> turbo dev• Packages in scope: docs, repo-ui, repo-utils, web
• Running dev in 4 packages
• Remote caching disabled
docs:dev: cache bypass, force executing 0906b5c91c3b269b
web:dev: cache bypass, force executing b446edc8270ef0f2
docs:dev:
docs:dev: > docs@0.0.0 dev G:\wokespace\FullStackProjects\monorepo-demo\apps\docs
docs:dev: > vite
docs:dev:
web:dev:
web:dev: > web@0.0.0 dev G:\wokespace\FullStackProjects\monorepo-demo\apps\web
web:dev: > vite
web:dev:
docs:dev: Port 5173 is in use, trying another one...
web:dev:
web:dev:   VITE v5.2.8  ready in 20313 ms
web:dev:
web:dev:   ➜  Local:   http://localhost:5173/
web:dev:   ➜  Network: use --host to expose
web:dev:   ➜  Vue DevTools: Open http://localhost:5173/__devtools__/ as a separate window
web:dev:   ➜  Vue DevTools: Press Alt()+Shift()+D in App to toggle the Vue DevTools
web:dev:
docs:dev:
docs:dev:   VITE v5.2.8  ready in 20368 ms
docs:dev:
docs:dev:   ➜  Local:   http://localhost:5174/
docs:dev:   ➜  Network: use --host to expose
docs:dev:   ➜  Vue DevTools: Open http://localhost:5174/__devtools__/ as a separate window
docs:dev:   ➜  Vue DevTools: Press Alt()+Shift()+D in App to toggle the Vue DevTools
docs:dev:
  • 全量打包子项目
λ pnpm build> monorepo-demo@1.0.0 build G:\wokespace\FullStackProjects\monorepo-demo
> turbo build• Packages in scope: docs, repo-ui, repo-utils, web
• Running build in 4 packages
• Remote caching disabled
web:build: cache miss, executing 5987b2c98bceeb10
docs:build: cache miss, executing aff8ae65ab7f527e
web:build:
docs:build:
web:build: > web@0.0.0 build G:\wokespace\FullStackProjects\monorepo-demo\apps\web
web:build: > vite build
web:build:
docs:build: > docs@0.0.0 build G:\wokespace\FullStackProjects\monorepo-demo\apps\docs
docs:build: > vite build
docs:build:
web:build: vite v5.2.8 building for production...
docs:build: vite v5.2.8 building for production...
web:build: transforming...
docs:build: transforming...
web:build: ✓ 1435 modules transformed.
docs:build: ✓ 1435 modules transformed.
docs:build: rendering chunks...
web:build: rendering chunks...
docs:build: computing gzip size...
web:build: computing gzip size...
docs:build: dist/index.html                       0.43 kB │ gzip:  0.29 kB
web:build: dist/index.html                       0.43 kB │ gzip:  0.29 kB
docs:build: dist/assets/AboutView-C6Dx7pxG.css    0.09 kB │ gzip:  0.10 kB
web:build: dist/assets/AboutView-C6Dx7pxG.css    0.09 kB │ gzip:  0.10 kB
web:build: dist/assets/index-B_6bWB-a.css      328.68 kB │ gzip: 45.17 kB
web:build: dist/assets/AboutView-9L8e1QJt.js     0.23 kB │ gzip:  0.20 kB
docs:build: dist/assets/index-DM4ReSuC.css      328.68 kB │ gzip: 45.17 kB
web:build: dist/assets/index-BUYK55Bj.js       175.04 kB │ gzip: 65.02 kB
docs:build: dist/assets/AboutView-CgU-TZmY.js     0.23 kB │ gzip:  0.20 kB
docs:build: dist/assets/index-wHPYhhNI.js       195.12 kB │ gzip: 72.35 kB
web:build: ✓ built in 14.67s
docs:build: ✓ built in 14.67sTasks:    2 successful, 2 total
Cached:    0 cached, 2 totalTime:    25.729s

关于 Turborepo 具体教程,请参考官网文档进行查阅,目前正在翻译官网文档,后续会开放浏览地址供阅览。

写在最后

至此一步步完成了利用 pnpm, monorepo, turborepo 等技术搭建多项目多包统一仓库管理的架构,解决了项目规模扩大后的管理难题,提高了开发效率和团队协作水平。选择合适的工具和策略,对提升项目成功率至关重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/702633.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据生命周期管理:从提取到治理再到安全保障的全面策略

在大数据的时代背景下&#xff0c;数据已经成为企业运营不可或缺的资源。然而&#xff0c;数据的管理并非易事&#xff0c;特别是在数据的整个生命周期中——从数据的提取、治理到安全保障&#xff0c;每一个环节都至关重要。本文将探讨如何制定一个全面的数据生命周期管理策略…

java AOP环绕通知记录操作日志

一.创建数据库日志表 CREATE TABLE uc_system_log (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID,user_code varchar(64) DEFAULT NULL COMMENT 用户编码,user_name varchar(128) DEFAULT NULL COMMENT 用户名称,is_login tinyint(4) NOT NULL DEFAULT 0 COMMENT 是…

电脑录屏软件有哪些?这3款神器必须要知道

在当今现代社会&#xff0c;电脑录屏软件已经成为人们日常生活中不可或缺的一部分。无论是录制游戏精彩瞬间、制作教程、还是在线会议记录&#xff0c;一款好用的电脑录屏软件都能帮助我们更高效地完成任务。可是电脑录屏软件有哪些呢&#xff1f;接下来&#xff0c;我们将介绍…

通过windows远程桌面,远程连接CentOS系统

1.配置阿里云的YUM仓库 1.1 备份当前的YUM仓库配置文件 sudo cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup1.2 下载阿里云的CentOS仓库配置文件 对于CentOS 7&#xff1a; sudo wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirr…

不懂数字后端Box List、Polygon的意思?

什么是BOX&#xff1f; 景芯SoC做design planning的第一步就是确定floorplan的box&#xff0c;也就是设计的区域。这个区域可以划分为三个边界&#xff0c;如下图所示&#xff1a; Die Box 最外面一圈&#xff0c;我们称为 Die Box&#xff0c;也就是用来放置 IO 单元&#x…

Matlab进阶绘图第54期—密度散点图(概率密度版)

在之前的文章中&#xff0c;分享过Matlab密度散点图的绘制方法&#xff1a; 此版内容用到了一些点云数据处理中求取密度的知识&#xff0c;对部分人来说&#xff0c;可能有些不好理解。 于是&#xff0c;本期内容使用Matlab自带的ksdensity函数进行密度散点图(概率密度版)的绘…

Mixtral

文章目录 一、关于 MixtralMistral AI、 La PlateformeMistral AI LLMs 二、Mistral AI API账户设置 三、Mixtral 说明通过稀疏架构推动开放模型的前沿表现Instructed 模型使用开源部署堆栈部署 Mixtral在我们的平台上使用 Mixtral。 一、关于 Mixtral 官网&#xff1a;https:…

【汇编】算术指令

一、加法指令 &#xff08;一&#xff09;各加法指令的格式及操作 加法指令可做字或字节运算 &#xff08;1&#xff09;加法指令 ADD 格式&#xff1a;ADD DST,SRC执行的操作&#xff1a;(DST) ← (SRC)(DST) &#xff08;2&#xff09;带进位加法指令 ADC 格式&#xf…

记录用python转换headers

转换前 转换后效果 代码如下。注意需要在控制台切换到content.txt所在位置&#xff0c;不然运行代码会报file not found错误 # 假设txt文件内容如下 txt open(content.txt).read()# 使用splitlines()方法将txt内容分割为行&#xff0c;然后使用json.loads()方法将每一行转换为…

unapp写微信小程序封装水印相机组件怎么实现?

<template><view><!-- <cu-custom bgColor"bg-gradual-blue" :isBack"true"><block slot"backText">返回</block><block slot"content">编辑资料</block></cu-custom> --><…

如何使用AzurEnum快速枚举Microsoft Entra ID(Azure AD)

AzurEnum是一款针对Azure的安全工具&#xff0c;在该工具的帮助下&#xff0c;广大研究人员可以轻松快速地枚举Microsoft Entra ID&#xff08;Azure AD&#xff09;。 该工具基于纯Python 3开发&#xff0c;可以在Windows和Linux系统上运行&#xff0c;但考虑到性能和稳定性&a…

网易云如何改ip地址到另外城市

在数字化时代&#xff0c;网络音乐平台已经成为我们日常生活中不可或缺的一部分。然而&#xff0c;有时候我们可能会因为某些原因想要改变自己的IP地址&#xff0c;网易云音乐作为国内领先的音乐平台&#xff0c;其强大的功能和丰富的音乐资源吸引了大量用户。那么&#xff0c;…