开发指南
本指南将帮助您了解如何在本地开发和贡献 Lerna Web UI 组件库。无论您是想添加新组件、修复 Bug 还是改进文档,这里都会提供详细的步骤说明。
🎯 开始之前
在开始开发之前,请确保您已经完成了环境搭建。如果您还没有安装和配置开发环境,请先参考 安装指南。
快速检查清单
- ✅ Node.js >= 18.0.0 已安装
- ✅ pnpm >= 8.0.0 已安装
- ✅ Git 已配置
- ✅ 已克隆项目并安装依赖
- ✅ 已成功运行
pnpm run bootstrap
🏗️ 项目结构
lerna-web-ui/
├── packages/ # 核心包目录
│ ├── shared/ # 共享常量、枚举、类型定义
│ ├── utils/ # 工具函数库
│ ├── core/ # 核心能力(composables, directives, plugins)
│ └── ui/ # UI 组件实现
├── docs/ # 文档项目
├── tooling/ # 工具配置
│ ├── configs/ # ESLint、TypeScript 配置
│ ├── shared/ # 共享工具
│ └── unplugin/ # Unplugin 插件
├── scripts/ # 自动化脚本
│ ├── create-component.js # 组件生成器
│ └── generate-docs.js # 文档生成器
├── .husky/ # Git Hooks
├── .vscode/ # VS Code 配置
└── package.json # 项目配置🔨 开发工作流
1. 启动开发服务器
bash
# 并行启动所有包的开发服务
pnpm run dev这会同时监听以下包的源码变化:
@lerna-web-ui/utils- 工具函数@lerna-web-ui/shared- 共享类型@lerna-web-ui/core- 核心逻辑@lerna-web-ui/ui- UI 组件
2. 开发单个模块
如果只需要开发特定模块:
bash
# 开发 UI 组件库
cd packages/ui
pnpm run dev
# 开发核心包
cd packages/core
pnpm run dev3. 构建模块
bash
# 构建所有模块
pnpm run build
# 单独构建 UI 包
pnpm run build:ui
# 单独构建 core 包
pnpm run build:core🧩 组件开发
创建新组件
使用内置的组件生成器快速创建组件模板:
bash
# 在项目根目录执行
pnpm run new:component modal这将自动生成以下文件:
packages/ui/src/components/modal/
├── Modal.vue # Vue 组件文件
├── index.ts # 导出文件
└── style.scss # 样式文件组件开发规范
1. Vue 组件文件结构
vue
<template>
<div class="lerna-component-name">
<slot />
</div>
</template>
<script setup lang="ts">
/**
* 组件描述
* @version 1.0.0
*/
// Props 接口定义
export interface ComponentNameProps {
/** 属性描述 */
prop1?: string;
/** 属性描述 */
prop2?: boolean;
}
// Props 默认值
const props = withDefaults(defineProps<ComponentNameProps>(), {
prop1: 'default',
prop2: false,
});
// Emits 定义
const emit = defineEmits<{
/**
* @event 事件描述
*/
(e: 'change', value: string): void;
}>();
// Slots 定义
defineSlots<{
/** 默认内容 */
default(): any;
}>();
// 组件逻辑
const handleClick = () => {
emit('change', 'new value');
};
</script>
<style scoped lang="scss">
.lerna-component-name {
// 组件样式
}
</style>2. JSDoc 注释规范
typescript
export interface ButtonProps {
/**
* @description 按钮类型
* @default 'default'
*/
type?: 'primary' | 'default' | 'danger';
/**
* @description 按钮尺寸
* @default 'medium'
*/
size?: 'small' | 'medium' | 'large';
/**
* @description 是否禁用
* @default false
*/
disabled?: boolean;
}
/**
* @event click 点击按钮时触发
* @param {MouseEvent} event 鼠标事件对象
*/
const emit = defineEmits<{
(e: 'click', event: MouseEvent): void;
}>();
/**
* @slot default 默认插槽
* @slot icon 图标插槽
*/
defineSlots<{
default(): any;
icon(): any;
}>();3. 样式命名规范
使用 BEM 命名约定:
scss
// 块(Block)
.lerna-button {}
// 元素(Element)
.lerna-button__icon {}
// 修饰符(Modifier)
.lerna-button--primary {}
.lerna-button--disabled {}4. 使用设计令牌
始终使用 CSS 变量而非硬编码值:
scss
.lerna-button {
// ✅ 好的做法
padding: var(--lerna-spacing-3) var(--lerna-spacing-4);
background-color: var(--lerna-color-primary);
border-radius: var(--lerna-radius-md);
// ❌ 避免的做法
padding: 12px 16px;
background-color: #3b82f6;
border-radius: 6px;
}更新组件导出
创建组件后,确保在以下位置正确导出:
1. 组件入口文件 (components/button/index.ts)
typescript
import Button from './Button.vue';
import type { App } from 'vue';
Button.install = (app: App) => {
app.component(Button.name || 'LernaButton', Button);
};
Button.name = 'LernaButton';
export default Button;
export { Button };
export type { ButtonProps } from './Button.vue';2. 组件索引文件 (components/index.ts)
typescript
import Button from './button';
import Input from './input';
export { Button, Input };
export type { ButtonProps, InputProps } from './button';
export default [Button, Input];3. 包入口文件 (index.ts)
typescript
import './styles/index.scss';
import { Button, Input } from './components';
export { Button, Input };
export type { ButtonProps, InputProps } from './components';
const components = [Button, Input];
const install = (app: App): void => {
components.forEach(component => {
app.component(component.name || component.__name || '', component);
});
};
export default {
install,
version: '__VERSION__',
};🎨 样式系统开发
添加设计令牌
1. 颜色令牌 (styles/tokens/_colors.scss)
scss
:root {
// 新增主题色
--lerna-color-brand: #ff6b35;
--lerna-color-brand-light: #ff8c5a;
--lerna-color-brand-dark: #e55a2b;
}2. 间距令牌 (styles/tokens/_spacing.scss)
scss
:root {
// 新增间距
--lerna-spacing-11: 2.75rem; // 44px
--lerna-spacing-12: 3rem; // 48px
}3. 圆角令牌 (styles/tokens/_spacing.scss)
scss
:root {
// 新增圆角
--lerna-radius-2xl: 1rem; // 16px
--lerna-radius-3xl: 1.5rem; // 24px
}创建 SCSS Mixins
在 styles/mixins/ 目录下创建可复用的样式逻辑:
scss
// styles/mixins/_flex.scss
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}
@mixin flex-between {
display: flex;
justify-content: space-between;
align-items: center;
}
// styles/mixins/_responsive.scss
@mixin responsive($breakpoint) {
@if $breakpoint == 'sm' {
@media (max-width: 640px) { @content; }
}
@else if $breakpoint == 'md' {
@media (max-width: 768px) { @content; }
}
@else if $breakpoint == 'lg' {
@media (min-width: 1024px) { @content; }
}
}🧪 测试
单元测试(待实现)
bash
# 运行测试
pnpm run test目前测试框架尚未配置,计划集成 Vitest + Testing Library。
手动测试
1. 在示例项目中测试
bash
# 进入示例项目
cd examples/vite-vue3
# 安装依赖
pnpm install
# 启动开发服务器
pnpm run dev2. 在 Storybook 中测试
bash
# 进入 UI 包
cd packages/ui
# 启动 Storybook
pnpm run storybook📝 文档开发
生成文档
bash
# 生成所有文档
pnpm run docs:generate
# 仅生成 UI 组件文档
pnpm run docs:generate:ui
# 仅生成核心包文档
pnpm run docs:generate:core预览文档
bash
# 进入文档项目
cd docs
# 安装依赖
pnpm install
# 启动开发服务器
pnpm run dev🔍 代码质量
类型检查
bash
# 检查所有包
pnpm run type-check
# 检查单个包
cd packages/ui
pnpm run type-check代码检查
bash
# 检查所有包
pnpm run lint
# 仅检查根目录
pnpm run lint:root
# 仅检查样式
pnpm run lint:style格式化代码
bash
# 格式化所有文件
pnpm run format
# 格式化特定文件
prettier --write "packages/ui/src/**/*.vue"提交前验证
bash
# 运行完整的验证流程
pnpm run validate这将依次执行:
- TypeScript 类型检查
- ESLint 代码检查
- Prettier 格式化
🤝 贡献流程
1. Fork 项目
bash
# 在 GitHub 上 Fork 项目
# 然后克隆到本地
git clone https://github.com/YOUR_USERNAME/lerna-web-ui.git
cd lerna-web-ui2. 创建特性分支
bash
# 基于 main 分支创建新分支
git checkout -b feature/add-new-component3. 开发与提交
bash
# 开发完成后,添加文件
git add packages/ui/src/components/new-component/
# 提交更改(遵循 Conventional Commits 规范)
git commit -m "feat: add NewComponent"
# 推送分支
git push origin feature/add-new-component4. 创建 Pull Request
- 在 GitHub 上创建 PR
- 填写详细的 PR 描述
- 等待 CI 检查通过
- 请求代码审查
- 根据反馈进行修改
- 合并到主分支
Commit 信息规范
遵循 Conventional Commits 规范:
<type>(<scope>): <subject>
<body>
<footer>Type 类型
feat: 新功能fix: Bug 修复docs: 文档更新style: 代码格式调整refactor: 重构perf: 性能优化test: 测试相关chore: 构建/工具链相关
示例
bash
# 新功能
git commit -m "feat(ui): add Modal component"
# Bug 修复
git commit -m "fix(button): fix hover state on mobile"
# 文档更新
git commit -m "docs: update installation guide"
# 重构
git commit -m "refactor(core): simplify useTheme logic"🚀 发布流程
发布前准备
bash
# 1. 确保所有测试通过
pnpm run validate
# 2. 构建所有模块
pnpm run build
# 3. 更新版本号(使用 Lerna)
pnpm exec lerna version发布到 NPM
bash
# 发布所有包
pnpm exec lerna publish from-package
# 或发布特定包
pnpm exec lerna publish --scope=@lerna-web-ui/ui发布到 GitHub
bash
# 创建 Git 标签
git tag -a v0.1.0 -m "Release v0.1.0"
# 推送标签
git push origin v0.1.0
# 在 GitHub 上创建 Release🛠️ 工具与技巧
VS Code 配置
推荐的 .vscode/settings.json:
json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}调试技巧
1. 使用 DevTools
在浏览器中使用 Vue DevTools 检查组件状态和 Props。
2. 添加调试日志
typescript
const props = withDefaults(defineProps<ButtonProps>(), {
type: 'default',
});
// 开发环境下打印日志
if (import.meta.env.DEV) {
console.log('Button props:', props);
}3. 使用 debugger
typescript
const handleClick = (event: MouseEvent) => {
debugger; // 断点
emit('click', event);
};性能优化
1. 按需导入
确保配置了自动导入插件,避免全量引入。
2. Tree Shaking
使用 ESM 格式导出,支持 Tree Shaking:
typescript
// ✅ 好的做法
export { Button };
export type { ButtonProps };
// ❌ 避免的做法
export default Button;3. 懒加载组件
typescript
const AsyncModal = defineAsyncComponent(() =>
import('./Modal.vue')
);📚 相关资源
内部资源
外部资源
❓ 常见问题
Q: 如何调试构建问题?
A: 使用 verbose 模式查看详细构建日志:
bash
pnpm run build:ui -- --debugQ: 为什么类型检查报错?
A: 检查以下几点:
- 确保 TypeScript 版本正确(>= 5.0.0)
- 检查
tsconfig.json路径配置 - 清除缓存重新构建:
rm -rf node_modules/.vite && pnpm install
Q: 如何添加新的设计令牌?
A: 在对应的 tokens 文件中添加 CSS 变量,然后在组件中使用。
Q: 组件样式不生效怎么办?
A: 检查:
- 是否正确引入样式文件
- 是否使用了正确的 CSS 变量
- 是否有样式冲突或覆盖
💡 提示: 开发过程中遇到任何问题,欢迎通过 GitHub Issues 提问或参与讨论。我们鼓励开发者积极参与社区建设!
