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

背景

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

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

思路

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

  1. 将 *.tsx 文件导出并打包成 esm 和 cjs 等结构的 *.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指定构建输出的文件名,可以根据需要使用不同的格式(例如es、cjs)。此外,我们还配置了外部依赖(如react和react-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中的配置选项,生成构建输出的文件并保存在es和lib目录下。

七、使用组件库

构建完成后,您可以将es和lib目录下生成的文件直接用于其他项目中,例如通过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组件库,并实现同时支持cjs和ES模块化导出。通过适当的配置,我们可以生成适用于不同模块系统的构建文件,并轻松地在其他项目中使用我们的组件库。希望本文对您有所帮助!

Q&A

  • Q: 有源码吗?

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

相关推荐
卸任9 小时前
Vibe coding工具使用心得
前端·ai编程
brien910 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance10 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M10 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写10 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李10 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易10 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马10 小时前
前沿视界
前端
kyriewen10 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易11 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员