Vue3组件库设计:从零搭建支持主题定制与按需加载的UI框架

Vue3组件库架构设计与Monorepo工程搭建

Vue3生态下组件库设计需要兼顾主题定制灵活性和按需加载性能。采用Monorepo架构管理多个组件包,pnpm workspace作为基础方案:

# 项目结构
my-ui/
├── packages/
│   ├── components/     # 组件源码
│   ├── theme/          # 主题样式
│   ├── utils/          # 工具函数
│   └── icons/          # 图标组件
├── playground/         # 开发调试
├── docs/               # 文档站
├── pnpm-workspace.yaml
└── package.json

pnpm-workspace.yaml配置:

packages:
  - 'packages/*'
  - 'playground'
  - 'docs'

根package.json统一管理TypeScript、Vite、ESLint等开发依赖,各子包仅声明自身运行时依赖。这种结构让组件、主题、工具独立版本管理,用户可按需安装子集。

组件开发规范与TypeScript类型设计

组件开发遵循统一规范:Props用TypeScript接口定义,事件用emits声明,暴露ref方法通过defineExpose。以Button组件为例:

<script setup lang="ts">
import { computed, ref } from 'vue'
import { useNamespace } from '@my-ui/utils'
import { buttonProps, buttonEmits } from './props'

const props = defineProps(buttonProps)
const emit = defineEmits(buttonEmits)
const ns = useNamespace('button')
const buttonRef = ref<HTMLButtonElement>()

const classes = computed(() => ({
  [ns.b()]: true,
  [ns.m(props.type)]: props.type,
  [ns.m(props.size)]: props.size,
  [ns.is('disabled', props.disabled)]: props.disabled,
  [ns.is('loading', props.loading)]: props.loading,
}))

defineExpose({ ref: buttonRef })
</script>

props.ts独立文件定义类型:

import type { PropType } from 'vue'

export type ButtonType = 'primary' | 'success' | 'warning' | 'danger' | 'info' | 'default'
export type ButtonSize = 'large' | 'default' | 'small'

export const buttonProps = {
  type: { type: String as PropType<ButtonType>, default: 'default' },
  size: { type: String as PropType<ButtonSize>, default: 'default' },
  disabled: Boolean,
  loading: Boolean,
  icon: String,
} as const

export const buttonEmits = {
  click: (e: MouseEvent) => e instanceof MouseEvent,
}

TypeScript实战中,类型定义独立于组件逻辑,方便后续自动生成API文档和类型声明文件。

CSS变量驱动的主题定制系统

主题定制是组件库的核心竞争力。基于CSS变量的方案运行时可动态切换,无需重新构建样式文件:

/* packages/theme/src/default.css */
:root {
  --my-color-primary: #409eff;
  --my-color-success: #67c23a;
  --my-color-warning: #e6a23c;
  --my-color-danger: #f56c6c;
  --my-color-info: #909399;
  --my-bg-color: #ffffff;
  --my-text-color-primary: #303133;
  --my-border-radius: 4px;
  --my-font-size: 14px;
}

组件样式引用CSS变量:

/* packages/theme/src/button.css */
.my-button {
  display: inline-flex;
  align-items: center;
  padding: 8px 16px;
  font-size: var(--my-font-size);
  border-radius: var(--my-border-radius);
  color: var(--my-text-color-primary);
  background-color: var(--my-bg-color);
  border: 1px solid var(--my-border-color);
  transition: all 0.3s;
}
.my-button--primary {
  color: #fff;
  background-color: var(--my-color-primary);
  border-color: var(--my-color-primary);
}

用户切换暗色主题只需覆盖变量:

document.documentElement.style.setProperty('--my-bg-color', '#1a1a2e')
document.documentElement.style.setProperty('--my-text-color-primary', '#e0e0e0')

按需加载与Tree-shaking实现方案

组件库按需加载有两套主流方案:ES Module原生Tree-shaking和unplugin-vue-components自动导入。

方案1:ES Module Tree-shaking

每个组件独立导出,配合sideEffects配置:

// packages/components/index.ts
export { Button } from './button'
export { Input } from './input'
export { Select } from './select'
// 用户按需导入
import { Button } from '@my-ui/components'

package.json标记sideEffects避免样式被Tree-shake:

// packages/components/package.json
{
  "sideEffects": ["*.css", "*.scss"]
}

方案2:unplugin自动导入

// vite.config.ts
import Components from 'unplugin-vue-components/vite'
import { MyUIResolver } from '@my-ui/auto-import'

export default defineConfig({
  plugins: [
    Components({
      resolvers: [MyUIResolver()],
    }),
  ],
})

自定义Resolver实现:

export function MyUIResolver() {
  return {
    type: 'component',
    resolve: (name: string) => {
      if (name.startsWith('My')) {
        const partialName = name.slice(2)  // MyButton -> Button
        return {
          name: partialName,
          from: '@my-ui/components',
          sideEffects: `@my-ui/theme/src/${partialName.toLowerCase()}.css`,
        }
      }
    },
  }
}

自动导入方案降低用户心智负担,模板中直接使用<MyButton>即可,无需手动import。两种方案生产包体积差异实测:全量引入Button/Input/Select三个组件约45KB(gzip),按需引入仅12KB,缩减73%。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/vue3-zu-jian-ku-she-ji-cong-ling-da-jian-zhi-chi-zhu-ti/

(0)
小编小编
上一篇 13小时前
下一篇 13小时前

相关推荐