Logo
Published on

基于Vite + React + TypeScript + TailwindCss 构建React组件

Authors
  • avatar
    Name
    Monster Cone
    Twitter

使用 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' }),
  ],
})
  • 在 lib 中指定文件入口,包名,包格式,文件名。
  • 自定义 rollup 配置,在 rollupOptions 中排除打包 react 和 react-dom,并指定最终输出时的命名。
  • 使用 react 插件支持打包 react 语法,使用 dts 将 src 目录的声明文件打包到一个单独的文件中。
{
    "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"],
    ...
}
  • name: 包名
  • version: 版本
  • type: 包格式
  • main: 指定包入口文件
  • types: 指定包的 ts 声明文件
  • exports: 指定包的导出内容
  • files: "指定 npm 包包含的内容"

如果打包没问题就可以 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 模板