用 Next.js 构建企业级组件库

237 阅读2分钟

用 Next.js 构建企业级组件库


📌 第 1 部分:项目初始化与结构规划

✅ 使用 create-next-app 初始化项目

npx create-next-app@latest my-ui-library --typescript
cd my-ui-library

✅ 项目结构建议

my-ui-library/
├── components/           // 组件库源码
│   ├── Button/
│   │   ├── Button.tsx
│   │   ├── Button.module.css
│   │   └── index.ts
│   └── index.ts          // 导出所有组件
├── docs/                 // 文档演示页面
│   └── button.md
├── pages/                // Next.js 页面(文档展示)
├── public/               // 公共资源
├── styles/               // 全局样式/主题变量
├── utils/                // 工具函数
├── types/                // 全局类型定义
├── .storybook/           // Storybook 配置(可选)
├── tsconfig.json
├── package.json
└── README.md

📦 第 2 部分:开发基础组件

以 Button 组件为例:

// components/Button/Button.tsx
import React from 'react';
import styles from './Button.module.css';

type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
  variant?: 'primary' | 'secondary';
};

const Button: React.FC<ButtonProps> = ({ variant = 'primary', ...rest }) => {
  return <button className={styles[variant]} {...rest} />;
};

export default Button;
/* components/Button/Button.module.css */
.primary {
  background: #0070f3;
  color: white;
}

.secondary {
  background: #eaeaea;
  color: #333;
}
// components/Button/index.ts
export { default } from './Button';
// components/index.ts
export { default as Button } from './Button';

📚 第 3 部分:构建组件文档系统

✅ 方法一:直接使用 Next.js 作为文档平台

  • 创建 pages/docs/button.tsx 来演示组件:
// pages/docs/button.tsx
import { Button } from '@/components';

export default function ButtonDoc() {
  return (
    <div>
      <h1>Button 组件</h1>
      <Button variant="primary">主按钮</Button>
      <Button variant="secondary">次按钮</Button>
    </div>
  );
}

✅ 方法二:引入 Storybook(推荐)

npx storybook init

创建故事文件:

// components/Button/Button.stories.tsx
import React from 'react';
import Button from './Button';
import type { Meta, StoryObj } from '@storybook/react';

const meta: Meta<typeof Button> = {
  title: 'Components/Button',
  component: Button,
};

export default meta;

export const Primary: StoryObj<typeof Button> = {
  args: {
    children: '主按钮',
    variant: 'primary',
  },
};

export const Secondary: StoryObj<typeof Button> = {
  args: {
    children: '次按钮',
    variant: 'secondary',
  },
};

运行:

npm run storybook

⚙️ 第 4 部分:构建系统与按需引入

✅ 使用 babel-plugin-import 或打包为单独模块

可选:使用 rolluptsup 构建最终产物

npm install tsup -D
// tsup.config.ts
import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['components/index.ts'],
  format: ['esm', 'cjs'],
  dts: true,
  clean: true,
});

构建命令:

npx tsup

输出结果:

dist/
├── index.js
├── index.d.ts
├── Button/
│   ├── Button.js
│   ├── Button.d.ts

🌐 第 5 部分:组件库主题化支持

你可以通过 CSS 变量 或 styled-components、Tailwind 等方式支持主题切换。

方案示例:全局 CSS 变量

:root {
  --primary-color: #0070f3;
  --secondary-color: #eaeaea;
}
<button style={{ backgroundColor: 'var(--primary-color)' }}>

🚀 第 6 部分:发布组件库到 NPM(可选)

1. 修改 package.json

{
  "name": "my-ui-library",
  "version": "1.0.0",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": ["dist"]
}

2. 登录 & 发布

npm login
npm publish

✅ 第 7 部分:最佳实践

实践推荐做法
类型系统使用 TypeScript
文档使用 Storybook + 示例文档
复用性避免组件中硬编码样式,支持 props
测试使用 Jest + RTL 进行单元测试
CI/CD发布前集成自动测试、构建流程
组件命名使用 PascalCase 命名组件文件夹

🎯 示例组件建议列表

组件名称功能说明
Button基础按钮、加载态、禁用态等
Input输入框、支持错误、前缀图标
Modal弹窗、支持 portal
Form表单容器、校验逻辑
Tabs标签页切换组件
Select下拉选择器
Toast全局提示框
Table表格封装、排序分页
ThemeProvider全局主题支持