《Vue3 组件库搭建指北:pnpm + monorepo + 代码提交规范+ BEM 环境配置》

Vue3 组件库搭建指北:pnpm + monorepo 环境配置

作为一个有追求的前端开发者,拥有一套自己的组件库不仅是技术实力的证明,更是提升团队效率的利器。本文将手把手带你使用最新的技术栈(Vue3 + Vite + TypeScript + pnpm Monorepo)从零搭建一个企业级组件库的基础架构。

1. 什么是 Monorepo?(从"找工具"说起)

在正式动手前,我们要先理解 Monorepo(单代码仓库)。

想象一下你正在装修房子:

  • Multirepo(多仓库):你把锤子放在卧室,锯子放在厨房,螺丝钉放在地下室。每次你想钉个架子,得在三个房间之间来回跑。如果锤子升级了,你可能还得去其他房间检查锯子还能不能配合。
  • Monorepo(单仓库) :你准备了一个巨大的专业工具箱。锤子、锯子、螺丝钉全都整齐地摆在不同的隔层里。

为什么组件库一定要用 Monorepo?

  1. "近水楼台先得月" (代码共享) : 你的组件代码在 packages/components,文档代码在 docs。在 Monorepo 里,文档可以直接"看到"并使用最新的组件,不需要像传统方式那样------先给组件发个 NPM 包,再在文档里下载。
  2. "一人得道,鸡犬升天" (统一规范): 你只需要在根目录放一个 ESLint 配置文件,整个工具箱里的所有代码都会乖乖听话,保持一样的缩进和风格。
  3. "一损俱损,一荣俱荣" (依赖一致性): 如果你想升级 Vue 版本,在 Monorepo 里只需要改一处,所有相关的演示项目、文档、组件包都会同步升级,不会出现"文档用 Vue3.2,组件用 Vue3.5"导致的诡异报错。

核心成员介绍

在我们的项目中,pnpm 是管理这个巨大工具箱的"管家"。通过 pnpm-workspace.yaml,我们划分了不同的区域:

  • packages/*:这里是核心,存放组件库、工具函数、主题样式。
  • play:这是我们的"沙盒",用来一边写组件一边预览效果。
  • docs:这是向外界展示组件库的"门面"。

2. 环境初始化

首先,确保你的 Node.js 版本 >= 18,并全局安装 pnpm:

bash 复制代码
npm install -g pnpm

初始化项目结构:

bash 复制代码
mkdir my-antd-ui
cd my-antd-ui
pnpm init

新建 pnpm-workspace.yaml,告诉 pnpm 这是一个 workspace 项目:

yaml 复制代码
packages:
  - 'packages/*'
  - 'play'
  - 'docs'

此时的目录结构应该如下:

text 复制代码
my-antd-ui/
├── packages/          # 存放核心代码 (components, theme, utils)
├── play/              # 本地调试项目 (Playground)
├── docs/              # 文档站点 (VitePress)
├── package.json
└── pnpm-workspace.yaml

3. TypeScript 配置

在根目录创建 tsconfig.json,作为所有子项目的基准配置:

json 复制代码
{
  "compilerOptions": {
    "baseUrl": ".",
    "jsx": "preserve",
    "strict": true,
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "Node",
    "skipLibCheck": true,
    "esModuleInterop": true,
    "lib": ["esnext", "dom"]
  }
}

4. 规范体系 (Lint & Format)

我们可以一步到位,使用 @antfu/eslint-config,它集成了 ESLint 和 Prettier 的最佳实践。

bash 复制代码
pnpm add -D -w eslint prettier @antfu/eslint-config typescript

新建 eslint.config.js:

javascript 复制代码
import antfu from '@antfu/eslint-config'

export default antfu({
  vue: true,
  typescript: true,
  ignores: ['**/dist', '**/node_modules']
})

5. 代码提交规范 (Husky + Commitlint)

为了防止像 fix: bug 这样随意的提交信息,我们需要引入 Commitlint。

bash 复制代码
pnpm add -D -w husky lint-staged @commitlint/cli @commitlint/config-conventional
npx husky init

在 .husky/commit-msg 中添加钩子:

bash 复制代码
npx --no -- commitlint --edit $1

新建 commitlint.config.js:

javascript 复制代码
export default {
  extends: ['@commitlint/config-conventional']
}

现在,如果你尝试提交 git commit -m "update",将会被拒绝;必须使用 git commit -m "feat: add button component" 这样符合规范的格式。

6. 样式架构设计:理解 BEM 规范

在编写组件库样式时,最头疼的就是样式冲突 。如果大家都在 CSS 里写 .item,那全局样式就会乱成一团。为了解决这个问题,主流组件库(如 Element Plus)都采用了 BEM 命名规范。

什么是 BEM?

BEM 将类名拆解为三个部分:

  1. Block (块) :组件的根节点。例如 my-button。
  2. Element (元素) :组件内部的子节点。用双下划线 __ 连接。例如 my-button__icon。
  3. Modifier (修饰符) :组件的不同状态或外观。用双连字符 -- 连接。例如 my-button--primary 或 my-button--disabled。

通俗例子: 想象一个"人"组件(Person):

  • person (Block)
  • person__hand (Element: 人的手)
  • person--female (Modifier: 女性的人)

为什么要这么写?

  • 语义清晰:一眼就能看出这个类名是属于哪个组件的哪个部分。
  • 避免冲突:每个组件都有独一无二的前缀(Namespace),样式不会互相污染。
  • 性能友好:减少了 CSS 选择器的嵌套深度(尽量保持一级类名选择器)。

自动化实现:useNamespace

在 packages/utils/src/namespace.ts 中,我们封装了一个工具函数,让类名的生成变得半自动化:

typescript 复制代码
export const useNamespace = (block: string) => {
  const namespace = 'my' // 你的组件库前缀
  const b = () => `${namespace}-${block}` // 生成 my-button
  const e = (el: string) => el ? `${b()}__${el}` : '' // 生成 my-button__icon
  const m = (mod: string) => mod ? `${b()}--${mod}` : '' // 生成 my-button--primary
  return { b, e, m }
}

在 Vue 组件中使用:

html 复制代码
<template>
  <!-- 最终生成 class="my-button my-button--primary" -->
  <button :class="[ns.b(), ns.m(type)]">
    <!-- 最终生成 class="my-button__content" -->
    <span :class="ns.e('content')">
      <slot />
    </span>
  </button>
</template>

<script setup>
const ns = useNamespace('button')
</script>

7. 结语

至此,我们的组件库地基已经打牢。我们配置了高效的 Monorepo 环境,统一了代码规范,并设计了样式架构。接下来,我们将逐步实现组件库的核心功能,并编写文档和示例项目。

敬请期待后续更新!

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
A黄俊辉A3 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
honkun63 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19913 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net
汉堡大王95273 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端