rushjs+pnpm之monorepo初探

9,954 阅读8分钟

前言

所在开发团队内部因为项目比较多,所以在项目上大家采用了monorepo这种项目,也就是把团队内的所有项目都统一放到一个代码仓库里面,公共的一些包和组件抽取成独立子项目或者子组件放在同个monorepo项目里面,这样方便复用组件,相关的好处网络上也有不少的文章说到,这里就不展开细说。关于monorepo的模块管理工具其实有不少,在此之前有lerna yarn等,笔者所在的团队之前是用yarn来管理monorepo的,最近做一些优化,改用rushjs+pnpm来管理,这篇blog作为笔者的一些初探学习。

技术选型

rushjs
pnpm
monorepo
tsdx

rushjs 走读

Rush makes life easier for JavaScript developers who build and publish many NPM packages at once. If you’re looking to consolidate all your projects into a single repo, you came to the right place! Rush is a fast, professional solution for managing this scenario.

摘抄自官网的introduction,简单讲就是rush的出现方便js开发者一次构建和发布多个npm包,如果考虑所有的project都放到同一个代码仓库里面的话(monorepo)可以考虑使用rush,rush为此提供了快速有效的解决方案。
rush的一些特点(来自官方文档):

  • A single NPM install: rush 将你所有的项目的依赖安装到一个公共的文件夹,这个的作用不仅仅只是类似于项目根目录下的package.json,rush还通过符号链(symlinks)去重构每个项目的node_modules.这个逻辑支持 pnpm npm yarn这几种包管理器。
  • Automatic local linking: rush repo里面的每个项目都可以自动符号链到其他的项目,不需要发布包,也不需要任何npm link.
  • Fast builds: rush会分析你的依赖图谱然后按照正确的顺序构建你的项目,如果两个项目之间是没有任何依赖的,rush会通过分开的进程来按照这些依赖,这种多进程的方式会比采用单线程的方式有明显的加速。
  • Subset and incremental builds: 子集和增量构建,在一个非常大的代码仓库里面,如果只是想使用或者开发其中一两个项目,这时候我们可以指定构建单独的项目,rush rebuild --to 只对你的上游依赖关系进行干净的构建,当你做了一些更改之后 rush rebuild --from <project> 只对受影响的下游项目进行干净的构建。
  • Cycli dependencies: 循环依赖关系,如果一个项目间接依赖于自己的旧版本时,循环中的项目使用最后发布的版本,而其他项目仍然获得最新的。(这个笔者看的时候不是特别理解,大概的意思就是可以很好的管理多个不同版本之间的循环依赖吧)
  • Bulk publishing: 当需要对代码仓库里面的多个包做release的时候,rush会检测出那些包发生了更改,自动修改所有合适的版本号,然后在每个目录下执行npm publish
  • Changelog tracking: 有变动的时候自动将变动信息聚合到一个CHANGELOG.md文件

pnpm 相关

笔者也是接触不久,这方面也是参考掘金上其他同学的文章
juejin.cn/post/693204…

环境

  1. 环境,笔者使用的MAC,使用window的同学可能有些不一样,本文还是以MAC这种开发环境来描述
  2. 安装nodejs(出于开发方便可能还要装一下nvm,方便切换不同的node版本,这里提一句,nvm的安装还是有不少网络限制的,可能要走不少弯路。。。)
  3. 安装yarn 非必须,个人的开发习惯是从npm转换到yarn的,所以自己本地是有安装yarn,有需要的可以自行安装

初始化工作

创建一个空的目录作为项目目录

mkdir eason-td-monorepo
cd eason-td-monorepo

安装rush(使用yarn安装,或者使用npm也行)

yarn global add @microsoft/rush

image.png

安装pnpm

yarn global add pnpm

image.png

rush初始化项目

rush init

image.png

使用编辑器打开,我这里用的是vscode,打开后看一下rush.json, emmm,一片警告

image.png 这时候不要慌,因为这是个json配置文件,json配置文件一般是不允许有comment的,vscode内置了一种类型叫JSON with Comments,专门来识别这种类型,在右下角这里切换一下类型,切换到JSON with Comments就不会显示警告报错了,这里不展开细讲

image.png 按上面的一步处理完之后,可以看到这边还是有一些拼写提示,虽然不是很重要,这里还是处理一下,可忽略该步骤

image.png vscode打开setting,搜索cSpell.words,添加进入这个pnpm,之后应该就不会有报错提醒

image.png

image.png

rush.json里面可以指定运行的工具,这里是指pnpm,npm, yarn这几个,我们这里指定pnpm就可以,其他的也可以玩一下,这里就不展开细讲

rush.json里面有一大堆配置和comment,emmm,这里也不仔细去研究,先看关键的,可以看一下projects这个配置,因为我们要创建的是一个monorepo项目,所以到时候会有多个子项目在这个monorepo项目里面,所以到时候可以重点关注一下这个

再来看一下目录下的这个位置common/config/rush,下面有一个对应的pnpmfile.js文件,如果我们不是用pnpm的话,可以删除这个文件,当然啦,这里不要删除,我们用的就是pnpm

image.png

创建子项目

在项目的根目录项目创建一个apps的路径,用于放置我们的子项目,我们这里创建一个landing的子项目

mkdir apps
cd apps
yarn create react-app landing

运行完上面的命令后会回去install各种依赖,这个过程会有点长,然后我们回到上面说的那个rush.json里面的projects配置项,为我们新增的这个子项目增加一个项目名还有指定对应的目录,如下

image.png

运行完之后我们再运行一个命令,这时候只要是在项目目录下即可,可以不用在项目的根目录,rush自己会处理识别这个

rush update

image.png

image.png

install完成之后,切换到apps/landing目录下运行这个子项目,可以用npm、yarn或者rushx运行项目,rushx是在我们全局安装rush之后会带的一个命令,这里我们推荐用rushx

cd apps/landing
rushx start

image.png

这时候会运行本地项目,然后在本地的浏览器打开该项目的页面,默认是3000端口,如果本地3000端口被占用的话会提示是否用其他端口,这时候输入yes即可

image.png

image.png

到这里一步的话我们的一个子应用算是跑起来了,我们这个项目是monorepo项目,所以单独一个项目是不够的,还需要多其他的子项目来实验,这里我们继续创建项目(control + c 结束运行刚刚的项目)

创建第二个子项目

回到项目根目录,创建一个libs目录,这个目录的作用类似于library,把一些共用的组件或者包之类的放在这个目录

cd ../../
mkdir libs
cd libs

这个时候我们需要借助一个工具叫tsdx来创建我们的子组件项目,创建一个components的子项目,tsdx会提供三个模板供选择,这里我们选react就可以

npx tsdx create components

image.png

image.png

切换到创建出来的路径,运行一下子应用,运行没有报错,我们就control+c结束运行

cd components
rushx start

image.png

新增多了一个project,这时候我们要在rush.json里面增加这个project的配置信息

image.png

这里我们给新创建的project命名为@shared/components,需要注意的是,在我们创建的libs/components/package.json里面有默认的name,这里我们要保持两边统一,这样才可以识别到具体对应的project

image.png 回到项目根目录更新一下,这时候会重新安装依赖

cd ../../
rush update --purge

运行结束之后我们尝试一下在landing这个项目里面安装刚刚声明的“包”,因为这时候rush知道我们引用的是一个本地monorepo项目里面的包,所以不会尝试着通过网络去npm查找这个对应的包

cd apps/landing
rush add --package @shared/components

image.png

我们可以看到提示,现在是link的的project成功,下一步推荐运行build或者rebuild

rush build

image.png

在landing项目中引用@shared/components,我们改一下apps/landing/src/App.js

import logo from './logo.svg';
import './App.css';
import { Thing } from '@shared/components';

function App() {
  return (
    <div className="App">
      <Thing />
    </div>
  );
}

export default App;

重新运行起这个apps/landing这个应用

rushx start

image.png 可以看到这时候已经可以正常link引入本地的包了,到这一步基本上我们的monorepo项目就告一段落

结语

本次只是一个初探,关于rush和pnpm等工具还有很多不懂的地方,文中若有不妥之处,还望各位读者同学雅正。

后续文章:rushjs+pnpm之monorepo rush进阶

广告

内推,欢迎投简历
jobs.bytedance.com/referral/pc…
小鹏汽车: app.mokahr.com/recommendat…