从0开始搭建一个Monorepo模版,基于Turborepo+pnpm+changesets+dumi

news2024/11/16 19:33:08

Monorepo

  • 前言
  • 开始
    • 一、使用turborepo初始化项目
    • 二、调整目录结构及文件
      • 1. 调整`package.json`文件
      • 2. 调整app目录
      • 3. 调整`eslint`包
      • 4. 调整`ui`包
      • 5. 调整eslint配置
      • 6. 调整.npmrc
      • 7. 使用commitizen规范代码提交
      • 8. 使用commitlint+husky进行 commit提交信息校验
      • 9. 使用husky进行commit前的规范校验
    • 三、dev run
    • 四、打包
      • ts与eslint
      • UI
    • 五、发版
      • 修改所有的包名
      • 使用Changesets进行版本管理并发版
  • 总结

前言

当你想要搭建一个Monorepo时,相信你已经调研过很多技术选型,之前我也使用过yarn+workspace+lerna+dumi开发过一套组件库,后续有时间把这套工具也抽一个模版。

因为pnpm本身支持workspace并且lerna已经停止维护,因此决定使用新的工具从新搭建一套Monorepo模版,那么这套工具就是:

  • pnpm—包管理器
  • turborepo—外壳
  • changesets—版本号管理、changelog管理
  • dumi—文档预览
  • 其他的规范代码的工具如:—commitizeneslintlint-stagedcommitlinthusky

你可能对Turborepo不太了解,他的官方解释是高性能的JavaScript和TypeScript代码库构建系统,他在这只是作为一个壳子用来提升开发及打包效率,不用了解太多。

开始

一、使用turborepo初始化项目

  1. pnpm dlx create-turbo@latest
  2. 选择目录(项目名)、选择包管理器
    在这里插入图片描述
  3. 项目初始化完成,具体的目录结构什么意思可以去Turborepo看一下,不看也没关系,因为后续我们要调整它。
    在这里插入图片描述

我现在这里的turbo的version是1.10.12,如果你很晚看见这篇文章,可能版本有了很大不同。

  1. 链接gitHub仓库,当然这一步不是必须的,链接它的目的只是为了测试规范代码的工具是否生效。
    git remote add origin https://github.com/Atw-Lee/monorepo-template.git

不要划走:Monorepo可以用来管理多应用工程(app目录下的各种工程),所有工程依赖相同的UI,而Turborepo初始化的项目也是这么干的。但是,我需要的是搭建一个我的UI组件库,这是与它不同的地方,app下我只需要一个文档预览工程(dumi),因此,我需要调整它的目录结构

二、调整目录结构及文件

1. 调整package.json文件

  • 安装eslint@latest(eslint提到全局,并更新到最新版本)
  • 安装@changesets/cli(版本号、changelog管理)
  • 安装commitizen cz-conventional-changelog(规范commit信息)
  • 安装@commitlint/cli @commitlint/config-conventiona husky(检验commit信息)
  • 安装lint-staged stylelint(校验规范格式)
  • 安装father(打包)
  • 增加"preinstall": "npx only-allow pnpm"只允许使用pnpm包管理器

pnpm i -Dw eslint@latest @changesets/cli commitizen cz-conventional-changelog @commitlint/cli @commitlint/config-conventional husky lint-staged stylelint father


2. 调整app目录

  • 删除web及docs目录的所有内容
  • 新建docs目录并初始化dumi项目
    在这里插入图片描述
  • 进入docs目录执行git init
  • 删除.fatherrc.ts文件(不需要在这打包组件)
  • .gitignore文件增加docs-dist(该目录为dumi的build产物)
  • 修改package.json文件:
    • 删除docs:build
    • 修改build:dumi build(打包直接是该文档工程打包,不打包组件)
    • 删除moduletypesfiles配置(用不着)
    • 依赖删除与外边重复的(commitlint、eslint、father、husky、lint-staged、stylelint等)

3. 调整eslint

我不准备使用它默认的eslint,因为我用不到nextjs相关的内容,我选择使用Tencent的eslint-config-alloy

  • 进入packages/eslint-config-custom目录,手动删除不需要的依赖,pnpm i eslint-config-alloy安装alloy
  • 更新eslint-plugin-react(后续补充,不是最新的出错了)

  1. 调整tsconfig
  • 删除package.json的private属性(为了后续可以正常发版)
  • 删除nextjs.js文件(不需要next的ts配置)

在这里插入图片描述


4. 调整ui

  • 删除turbo目录(用不着)
  • package.json文件删除generate脚本(用不着)
  • package.json文件删除eslint依赖(外边已经有了)
  • package.json文件新增脚本"build": "father build"(打包组件,app里的docs不需要了,因为UI组件包的开发在这里)
  • package.json文件修改main属性"main": "./src/index",
  • package.json文件修改types属性"main": "./src/index",
  • 新建src目录,增加button组件
    在这里插入图片描述
  • 修改tsconfig.json文件
{
  "extends": "tsconfig/react-library.json",
  "include": ["src"],
  "exclude": ["lib", "dist", "es", "node_modules"]
}
  • 新增.fatherrc.ts文件
import { defineConfig } from "father";
export default defineConfig({
  // more father config: https://github.com/umijs/father/blob/master/docs/config.md
  esm: { output: "es" },
  cjs: { output: "lib" },
});
  • .gitignore文件增加lib及es(该目录为ui通过father打包产物,具体名称还是根据上一步的配置来)
  • .gitignore文件删除next相关的(用不到)

5. 调整eslint配置

module.exports = {
  root: true,
  extends: ["custom"],
};

6. 调整.npmrc

  • 增加registry=你公司的私有源,开发的UI组件库发布到这(在这直接定义注册地址就比较方便了)

7. 使用commitizen规范代码提交

  • package.json文件增加"commit": "cz"脚本
  • package.json文件增加config属性
  "config": {
    "commitizen": {
      "path": "node_modules/cz-conventional-changelog"
    }
  }
  • 执行 pnpm commit测试
    在这里插入图片描述

8. 使用commitlint+husky进行 commit提交信息校验

  • 根目录新增commitlint.config.js文件
module.exports = { extends: ["@commitlint/config-conventional"] };
  • package.json文件增加"postinstall": "husky install"
  • 执行pnpm i生成.husky文件,初始化husky。完成后可删除postinstall属性
  • 执行npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'生成commit-msg的hook
  • package.json文件增加commitlintlint-staged属性
	"commitlint": {
    "extends": [
      "@commitlint/config-conventional"
    ]
  },
	  "lint-staged": {
    "*.{md,json}": [
      "prettier --write --no-error-on-unmatched-pattern"
    ],
    "*.{css,less}": [
      "stylelint --fix",
      "prettier --write"
    ],
    "*.{js,jsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{ts,tsx}": [
      "eslint --fix",
      "prettier --parser=typescript --write"
    ]
  },
  • 执行错误的commit信息测试
    在这里插入图片描述

9. 使用husky进行commit前的规范校验

  • 执行npx husky add .husky/pre-commit "npx --no-install lint-staged"
  • 上一步已经添加完成了lint-staged属性
  • 执行commit进行校验
    在这里插入图片描述

三、dev run

  • 执行pnpm dev:页面正常打开dumi运行的应用
  • docs的package.json增加ui的依赖"ui": "workspace:*"
  • 页面中使用ui包中的button组件
    在这里插入图片描述
    到这我们的运行时的组件与文档预览已经ok了,接下来就是ui组件的打包

四、打包

ts与eslint

他俩不需要打包,都是些配置项

UI

上文我们已经设置好了father打包的配置文件,直接执行pnpm build
在这里插入图片描述
生成了对应的lib和es文件夹,docs也跟着打包了,这里是turborepo的操作逻辑,我们不用关心它

  • ui的package.json中新增files属性
  • ui的package.jsonmain、types属性也要做一个修改,之前是./src
  "main": "./lib/index",
  "types": "./lib/index",
  "files": [
	  "es",
	  "lib",
	  "dist"
	],

五、发版

接下来就需要把我们的包发布到我们的私有源上了,当然开源也没有问题

我们现在有三个包,分别是eslint、typescript、ui
我们的包肯定不能叫这个名字,那我们给他们改下名字,加上组织的前缀,我这里以@you-org为例

修改所有的包名

在这里插入图片描述
该变更中的文件均有需要修改

使用Changesets进行版本管理并发版

  • 执行pnpm changeset init生成.changeset文件
  • 执行pnpm changeset选择要发布的包
    在这里插入图片描述
  • 选择版本(一版fix是patch,feat是minor)
    在这里插入图片描述
  • 执行changeset version增加版本号
    在这里插入图片描述
  • commit提交
  • 执行pnpm -r publish --tag alpha0.1.0发布版本
    在这里插入图片描述
    OK到这里就结束了~

总结

收获:从0开始搭建了一个多包(Monorepo)的UI组件模版,了解了一个简单开源UI工程应该具有的工具及搭建步骤。

不足之处在于:

  • 组件库的打包使用rollup可能会更好,但是因为额外的学习成本,还是使用了dumi上自带的father
  • 除了ui包,应该在添加一个utils包,这样才更加具有Monorepo的特性
  • tsconfigeslint包不确定是否有必要单独提成一个包,如果项目很复杂的话,eslint和tsconfig需要灵活配置的话,可能会更有用吧
  • 缺少了一些脚本,通过脚本来减少复杂的原生命令
  • 需要额外的脚手架来协调模版工作,以便不需要更改额外的package.json文件,后续也会做这方面的工作

参考文章

  • 打造高效Monorepo:Turborepo、pnpm、Changesets实践
  • pnpm + workspace + changesets 构建你的 monorepo 工程
  • 在 pnpm 中使用 Changesets
  • Creating a new monorepo

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3 - 使用reactive定义响应式数据进行列表赋值时,视图没有更新的解决方案

文章目录 1,问题2,原因3,解决方案一、再封装一层数据,即定义属性名,在后期赋值的时候,对此属性进行直接赋值三、使用数组的splice来直接更改原数组三、使用 ref 来定义数据 1,问题 在Vue 3.0 中…

pythonocc进阶学习:投影projection

1.点 到 线, 直线,曲线,等上的投影 staticmethod # 点到Lin的投影 def Project_Pnt_To_Lin(p: gp_Pnt, lin: gp_Lin):Edge BRepBuilderAPI_MakeEdge(lin).Edge()curve BRep_Tool.Curve(Edge)proPnt GeomAPI_ProjectPointOnCurve(p, curve[0])NearestPoint proPnt.Nearest…

JVM虚拟机篇

JVM组成 面试题1:什么是程序计数器? 面试题2:你能给我详细的介绍Java堆吗? 面试题3:什么是虚拟机栈? 面试题4:垃圾回收是否涉及栈内存? 垃圾回收主要指就是堆内存,当栈帧弹栈以后…

全开源国外购物商城手机APP页面装修功能开发

搭建一个全开源国外购物商城手机APP页面装修功能开发需要以下步骤: 1. 确定需求:首先,需要明确页面装修功能的具体需求。例如,是否需要支持自定义布局、颜色、字体等;是否需要支持多种商品展示方式(列表、…

misc学习(1)Bugku-社工-进阶收集

新手一枚,参考文献如下: Bugku:社工-进阶收集_bugku 社工 进阶收集_FW_ENJOEY的博客-CSDN博客 照片如图所示: 线索线: 1.百度识图 发现是大雁塔 2.主角家距离大雁塔一共有七站地铁,其中要进行中转。 同时…

噼里啪啦 图像分类篇

1. LeNet初始化权重的问题 由于我使用的是torch 1.10.0的版本,其Conv2d的init是使用asqrt(5) 我将这里的torch默认初始化改为a1之后,acc的对比如下:可以看出:更改初始化之后,5个epoch,acc提高了3个点。改为…

数组相关练习

数组练习 将数组转化成字符串数组拷贝求数组元素的平均值查找数组中指定元素(顺序查找)二分查找冒泡排序数组逆序 将数组转化成字符串 import java.util.Arrays;public class Text1 {public static void main(String[] args) {int[] arr {5, 6, 4, 2};System.out.println(Arr…

机器学习中训练数据的重要性

人工智能技术发展至今,训练数据的重要性已经是我们老生常谈的问题。在重声训练数据为什么重要之前,我们先重新回顾下AI技术大爆炸的三大初始概念:机器学习是什么?人工智能是什么?训练数据又是什么? 机器学…

《Kali渗透基础》14. 无线渗透(四)

kali渗透 1:相关工具1.1:Aircrack-ng1.1.1:airmon-ng1.1.2:airodump-ng1.1.3:aireplay-ng1.1.4:airolib-ng1.1.5:bessid-ng 1.2:JTR1.3:Evil Twin Attacker1.4&#xff1…

Vue 中使用 WebWorker

目录 安装 loader 应用场景 打包时错误处理 安装 loader npm install worker-loader -D 如果直接把worker.js放到public目录下,则不需要安装loader vue.config.js const { defineConfig } require(vue/cli-service)module.exports defineConfig({transpileDe…

JS逆向系列之猿人学爬虫第14题-备而后动-勿使有变

文章目录 题目地址参数分析参考jspython 调用往期逆向文章推荐题目地址 https://match.yuanrenxue.cn/match/14题目难度标的是困难,主要难在js混淆部分。 参数分析 初始抓包有无限debugger反调试,可以直接hook 函数构造器过掉无限debugger Function.prototype.__construc…

C++异常体系

文章目录 一.C对运行时错误的处理方式函数调用链中的异常机制 二.异常的使用规范三.C异常体系C标准库中的异常体系 四.关于C异常的注意事项 一.C对运行时错误的处理方式 传统的C语言处理运行时错误采用的是assert或者错误码的方式,这种异常处理机制对错误信息的定位和描述能力…

ArcGIS Pro技术应用(暨基础入门、制图、空间分析、影像分析、三维建模、空间统计分析与建模、python融合)

GIS是利用电子计算机及其外部设备,采集、存储、分析和描述整个或部分地球表面与空间信息系统。简单地讲,它是在一定的地域内,将地理空间信息和 一些与该地域地理信息相关的属性信息结合起来,达到对地理和属性信息的综合管理。GIS的…

lc137. 只出现一次的数字 II

数组排序,既和前不一样又和后不一样的就是唯一的一个 public static int numberOnce(int[] nums) {Arrays.sort(nums);if (nums.length > 2 && nums[0] ! nums[1]) {//避免只有一个元素的数组return nums[0];}if (nums.length > 2 && nums[nu…

994. 腐烂的橘子

题目描述&#xff1a; 主要思路&#xff1a; 宽度优先搜索&#xff0c;利用队列实现。 需要注意的是放进队列的时候就需要标记&#xff0c;而不是取出的时候再标记。 class Solution { public:int orangesRotting(vector<vector<int>>& grid) {int ngrid.siz…

解决Spring Boot 2.6及之后版本取消了循环依赖的支持的问题

目录 1、问题&#xff1a; 2、报错&#xff1a; 3、解决方案&#xff1a; 1、问题&#xff1a; 循环依赖指的是两个或者多个bean之间相互依赖,形成一个闭环。直接表现为两个service层互相调用对方。 此时会遇到以下问题&#xff1a; 2、报错&#xff1a; 当启动项目时&…

Smartbi 权限绕过漏洞复现(QVD-2023-17461)

0x01 产品简介 Smartbi大数据分析产品融合BI定义的所有阶段&#xff0c;对接各种业务数据库、数据仓库和大数据分析平台&#xff0c;进行加工处理、分析挖掘和可视化展现&#xff1b;满足所有用户的各种数据分析应用需求&#xff0c;如大数据分析、可视化分析、探索式分析、复杂…

odoo-033 比较 float 浮点数大小之精度坑

文章目录 前提原因问题 前提 产品单位精确到6位小数生产制造模块&#xff0c;重写了完成的方法&#xff0c;在点击完成的时候报错如下&#xff1a; &#xff08;解释下&#xff1a;就是很奇怪&#xff0c;明明都是必填字段&#xff0c;也都赋值了但是就是拿不到值&#xff09;…

2.若依前后端分离版第一个增删查改

1.介绍 若依提供了代码生成功能&#xff0c;单表的CRUD可以直接用若依框架提供的代码生成进行创建。 2.实现 2.1 在数据库创建业务表test_teacher 2.2 生成代码 运行系统&#xff0c;进入菜单[系统工具]-》[代码生成],点击导入按钮&#xff0c;选择需要生成代码的表进行导…

Redis储存结构

Redis怎么储存的 这个redisDb是数据库对象 里面的其他字段忽略了 然后里面有个dict列表(字典列表) 我们随便来看一个redisObject 区分一下子啊 他这个dict里面没有存redisObject的对象 也没有存dict对象 它只是存了个数据指针 你看那个redis每个底层编码 抠搜的 这块要是再保存…