跳转到正文
Monster Cone
返回

Vite + React + TypeScript 实战:从零搭建组件库

编辑页面

使用 Vite + React + TypeScript + Tailwind CSS 技术栈封装一个 React 组件

1. 使用 Vite 创建项目

$ npm create vite@latest blog-demo --template react-swc-ts
√ Select a framework: » React
√ Select a variant: » TypeScript + SWC

1. 添加 Tailwind CSS

安装
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
配置
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
  content: ["./src/**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};
// postcss.config.js
export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};
/* style.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

2. 封装我们的组件

我们在 src/components 目录下封装一个简单的 button 组件

// MyButton.tsx
import { FC } from "react";
import "./index.css";

export interface MyButtonProps {
  onClick?: () => void;
  children: string;
}

const MyButton: FC<MyButtonProps> = ({ onClick, children }) => {
  return (
    <button className="bg-blue-500 px-6 py-4 text-white" onClick={onClick}>
      {children}
    </button>
  );
};

export default MyButton;
/* index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

3.打包和 npm 发布

编写入口文件导出我们的组件和 TS 声明
// src/index.ts
import MyButton, { MyButtonProps } from "./components/MyButton";

export default MyButton;
export type { MyButtonProps };
安装相关插件
npm i -D @types/node vite-plugin-dts
配置 vite.config.ts 和 package.json
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import { resolve } from "path";
import dts from "vite-plugin-dts";

export default defineConfig({
  build: {
    lib: {
      entry: resolve(__dirname, "./lib/index.ts"),
      name: "react-simple-slide-captcha",
      formats: ["es"],
      fileName: format => `index.${format}.js`,
    },
    rollupOptions: {
      external: ["react", "react-dom"],
      output: {
        globals: {
          react: "React",
          "react-dom": "ReactDOM",
        },
      },
      plugins: [insertConsoleLog()],
    },
  },
  plugins: [
    react(),
    dts({
      rollupTypes: true,
      include: ["./lib"],
      tsconfigPath: "./tsconfig.app.json",
    }),
  ],
});
{
    "name": "react-button",
    "version": "1.0.0",
    "type": "module",
    "main": "./dist/index.es.js",
    "types": "./dist/index.d.ts",
    "exports": {
        ".": {
            "import": "./dist/index.es.js",
            "types": "./dist/index.d.ts"
        },
        "./dist/style.css": {
            "import": "./dist/style.css"
        }
    },
    "files": ["dist"],
    ...
}

如果打包没问题就可以 npm 发布了

npm login

npm publish

4.组件使用

npm i react-button
import MyButton from "react-button";
import "react-button/dist/style.css";

const App = () => {
  const handleClick = () => {
    console.log("按钮点击");
  };
  return <MyButton onClick={handleClick}>My Button</MyButton>;
};

export default App;

5. 优化样式引用问题

即使我们文件中有导入 style 的代码,但在打包时会删除掉,所以我们在打包后的文件中引用 style 即可。

自定义 rollup 插件引入 style
// vite.config.js
function insertStyle() {
    return {
        name: 'insert-style',
        renderChunk(code: any, chunk: any, options: any, meta: any) {
            return {
                code: `import "./style.css";` + code
            }
        }
    }
}

export default defineConfig({
    build: {
        ... // 其他代码
        rollupOptions: {
            ... // 其他代码
            plugins: [insertStyle()]
        }
    },
    ... // 其他代码
})

定义一个名为 insertStyle 的 rollup 插件,通过 renderChunk 钩子获取编译打包后的 code,然后在首行加上 style 的导入 code,在 rollupOptions 的 plugins 中使用 insertStyle 插件即可。

优点是不用再手动导入 style 文件,缺点是好像不支持 umd,暂时没有验证。

如果想直接使用,可以使用我发布的vite-react-components-template 模板


编辑页面
分享这篇文章:

上一篇
Chrome 扩展如何只在指定路由注入 content.js
下一篇
FCM 迁移 HTTP v1 API:鉴权、发送与避坑