✨
blog
  • Blog
  • Element-UI
    • 2019-09-04
  • JS
    • ES6 之 Set 和 Map
    • let 和 const 声明常见概念
    • 元编程
    • ES6之字符串的扩展
    • ES6 之异步流程的前世今生(上)
    • ES6之异步流程的前世今生(下)
    • ES6 之模块你知吗
    • ES6 之解构赋值与箭头函数的妙用
    • 迭代器
    • ES5 之原型(一)
    • ES6之类(二)
    • es7之装饰器
    • es6之数组详解
    • js之this指向
    • 对象
    • vue项目配合使用canvas联动
    • 本文解决痛点:对象里面是否有值
  • MAC
    • vue源码之method
    • Mac的使用技巧
    • 前文
    • Mac常用软件(二)
    • 如何查看 Mac 端口号以及占用情况
  • Node
    • Node之Buffer详解
    • 浏览器与 node 的事件循环(event loop)有何区别
    • Node之多线程
    • node之模块解析(一)
    • 错误捕获与内存告警
  • TS
    • Record
    • 使用方法
    • 工具泛型
    • 类型体操
    • 泛型
  • chrome
    • v8 引擎
    • v8 垃圾回收机制
    • 浏览器的知识
  • flutter
    • 路由
    • 页面布局
  • go
    • index
  • html&css
    • 两栏布局
    • ES5和ES6的区别
    • ES5 和 ES6 的区别
    • HTTP详解
    • TCP 与 UDP 的区别
    • MDN
    • css modules 使用教程
    • css 居中
    • 拖拽
    • flex布局
    • h5 新增特性 html5
    • history 与 hash 路由策略
    • position 定位方式
    • rem布局
    • svg
    • web性能优化
    • 事件循环
    • 从输入网址后发生了什么
    • 前端状态管理
    • 圣杯布局与双飞翼
    • 性能优化 页面的性能统计指标
    • 本地存储的几种对比
    • 浏览器的渲染进程
    • 浏览器缓存策略详解
    • 盒模型
    • 为什么要移动端适配
    • 跨域的 N 种实现方式
  • web3
    • 常见概念
    • vue项目配合使用canvas联动
  • webgl
    • Mac使用技巧(二)
    • Node之模块解析path
  • 代码库
    • documeng的一些常见操作
    • eventBus事件
    • jquery提交
    • jquery的一些常见操作
    • 常见操作
    • 数组polyfill
    • TS代码片段
      • 面试官眼中的test unit
  • 全年安排
    • AfterShip
    • 大企业
  • 函数编程题
    • Promise问题
    • 继承
  • 前端早早聊
    • vue生态
    • 开发一款VScode语言插件
    • 简历回顾和进行复盘
    • 重新认知性能优化及其度量方法
    • 2022-09-17-音视频专场.md
      • 2022-09-17-音视频专场
    • 前端晋升专场
      • 成长的诀窍是靠自己
      • 销销帮
    • 前端监控专场
      • 字节前端监控实践
      • 李港:大前端-从无到有搭建自研前端监控系统
    • 前端跳槽
      • 50个面试官在线招聘
      • 如何识别优秀的前端猎头来跳槽大厂
      • 面试套路
    • 支付宝
      • 面试
    • 管理专场
      • 芋头:管理者眼中的web技术发展前沿
    • 组件专场
      • 基于webCompents的跨技术组件库实践
    • 面试
      • 面试辅导问题
      • 早早聊面试
      • 前端沙箱是什么? 怎么实现沙箱环境?
  • 常见总结
    • 2018年终总结-年底了,你总结了吗?我先来
    • 在逆境中成长
    • 2021年终总结
    • 2024年全年总结
    • 项目
    • Tell2.0 前端复盘
    • 复盘
    • 前端工程师素养
    • 学习方法论
    • 希望与破晓| 2022 年终总结
    • 新起点, 新征途 | 掘金年度征文
    • 稳定| 2023 年终总结
    • 趁着有风快飞翔 | 2019 年终总结
    • AfterShip
      • Emotion:用 JavaScript 编写 CSS 的强大工具
      • 个人中长期目标
      • 事故复盘
      • 时间解析
      • 国内外区别
      • 独立站建设
    • MEIZU
      • NativeApp与H5通信原理
      • SSR 原理
      • SSR的常见问题
      • CLI
      • electron 应用发布流程
      • electron
      • electron 面试
      • 数据结构与算法之美
      • mgc 一期复盘
      • 架构原理
      • 喵币管理
      • 三期复盘总结
      • 异常监控之 sentry 实践
      • 微前端
      • qiankun 原理解析
      • 快游戏一期
      • 游戏中心复盘
    • 个人准则
      • index
    • 编程猫
      • pc 接入 micro bit 方案
      • prompt engineer
      • web work 跨域解析与解决方式
      • web 中的 ai
      • 低版本 node 环境下 ffmpeg 的使用
      • 关于 taobao 源 https 过期
      • 加密 json
      • 安卓 5 和 6 的白屏解决
      • 性能排查与优化实践
      • 探月接入
      • 接入硬件
      • 新生态下的state
      • monorepo 包管理方式
      • 自修复 npm 库
      • 音频的绘制
    • 谨启
      • 音视频
      • 小程序
        • taro 规范
        • 结合 mobx 在跳转前预请求
        • Taro 浅析用法与原理
        • 前文
        • 小程序优化指南
        • 小程序内部实现原理
        • 支付相关
    • tencent
      • TAPD
        • MathJax的食用
        • canvas渲染优化策略
        • 为什么 JavaScript 是单线程的呢?
        • svg 总是不对
        • 前端库
        • 原生端和js端如何通信
        • 在旧项目中复用vue代码
        • 提升自我
        • 批量编辑优化
        • 插入业务对象
        • 编辑器
        • 挂载点
        • 性能优化对比
        • 遇到的问题
        • 项目迁移公告
        • 领导力
      • 行家
        • 实战篇
        • 职业发展、领导力、个人成长
        • 高质量沟通
  • 慕课网
    • react-native原理
    • react-native学习
  • 杂文
    • Dom 节点变动检测并录制的简单实现
    • 错误监控&错误捕获
    • NextJS与NuxtJS
    • 负载均衡的几种常用方式
    • PM2
    • service worker 控制网络请求?
    • SSL 和 TLS 的区别
    • Babel 你太美
    • echart踩坑经验
    • keyup、keydown你都知道有什么区别吗
    • 常见概念
    • 首屏加载优化与性能指标分析
    • preload 和 prefetch 的详解
    • 在项目中配置这几个关系
    • roullp 解析
    • tinymce原理浅析
    • wasm 在前端的应用
    • websocket
    • webworker
    • 项目
    • 从 ajax 到 axios
    • 从postcss 到自己开发一款插件
    • 从输入浏览器到页面展示涉及的缓存机制
    • 代码整洁之道
    • 你知道什么是aop吗
    • 函数式编程
    • 函数式编程指南
    • 前端input框文字最大值
    • 攻坚战
    • 前端书写 sdk
    • 前端文字转语音播放
    • 前端领域的 Docker 和 Kubernetes
    • 前端安全
    • 前端进阶之内存空间
    • 前端音频浅析
    • 十分钟搞定多人协作开发
    • 字符串的比较
    • 尾递归
    • 前文
    • 常见的算法可以分为以下三类
    • 手机调试--mac篇
    • 数组的原生系列
    • COOP 和 COEP - 新的跨域策略
    • 浅谈react组件书写
    • 浏览器与 Node.js 事件循环的区别
    • 由三道题引伸出来的思考
    • 移动端300ms点击延迟
    • 移动端和pc端事件
    • Git 常见疑惑
    • 我们离发 npm 包还有多远
    • 重绘和重排
    • AI 时代下的前端编程范式
    • 音频可视化实战
  • 极客时间
    • Serverless入门课
    • 二分查找
    • 二叉树
    • 全栈工程师
    • 动态规划面试宝典
    • 前端与rust
    • 散列表
    • 前端方面的Docker和Kubernetes
    • 栈
    • 深入浅出区块链
    • 玩转 vue 全家桶
    • 玩转 webpack
    • 程序员的个人财富课
    • 算法
    • 说透元宇宙
    • 跳表
    • 链表
    • 10x 程序员工作法
      • index
    • Node开发实战
      • HTTP服务的性能测试
      • JavaScript语言精髓与编程实战
      • 什么是node。js
      • svg精髓
    • ReactHooks核心原理与实战
      • ReactHooks核心原理与实战
    • Rust
      • Rust编程第一课
      • 前置篇
      • 深度思维
      • 重构
      • 类型体操
      • 基础知识
    • WebAssembly入门课.md
      • 基础篇
      • SSR的注水和脱水
      • jsBriage通信原理
      • 基础知识篇
    • 互联网的英语私教课
      • 互联网人的英语私教课
    • 代码之丑
      • 代码之丑
    • 前端全链路优化实战课
      • 网页指标
    • 图解 Google V8
      • 图解 Google V8
    • 浏览器工作原理与实践
      • 浏览器工作原理与实践
    • 算法面试通关 40 讲
      • 算法面试通关40讲
    • 跟月影学可视化
      • index
    • 软件设计之美
      • 软件设计之美
    • 重学前端
      • js
  • 后续的文件增加都会增加到上面并以编号对应
    • 1029. 两地调度
    • 151.翻转字符串里的单词
    • 2022.3.15
    • 前端数据结构
    • 前端常见算法
    • 前端常见排序
    • 恢复一棵树
  • 设计模式
    • 前端常见设计模式之MVC与MVVM
    • 前端之代理模式
    • 前端常见设计模式之单例模式
    • 前端常见设计模式之发布订阅模式
    • 前端之工厂模式
    • 观察者模式
    • 前端常见设计模式之适配器模式
  • 译文
    • [译] 如何使用CircleCI for GitHub Pages持续部署
    • 您是否优化了 API 的性能
    • [译][官方] Google 正式发布 Flutter 1.2 版本
    • 什么是 Deno ,它将取代 NodeJS ?
  • 读后感
    • JavaScript二十年
    • 1368个单词就够了
    • js编程精解
    • labuladong 的算法小抄
    • lodash常用方法
    • vue的设计与实现
    • 所有的静态资源都是get请求
    • 人生
    • 人生护城河
    • 你不知道的JavaScript
    • 前端核心知识进阶
    • 华为工作法
    • 反脆弱
    • 好好学习
    • 左耳听风
    • 摩托车维修之道
    • 数学之美
    • 深入理解svg
    • 浏览器的ESM到底是啥
    • 经济学原理
    • 编程珠玑
    • 防御式 css 精讲
    • 韭菜的自我修养
  • 雪狼
    • 2022-07-17
    • 基础知识
    • 阶一课程
      • 实战辅导一
      • 实战辅导二
  • 嵌入式
    • 树莓派
      • 排序
  • 源码
    • React
      • 核心知识点
      • errorBoundaries
      • immutable.js 的实现原理
      • React.Suspense
      • react源码分析之Fiber
      • batchedUpdate
      • Component
      • Context
      • react 源码分析之 diff 算法
      • React 中的 key 属性:原理、使用场景与注意事项
      • 使用方式
      • react源码分析之memo
      • react 源码分析之mixin
      • 实战篇
      • react源码分析之react-dom
      • 使用方式
      • scheduleWork
      • useImperativeHandle的使用与原理
      • React 书写小技巧
      • 入口和优化
      • 合成事件和原生事件的区别
      • react 性能优化
      • 构建一个 hooks
      • 浅析 styled-components
      • 生命周期
      • 组合 vs 继承
      • 通信机制
      • 高阶组件
      • 慕课网
        • 应用篇
        • 课程导学
    • ReactHook
      • useCallback
      • useContext
      • useEffect 与 useLayoutEffect
      • useHook
      • useMemo
      • useReducer
      • 原理
      • useState
      • 总结
    • Redux
      • mobx 原理解析
      • redux-saga
      • redux-thunk
      • Mobx 和 Redux 对比
      • 使用方法
      • redux 原理
    • Vite
      • Vite原理
      • Vite配置
      • 热更新原理
      • vite 为什么生产环境用 Rollup
    • Webpack
      • PostCSS
      • Webpack5 核心原理与应用实践-loader
      • Webpack5 核心原理与应用实践-plugin
      • Webpack5 核心原理与应用实践
      • 区分
      • 升级详情
      • treeShaking(树摇Tree Shaking)
      • 编写一个自己的webpack插件plugin
      • 代码分离(code-splitting)
      • webpack 打包优化
      • 基础配置
      • webpack 打包优化
      • webpack 工作原理
      • webpack 按需加载原理
      • webpack 热更新 HMR(Hot Module Replacement)
      • 缓存
      • webpack 自定义 plugin
    • next
      • tailwind
      • 什么是水合
    • sveltejs
      • index
    • tinymce
      • 并发篇
    • 源码手写系列
      • create
      • call
      • bind
      • call
      • es6 单例
      • forEach vs Map
      • instanceOf
      • new
      • reduce
      • 取两个重复数组的交集
      • 函数柯理化
      • 动态规划
      • 基于Generator函数实现async
      • 新建 js 文件
      • 手写一个 slice 方法
      • 手写一个 webpack loader
      • Plugin
      • 手写一个寄生组合式继承
      • 二叉树
      • 链表相关的操作
      • 手动实现发布订阅
      • 数组去重
      • 数组扁平化
      • 数组
      • 构造大顶堆和小顶堆
      • 深浅拷贝 深拷贝
      • 两者对比
    • vue
      • vue2
        • vm.attrs与$listeners
        • vue 和 react 的 diff 算法比较
        • vue 源码分析
        • vue 优化的 diff 策略
        • extends
        • 核心原理篇
        • keep-alive
        • vue 源码分析之 mixins
        • vue 源码分析之 nextTick
        • vue之slot
        • vnode
        • vue 源码分析之 watch
        • 原理
        • vue 源码分析之transition
        • vue 源码分析之异步组件
        • 调用的是 watch
        • 安装
        • react源码分析之portals
        • event 的实现原理(事件的实现原理)
        • 什么是h
        • 分析provide 和 inject
        • vue 源码分析之 use
        • v-model
        • vue源码分析之vuex
        • 响应式原理
        • 初始化的流程
        • 组件更新
        • 编译
        • 父子组件生命周期
        • 原理
        • 多实例
        • Vue 面试
        • 源码研读一
        • 响应式原理
        • 常见问题
        • 数组的劫持
        • vue之自定义指令
        • 运行机制全局概览
      • vue3相比vue2的提升点
        • vue composition api
        • vue3的虚拟dom优化
        • vue3层面的双向数据绑定
        • 预处理优化
  • 重构
    • notification
      • 讲解
  • 面试
    • AfterShip经历
      • JS对URL进行编码和解码
      • ShippingLabelTemplate
      • 接入keycloak详解
      • reCAPTCHA接入
      • yalc与动态解决升级的依赖包
      • RBAC 简介
      • 多语言计划
      • 接入Google登录及其主动弹出快捷登录方式
      • 读书计划
        • 传染
        • 这就是OKR
    • 编程猫经历
      • 2024.1.16
      • 2025.2.20
      • 2025.2.21
      • 2025.2.26
      • 2025.3.28
      • 2025.3.3
      • 2025.3.7
      • 行动轨迹
      • 面试主观题
    • 腾讯经历
      • 2022.02.21
      • 2022.03.30
      • 2022.04.24
      • 2022.04.25
      • 2022.04.27
      • 2022.04.28
      • 2022.04.29
      • 2022.05.05
      • 不同公司的面试关注点不同
      • 2022.05.07
      • 2022.05.09
      • 2022.05.10
      • 2022.05.11
      • 2022.05.12
      • 2022.05.13
      • 2022.05.16
      • 2022.05.17
      • 2022.05.19
      • 2022.05.27
      • 面试
      • 行动轨迹
      • 面试主观题
    • 针对字节
      • 2022.05.14
      • 2022.05.17
      • HR面试准备
      • Promise的相关题目
      • React 进阶实践指南(二)
      • React 面试准备
      • vue 与 react 有什么不同 (react 和 vue 有什么区别)
      • TypeScript 全面进阶指南
      • cookie和session区别
      • express 面试准备 koa 中间件原理
      • next面试准备
      • requestCallBack
      • interface 与 type 异同点
      • 取消 promise
      • 如何设计一个前端项目
      • 进阶篇
      • 早早聊面试准备
      • 自动化部署
      • 挖掘项目的深度
      • 面试
      • 出题指数
    • 魅族经历
      • 2020.09.11
      • 一灯
      • 一灯
      • 一灯
      • 2020.09.20
      • 2020.09.21
      • 网易二面
      • 2020.09.23
      • 头条
      • 360 金融面试题
      • 富途一面
      • 算法
      • 字节
      • 2020.11.04
      • baidu 一面
      • meta 标签的作用
      • 字节
      • 2020.11.22
      • 2020.11.25
      • 微前端接入笔记
      • 面试的基本原则
由 GitBook 提供支持
在本页
  • monorepo 是什么
  • monorepo 和 multirepo 区别
  • monorepo 的优缺点
  • 复用 package Workspaces
  • 启用 yarn workspace
  • pnpm-workspace
  • lerna 是什么
  • lerna 可以做什么
  • lerna 是如何工作的
  • lerna 的一些相关概念
  • lerna 的原理
  • lerna 常见指令
  • Lerna 与 pnpm/yarn/npm 分工
  • lerna 实战部分
  • pm2 启动命令
  • 安装 lerna
  • lerna 初始化
  • pnpm 安装项目
  • 遇到的坑
  • lerna 最佳实践
  • 参考文献

这有帮助吗?

  1. 常见总结
  2. 编程猫

monorepo 包管理方式

上一页新生态下的state下一页自修复 npm 库

最后更新于2个月前

这有帮助吗?

monorepo 是什么

monorepo 是一种项目架构。 简单来说: 一个仓库内包含多个开发项目(模块、包).

目前使用 lerna 进行多 packages 管理的明星仓库有:

  • babel/babel

  • facebook/create-react-app

  • vuejs/vue-cli

  • webpack/webpack-cli

monorepo 和 multirepo 区别

multirepo 将应用按照模块分别在不同的仓库中进行管理

monorepo 将应用中所有的模块一股脑全部放在同一个项目中

monorepo 的优缺点

  • 各模块独立方便管理(对于 element 来说,修改表单只需要修改 packages 下的 form 目录)

  • 结构清晰(模块独立之后,结构自然清晰)

  • 有依赖的项目之间调试非常方便,上层应用能够感知其依赖的变化,可以很方便的对依赖项进行修改和调试。

  • 缺点就是仓库代码体积可能比较大(一个仓库包含多个项目,项目多了,体积自然会大)

复用 package Workspaces

Workspaces 是设置包架构的一种新方式。他的目的是更方便的使用 monorepo, 具体就是能让你的多个项目集中在同一个仓库,并能够互相引用--被依赖的项目代码修改会实时反馈到依赖项目中。monorepo 中的子项目称为一个 workspace,多个 workspace 构成 Workspaces。

使用 Workspaces(以 yarn 为例)好处:

  • 依赖包可以被 linked 到一起,这意味着你的工作区可以相互依赖,代码是实时更新的。这是比 yarn link 更好的方式因为这只会影响工作区部分,不会影响整个文件系统。

  • 所有项目的依赖会被一起安装,这让 Yarn 更方便的优化安装依赖。

  • Yarn 只有一个 lock 文件,而不是每个子项目就有一个,这意味着更少的冲突。

使用 monorepo 策略后,收益最大的两点是:

避免重复安装包,因此减少了磁盘空间的占用,并降低了构建时间; 内部代码可以彼此相互引用; 这两项好处全部都可以由一个成熟的包管理工具来完成,对前端开发而言,即是 yarn(1.0 以上)或 npm(7.0 以上)通过名为 Workspaces 的特性实现的(⚠️ 注意,支持 Workspaces 特性的 npm 目前依旧不是 TLS 版本)。

为了实现前面提到的两点收益,您需要在代码中做三件事:

  1. 调整目录结构,将相互关联的项目放置在同一个目录,推荐命名为 packages;

  2. 在项目根目录里的 package.json 文件中,设置 Workspaces 属性,属性值为之前创建的目录;

  3. 同样,在 package.json 文件中,设置 private 属性为 true(为了避免我们误操作将仓库发布);

 .
 ├── package.json
 └── packages/
     ├── @mono/project_1/ # 推荐使用 `@<项目名>/<子项目名>` 的方式命名
     │   ├── index.js
     │   └── package.json
     └── @mono/project_2/
         ├── index.js
         └── package.json

在项目根目录中执行 npm install 或 yarn install 后,您会发现在项目根目录中出现了 node_modules 目录,并且该目录不仅拥有所有子项目共用的 npm 包,还包含了我们的子项目。因此,我们可以在子项目中通过各种模块引入机制,像引入一般的 npm 模块一样引入其他子项目的代码

启用 yarn workspace

默认是 npm,每个子 package 下都有自己的 node_modules,如果使用 yarn workspace,可以共享 node_modules,减少安装时间

"private": true,

"workspaces": [

    "packages/*"

],

pnpm-workspace

安装依赖包 使用 pnpm 安装依赖包一般分以下几种情况:

全局的公共依赖包,比如打包涉及到的 rollup、typescript 等

pnpm 提供了 -w, --workspace-root 参数,可以将依赖包安装到工程的根目录下,作为所有 package 的公共依赖。 比如:

pnpm install react -w

如果是一个开发依赖的话,可以加上 -D 参数,表示这是一个开发依赖,会装到 pacakage.json 中的 devDependencies 中,比如:

pnpm install rollup -wD

给某个 package 单独安装指定依赖

pnpm 提供了 --filter 参数,可以用来对特定的 package 进行某些操作。 因此,如果想给 pkg1 安装一个依赖包,比如 axios,可以进行如下操作:

pnpm add axios --filter @codemao/monorepo1

需要注意的是,--filter 参数跟着的是 package 下的 package.json 的 name 字段,并不是目录名。 关于 --filter 操作其实还是很丰富的,比如执行 pkg1 下的 scripts 脚本:

pnpm build --filter @codemao/monorepo1

filter 后面除了可以指定具体的包名,还可以跟着匹配规则来指定对匹配上规则的包进行操作,比如:

pnpm build --filter "./packages/\*\*"

此命令会执行所有 package 下的 build 命令。具体的用法可以参考 filter 文档。

模块之间的相互依赖

最后一种就是我们在开发时经常遇到的场景,比如 pkg1 中将 pkg2 作为依赖进行安装。 基于 pnpm 提供的 workspace:协议,可以方便的在 packages 内部进行互相引用。比如在 pkg1 中引用 pkg2:

pnpm install @codemao/monorepo2 -r --filter @codemao/monorepo1

此时我们查看 pkg1 的 package.json,可以看到 dependencies 字段中多了对 @codemao/monorepo2 的引用,以 workspace: 开头,后面跟着具体的版本号。

{
  "name": "@codemao/monorepo1",
  "version": "1.0.0",
  "dependencies": {
    "@codemao/monorepo2": "workspace:^1.0.0",
    "axios": "^0.27.2"
  }
}

在设置依赖版本的时候推荐用 workspace:*,这样就可以保持依赖的版本是工作空间里最新版本,不需要每次手动更新依赖版本。 当 pnpm publish 的时候,会自动将 package.json 中的 workspace 修正为对应的版本号。

我们面临的问题:

  1. 如果我们需要在多个子目录执行相同的命令,我们需要手动进入各个目录,并执行命令;

  2. 当一个子项目更新后,我们只能手动追踪依赖该项目的其他子项目,并升级其版本。

lerna 是什么

Lerna 是一个工具,它优化了使用 git 和 npm 管理多包存储库的工作流。

lerna 可以做什么

  1. 将一个大的 package 拆分成多个小的 package,便于分享和调试

  2. 多个 git 仓库中更改容易变得混乱且难以跟踪

  3. 多个 git 仓库中维护测试繁琐

lerna 是如何工作的

lerna 有两种模式让你去管理你的项目:固定(Fixed)或独立(Independent)。

  1. Fixed/Locked 模式(默认)

固定模式。该模式为单版本号,在根目录中的 lerna.json 中设置。当使用 lerna publish 时,如果自从上次发布后有模块改动,那么将会更新到新发布的版本。

这也是目前 Babel 用的模式,当你想要自动整合不同包的版本时使用这个模式。它的特点是任何 package 的 major change 均会导致所有包都会进行 major version 的更新。

  1. Independent 模式

// 独立模式的 lerna.json
{
  "packages": ["packages/*"],
  "version": "independent"
}

独立模式。该模式中允许开发者独立管理多个包的版本更新。每次发布时,会得到针对每个包改动(patch, minor, major custom change)的提示。lerna 会配合 git,检查文件变动,只发布有改动的 package。

独立模式允许你更具体地更新每个包的版本,并且对于一组组件是有意义的。将这种模式和 semantic-release 结合起来就不会那么痛苦了。

独立模式允许开发者更新指定 package 的版本。将 lerna.json 中的 version 键设为 independent 来启用独立模式。

lerna 的一些相关概念

{
  "version": 当前仓库的版本。,
  "npmClient": 一个选项执行客户端使用哪种命令运行。npm 和 yarn,
  "packages": 要用作包位置的全局变量数组。,
}

默认情况下,lerna 初始化 packages 值为["packages/"], 但是也可以使用自定义目录 ["modules/"]或["package1", "package2"].

lerna 的原理

lerna 常见指令

lerna bootstrap

在当前 Lerna 仓库中执行引导流程(bootstrap)。安装所有 依赖项并链接任何交叉依赖。

lerna bootstrap --scope=@codemao/components

此命令至关重要,因为它让你可以 在 require() 中直接通过软件包的名称进行加载,就好像此软件包已经存在于 你的 node_modules 目录下一样。

lerna import

将本地路径 中的软件包导入(import) packages/ 中并提交 commit。

增加指定的包

1. lerna add @codemao/hooks packages/components
2. lerna add lodash --scope=@codemao/components --dev

删除指定的包

1. pnpm remove @codemao/hooks --filter @codemao/components

2. lerna exec 'pnpm remove loadsh' --scope=@codemao/components

更新的工作

lerna publish

lerna diff [package?] 列出所有或某个软件包自上次发布以来的修改情况。

lerna run [script] 在每一个包含 [script] 脚本的软件包中运行此 npm 脚本。

lerna ls 列出当前 Lerna 仓库中的所有公共软件包(public packages)。

lerna clean

删除所有包下面的 node_modules 目录,也可以删除指定包下面的 node_modules。 注意: 不会删除 package.json 里面的依赖项定义,也不会删除 root 目录的 node_modules。

lerna clean --scope=@codemao/components

Lerna 与 pnpm/yarn/npm 分工

lerna 利用语义链接来实现这一目的。它还允许使用 yarn 工作空间,然后,将整个 Mono-Repo 方面的工作完全交给 yarn 工作空间的本地实现的功能。

在 Mono-Repo 工作流中使用 yarn 工作空间。 使用 lerna 的实用命令来优化多个包的管理,例如,选择性地执行 npm 脚本进行测试。

  • 使用 lerna 发布软件包,因为 lerna 的版本和发布命令提供了复杂的功能。

通俗来讲就是:

包管理的能力交给 Lerna, 如版本管理; 依赖管理的能力交给 pnpm, 如依赖包的安装删除;

lerna 实战部分

pm2 启动命令

准备工作

  1. npm install pm2 -g

  2. npm install --global verdaccio

  3. pm2 start verdaccio

  4. verdaccio

安装 lerna

  1. pnpm install lerna -g

lerna 初始化

在当前根目录下执行: lerna init --independent

pnpm 安装项目

pnpm install lerna@5.3.0 -D -w

pnpm dlx lerna init

通过 lerna add @codemao/hooks packages/components

发包 lerna publish from-package

遇到的坑

lerna publish 主要做了以下几件事:

  • Run the equivalent of lerna updated to determine which packages need to be published.

  • If necessary, increment the version key in lerna.json.

  • Update the package.json of all updated packages to their new versions.

  • Create a new git commit and tag for the new version.

  • Publish updated packages to npm.

• 检查从上一个 git tag 之后是否有提交,没有提交就会显示 No changed packages to publish 的信息,然后退出 • 检查依赖了修改过的包的包,并更新依赖信息 • 提交相应版本的 git tag • 发布修改的包及依赖它们的包

如果 lerna.json 并没有更新,重试一下

lerna publish。

如果已经更新,您可以强制重新发布。

lerna publish --force-publish '\*'

lerna 最佳实践

  1. 采用 independent 模式

  2. 根据 Gi 提交信息,自动生成 changelog

  3. eslint 规则检查

  4. prettier 自动格式化代码

  5. 提交代码,代码检查 hook

  6. 遵循 semver 版本规范

参考文献

启动后

Update all dependencies of the updated packages with the new versions, specified with a .

caret (^)
JavaScript and TypeScript Monorepos
lerna 管理前端 packages 的最佳实践
基于 lerna 和 yarn workspace 的 monorepo 工作流
Monorepos: Please don’t!
Monorepo: please do!
monorepo架构
重新发布
发包效果
页面效果
未登录