使用Vite构建cjs和esm格式的React组件库

背景

React 有很多现成的组件库,例如 Material UI 和 Ant Design 等都可以拿来直接用。为什么还要自己搭建 React 的组件库?

其实我们现实中会出现很多定制化的需求,并不能完全直接使用组件库的组件完成,多或少都会对上面的组件进行修改或者二次封装;这些定制化的需求,可能会应用到现实中的所有相同类型的项目当中,把这部分公共的组件抽离出来就更加有必要了。

思路

实现 TypeScript 类型支持的 React 组件库思路

  1. *.tsx 文件导出并打包成 esmcjs 等结构的 *.js 文件。
  2. 生成 *.d.ts 类型文件,让组件库支持 TypeScript 类型。
  3. *.css 样式文件与 *.tsx 文件分离,有利于实现组件和样式的按需加载。

实现

一. 初始化项目

方法一:

首先,确保您在机器上已经安装了Node.js。然后,在终端中执行以下命令来全局安装Vite:

js 复制代码
npm install -g create-vite

接下来,使用Vite初始化一个新的React项目:

arduino 复制代码
create-vite my-component-library --template template-react-ts

方法二(推荐):

js 复制代码
# npm 7+, extra double-dash is needed:
npm create vite@latest my-component-library --template template-react-ts

# yarn
yarn create vite my-component-library --template template-react-ts

# pnpm
pnpm create vite my-component-library --template template-react-ts

# Bun
bunx create-vite my-component-library --template template-react-ts

这个命令将会创建一个名为my-component-library的目录,并在其中生成一些初始化的React项目文件。

二、组件开发和导出

进入到my-component-library目录中,您可以开始编写属于您组件库的React组件。

lua 复制代码
|-- src
    |-- components
        |-- Button.tsx
        |-- Input.tsx
    |-- main.js

例如,您可以在src目录下创建一个Button.tsx文件,编写一个简单的按钮组件:

js 复制代码
import React from 'react';

function Button({ text, onClick }) {
  return (
    <button onClick={onClick}>
      {text}
    </button>
  );
}

export default Button;

在这里,我们编写了一个Button组件,并通过export default语句进行导出。

三、配置Vite

配置Vite构建选项 在my-component-library目录下,找到并打开vite.config.js文件。在文件中添加以下配置选项:

php 复制代码
// vite.config.js
import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react-swc";
import { resolve, join } from "path";
import { visualizer } from "rollup-plugin-visualizer";

export default defineConfig({
  plugins: [react(), visualizer() as any],
  build: {
    lib: {
      entry: 'src/main.ts', // 组件库的入口文件
      name: 'MyComponentLibrary', // 组件库的全局变量名
      fileName: format => `my-component-library.${format}.js`, // 构建输出的文件名
    },
    rollupOptions: {
      external: ['react', 'react-dom'], // 外部依赖
      output: [
      // ES Module 模块格式的编译
        {
            format: "es",
            entryFileNames: "[name].mjs",
            preserveModules: true,
            exports: undefined,
            dir: resolve(__dirname, `es`),
            preserveModulesRoot: "src",
       },
       // CommonJS 模块格式的编译
       {
            format: "cjs",
            entryFileNames: "[name].js",
            //让打包目录和我们目录对应
            preserveModules: true,
            exports: "named",
            //配置打包根目录
            dir: resolve(__dirname, `lib`),
            preserveModulesRoot: "src",
	},
    ],
    },
  },
});

在上述配置中,我们使用build.lib.entry来指定组件库的入口文件(例如src/main.ts),build.lib.name来指定组件库的全局变量名(例如MyComponentLibrary),build.lib.fileName指定构建输出的文件名,可以根据需要使用不同的格式(例如escjs)。此外,我们还配置了外部依赖(如reactreact-dom)和对应的全局变量名。

四、配置tsconfig.build.json

my-component-library目录下新建一个tsconfig.build.json文件。

js 复制代码
// tsconfig.build.json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "declaration": true,
    "emitDeclarationOnly": true,
    "outDir": "./es",
    "noEmit": false
  },
  "include": [
    "src"
  ]
}

五、配置package.json

js 复制代码
...
"name": "my-component-library",
"version": "1.0.0",
"scripts": {
+ "build": "rimraf es && tsc && vite build && tsc --project tsconfig.build.json",
},
"main": "lib/index.js",
"module": "es/index.mjs",
"typings": "es/index.d.ts",
...

六、构建组件库

完成组件开发和Vite配置后,使用以下命令来构建组件库:

arduino 复制代码
npm run build

Vite将会根据vite.config.js中的配置选项,生成构建输出的文件并保存在eslib目录下。

七、使用组件库

构建完成后,您可以将eslib目录下生成的文件直接用于其他项目中,例如通过npm包管理工具进行安装和引入。

在您的目标项目中,您可以使用import或require语法来导入组件库的组件:

  • ES模块中使用import:
javascript 复制代码
import Button from 'my-component-library/es/index.mjs';
  • CommonJS模块中使用全局引用:
xml 复制代码
<script src="my-component-library/lib/index.js"></script>

注意:上述示例中的文件路径根据实际构建生成的文件名和文件路径进行调整。

结论

通过使用Vite构建工具,我们可以快速构建React组件库,并实现同时支持cjsES模块化导出。通过适当的配置,我们可以生成适用于不同模块系统的构建文件,并轻松地在其他项目中使用我们的组件库。希望本文对您有所帮助!

Q&A

  • Q: 有源码吗?

当然有,地址如下:github.com/027xiguapi/...,有兴趣的话可以大家一起探讨,同时也欢迎大家forkstar

相关推荐
m0_738120723 小时前
CTFshow系列——命令执行web53-56
前端·安全·web安全·网络安全·ctfshow
Liu.7745 小时前
uniappx鸿蒙适配
前端
山有木兮木有枝_6 小时前
从代码到创作:探索AI图片生成的神奇世界
前端·coze
言兴6 小时前
秋招面试---性能优化(良子大胃袋)
前端·javascript·面试
WebInfra7 小时前
Rspack 1.5 发布:十大新特性速览
前端·javascript·github
雾恋8 小时前
我用 trae 写了一个菜谱小程序(灶搭子)
前端·javascript·uni-app
烛阴8 小时前
TypeScript 中的 `&` 运算符:从入门、踩坑到最佳实践
前端·javascript·typescript
Java 码农9 小时前
nodejs koa留言板案例开发
前端·javascript·npm·node.js
ZhuAiQuan9 小时前
[electron]开发环境驱动识别失败
前端·javascript·electron
nyf_unknown10 小时前
(vue)将dify和ragflow页面嵌入到vue3项目
前端·javascript·vue.js