如题,大家在日常开发中针对可复用的ui及逻辑,都会在项目中封装组件,以达到复用的目的。目前市面上也有很多优秀的ui组件库,像antd、vant等,这些框架也给我们日常开发提供了很多的便利,本文使用react框架 搭配rollup来分享一下,如何开发维护一个我们自己的组件库。
技术选型
编译工具
目前市面上的构建工具主要有webpack、vite、rollup以及gulp,rollup总能打出更小体积的包,vite本身也是集成rollup,之后添加更多的功能及插件,但是组件库相对来说不是很需要,所以这里使用rollup进行编译。
文档工具
目前主要使用的是两个,一个是 storybook,现在github star数量是80.8k ,使用更广泛。另外一个是 Dumi和father-build,目前star数量是3.3k,但是阿里出品,中文文档方便一些。这两者都可以自动生成文档,极大提高项目可维护性,这里选用storybook。
包管理工具
这里使用yarn,npm的包管理相对混乱,pnpm在实际使用中,发现安装存在一定问题,经常丢包,所以这里使用yarn作为包管理工具
框架
使用react@18.2进行开发,css预编译工具为scss,typescript版本为@5.2.2,大家可以结合自己的情况自由选择,编译库所用工具为rollup,storybook预览组件项目库时,使用webpack进行编译,node版本为18.17.0,eslint + prettierrc进行代码检测,项目最终目录结构为
lua
.
|-- package.json
|-- public
| |-- favicon.ico
| |-- index.html
| |-- logo192.png
| |-- logo512.png
| |-- manifest.json
| `-- robots.txt
|-- readme.md
|-- rollup.config.mjs
|-- src
| |-- Introduction.stories.mdx
| |-- assets
| | |-- close.svg
| | |-- phone.svg
| | `-- verify.svg
| |-- components
| | |-- login
| | | |-- AtLogin.tsx
| | | |-- index.scss
| | | |-- login.stories.mdx
| | | |-- login.stories.tsx
| | | `-- index.tsx
| | |-- login-popup
| | | |-- AtLoginPopup.tsx
| | | |-- index.scss
| | | |-- index.ts
| | | |-- loginPopup.stories.mdx
| | | |-- loginPopup.stories.tsx
| | | `-- show.tsx
| | `-- button
| | |-- Button.stories.mdx
| | |-- Button.tsx
| | `-- index.ts
| |-- demo
| | `-- login
| | `-- index.tsx
| |-- global
| | |-- global.scss
| | |-- index.ts
| | |-- theme-dark.scss
| | `-- theme-default.scss
| |-- index.ts
| |-- react-app-env.d.ts
| |-- type.d.ts
| `-- utils
| |-- attach-properties-to-component.ts
| |-- axios.ts
| |-- index.ts
| |-- native-props.ts
| |-- render-imperatively.tsx
| `-- renderToBody.tsx
|-- tsconfig.json
|-- yarn-error.log
`-- yarn.lock
基础架构搭建
快速开始
使用create-react-app创建一个初始项目,执行命令:
lua
npx create-react-app my-component --template typescript
接入storybook
使用storybook,如果你不熟悉storybook,请前往storybook学习了解。
bash
cd ./my-component
npx storybook init
执行完成后,此时在项目根目录下执行:
arduino
yarn run storybook
将在本地启动 Storybook 并输出地址。
新增组件
在src目录下创建components,并在components目录下,创建button文件夹,添加文件如下图:

其中index.ts
文件主要处理一些导入导出及其他必要的公共逻辑,组件文件为Button.tsx,为单纯的组件:

Button.stories.mdx
为文档文件,语法几乎等同markdown语法,如图,可从storybook
中导出三个组件
- Meta // 用于生成文档菜单
- Story // 用于渲染真正的业务组件
- Canvas // 用于渲染story组件

在上图中,<Canvas>
组件包裹的部分,会在页面真正渲染。

如需进一步完善文档,可在同级目录中添加 stories.tsx
文件,通过增减配置,可以生成可编辑的预览页面,配置可参考如下:
编译
使用rollup进行编译,配合terser进行混淆压缩,以降低代码体积,具体配置可参考如下:

上图中,箭头所指的地方可以实时进行修改,页面实时预览
javascript
/* eslint-disable import/no-unresolved */
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import strip from '@rollup/plugin-strip';
import typescript from '@rollup/plugin-typescript';
import autoprefixer from 'autoprefixer';
import path from 'path';
import externals from 'rollup-plugin-node-externals';
import postcss from 'rollup-plugin-postcss';
import json from '@rollup/plugin-json';
import pluginUrl from '@rollup/plugin-url';
import terser from '@rollup/plugin-terser';
import pkg from './package.json' assert { type: 'json' };
export default [
{
input: './src/index.ts',
output: [{
dir: path.dirname(pkg.module),
format: 'es',
name: pkg.name,
exports: 'named', // 指定导出模式(自动、默认、命名、无)
preserveModules: true, // 保留模块结构
preserveModulesRoot: 'src', // 将保留的模块放在根级别的此路径下
}],
plugins: [
externals({
devDeps: false,
}),
json(),
resolve(),
pluginUrl(),
commonjs(),
typescript({
outDir: 'es',
declaration: true,
declarationDir: 'es',
tsconfig: 'tsconfig.json',
}),
postcss({
plugins: [
autoprefixer(),
],
}),
terser(), // 压缩
strip(),
],
},
];
编译后即可得到制品,再方式npm或者私有源即可