React 组件库都是怎么打包的?

大家都用过组件库,react 流行的组件库有阿里的 ant-design、字节的 semi-design、arco-design 等。

那这些组件库都是怎么打包的呢?

我们自己写个组件库的话,怎么写打包逻辑呢?

这篇文章我们就来探究下。

新建一个项目:

bash 复制代码
mkdir component-lib-test

cd component-lib-test

npm init -y

分别安装 ant-design、arco-design、semi-design

bash 复制代码
pnpm install antd

pnpm install @douyinfe/semi-ui

pnpm install @arco-design/web-react

npm、yarn 会把所有依赖铺平,看着比较乱。而 pnpm 不会,node_modules 下很清晰:

首先看下 antd,分为了 lib、es、dist 3 个目录:

分别看下这三个目录的组件代码:

lib 下的组件是 commonjs 的:

es 下的组件是 es module 的:

dist 下的组件是 umd 的:

然后在 package.json 里分别声明了 commonjs、esm、umd 还有类型的入口:

这样,当你用 require 引入的就是 lib 下的组件,用 import 引入的就是 es 下的组件。

而直接 script 标签引入的就是 unpkg 下的组件。

再来看看 semi-design 的:

也是一样:

只不过多了个 css 目录。

antd 没有这个目录是因为它已经换成 css in js 的方案了,不需要单独引入 css 文件。

然后是 arco-design 的:

也是一样:

同样是 lib、es、dist 3 个目录,同样是分别声明了 esm、commonjs、umd 的入口。

也就是说,组件库都是这样的,分别打包出 3 份代码(esm、commonjs、umd),然后在 package.json 里声明不同模块规范的入口。

那问题来了,如果我有一个 esm 的模块,怎么分别构建出 esm、commonjs、umd 的 3 份代码呢?

这个问题很容易回答。

umd 的代码用 webpack 打包就行。

esm 和 commonjs 的不用打包,只需要用 tsc 或者 babel 编译下就好了。

我们分别看下这三个组件库都是怎么做的:

先是 arco-design 的:

它的打包逻辑在 arco-cli 的 arco-scripts 下:

看下这个 index.ts

分别有 build 3 种代码加上 build css 的方法。

我们分别看下:

esm 和 cjs 的编译它封装了一个 compileTS 的方法,然后传入不同的 type。

compileTS 里可以用 tsc 或者 babel 编译:

tsc 编译就是读取项目下的 tsconfig.json,然后 compile:

babel 编译是基于内置配置,修改了下产物 modules 规范,然后编译:

babelConfig 里配置了 typescript 和 jsx 的编译:

再就是 umd:

和我们分析的一样,确实是用 webpack 来打包:

webpack 配置里可以看到,确实是为了 unpkg 准备的,用了 ts-loader 和 babel-loader:

而 css 部分则是用了 less 编译:

gulp 是用来组织编译任务的,可以让任务串行、并行的执行。

这里的 gulp.series 就是串行执行任务,而 gulp.parallel 则是并行。

所以说,那 3 种代码加上 css 文件是怎么打包的就很清晰了:

其中用到 gulp 只是用来组织编译任务的,可用可不用。

再来看下 semi-design 的:

它就没有单独分一个 xx-scripts 包了,直接在 semi-ui 的 scripts 目录下。

它也是用到了 gulp 来组织任务。

看下这个 compileLib 的 gulp task:

这里的 compileTSXForESM 和 ForCJS 很明显就是编译组件到 esm 和 cjs 两种代码的。

先用了 tsc 编译再用了 babel 编译:

然后是 umd,也是用了 webpack:

用了 babel-loader 和 ts-loader:

最后是 scss 的编译:

semi-design 把所有组件的 scss 都放在了 semi-foundation 这个目录下来维护:

所以编译的时候就是这样的:

就是把 semi-foundation 这个目录下的所有 scss 编译后合并成了一个文件

而 arco-design 的样式是在组件目录下维护的:

这个倒是没啥大的区别,只是编译的时候改下源码目录就好了。

这就是 semi-design 的 esm、cjs、umd、scss 是如何编译打包的。

和 arco-design 的 scripts 区别大么?

不大,只不过没有单独做一个 xxx-scripts 的包,编译出 esm 和 cjs 代码用的是 tsc + babel,而且用的是 scss 不是 less 而已。

再来看看 ant-design 的:

它也是单独分了一个包来维护编译打包的 scripts,叫做 @ant-design/tools。

它也有个 gulpfile 定义了很多 task

比如 compile 的 task 是编译出 es 和 cjs 代码的:

是不是很熟悉的感觉?

大家都是这么搞的。

它也是先用了 tsc 再用 babel 编译,最后输出到 es 或者 lib 目录:

打包 umd 代码的时候也是用了 webpack:

只不过它这个 webpack 配置文件是读取的组件库项目目录下的,而不像 arco-design 那样是内置的。

这就是这三个组件库的编译打包的逻辑。

区别大么?

不大,甚至可以说几乎一模一样。

总结

我们分析了 ant-design、semi-design、arco-design 组件库的产物和编译打包逻辑。

它们都有 lib、es、dist 目录,分别放着 commonjs、es module、umd 规范的组件代码。

并且在 package.json 里用 main、module、unpkg 来声明了 3 种规范的入口。

从产物上来看,三个组件库都是差不多的。

然后我们分析了下编译打包的逻辑。

ant-design 和 acro-design 都是单独抽了一个放 scripts 的包,而 semi-design 没有。

它们编译 esm 和 cjs 代码都用了 babel 和 tsc 来编译,只不过 arco-design 是用 tsc 或者 babel 二选一,而 ant-design 和 semi-design 是先用 tsc 编译再用 babel 编译。

打包出 umd 的代码,三个组件库都是用的 webpack,只不过有的是把 webpack 配置内置了,有的是放在组件库项目目录下。

而样式部分,ant-design 是用 css-in-js 的运行时方案了,不需要编译,而 arco-design 用的 less,样式放组件目录下维护,semi-design 用的 scss,单独一个目录来放所有组件样式。

并且编译任务都是用的 gulp 来组织的,它可以串行、并行的执行一些任务。

虽然有一些细小的差别,但从整体上来看,这三大组件库的编译打包逻辑可以说是一模一样的。

写这样的 scripts 麻烦么?

并不麻烦,umd 部分的 webpack 打包大家都会,而 esm 和 cjs 用 babel 或者 tsc 编译也不难,至于 scss、less 部分,那个就更简单了。

所以编译打包并不是组件库的难点。

如果你要写一个组件库,也可以这样来写 scripts。

相关推荐
咖啡の猫25 分钟前
Shell脚本-for循环应用案例
前端·chrome
百万蹄蹄向前冲3 小时前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
朝阳5813 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路3 小时前
GeoTools 读取影像元数据
前端
ssshooter4 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
你的人类朋友4 小时前
【Node.js】什么是Node.js
javascript·后端·node.js
Jerry5 小时前
Jetpack Compose 中的状态
前端
dae bal5 小时前
关于RSA和AES加密
前端·vue.js
柳杉6 小时前
使用three.js搭建3d隧道监测-2
前端·javascript·数据可视化
lynn8570_blog6 小时前
低端设备加载webp ANR
前端·算法