61 |
62 | [optional body]
63 |
64 | [optional footer(s)]
65 | ```
66 |
67 | 类型包括:
68 |
69 | - `feat`: 新功能
70 | - `fix`: 修复 bug
71 | - `docs`: 文档更新
72 | - `style`: 代码格式调整
73 | - `refactor`: 代码重构
74 | - `test`: 测试相关
75 | - `chore`: 构建过程或辅助工具的变动
76 |
77 | 示例:
78 |
79 | ```
80 | feat(ui): add new Button component
81 | fix(utils): resolve array chunk function edge case
82 | docs: update installation guide
83 | ```
84 |
85 | ## 🧪 测试
86 |
87 | ### 运行测试
88 |
89 | ```bash
90 | # 运行所有测试
91 | pnpm test
92 |
93 | # 运行测试并生成覆盖率报告
94 | pnpm test:coverage
95 |
96 | # 运行 UI 测试
97 | pnpm test:ui
98 | ```
99 |
100 | ### 编写测试
101 |
102 | - 为新组件添加测试文件:`ComponentName.spec.ts`
103 | - 测试文件应该放在组件目录下的 `__tests__` 文件夹中
104 | - 确保测试覆盖主要功能和边界情况
105 |
106 | ## 🎨 添加新组件
107 |
108 | 使用组件生成器快速创建新组件:
109 |
110 | ```bash
111 | pnpm generate:component ComponentName
112 | ```
113 |
114 | 这会自动创建:
115 |
116 | - 组件文件 (`ComponentName.vue`)
117 | - 类型定义 (`ComponentName.types.ts`)
118 | - 样式文件 (`ComponentName.scss`)
119 | - 导出文件 (`index.ts`)
120 | - 测试文件 (`ComponentName.spec.ts`)
121 |
122 | ## 📚 文档
123 |
124 | ### 更新文档
125 |
126 | 文档位于 `apps/docs` 目录:
127 |
128 | - 中文文档:`apps/docs/zh/`
129 | - 英文文档:`apps/docs/en/`
130 |
131 | 添加新组件文档时,请确保:
132 |
133 | 1. 提供清晰的使用示例
134 | 2. 列出所有 props 和 events
135 | 3. 包含中英文版本
136 |
137 | ### 本地预览文档
138 |
139 | ```bash
140 | pnpm dev:docs
141 | ```
142 |
143 | ## 🔧 构建和发布
144 |
145 | ### 构建项目
146 |
147 | ```bash
148 | # 构建所有包
149 | pnpm build
150 |
151 | # 使用 gulp 统一构建
152 | pnpm build:gulp
153 |
154 | # 分析构建产物
155 | pnpm build:analyze
156 | ```
157 |
158 | ### 版本管理
159 |
160 | 项目使用 [Changesets](https://github.com/changesets/changesets) 进行版本管理:
161 |
162 | 1. 添加变更记录:
163 |
164 | ```bash
165 | pnpm changeset
166 | ```
167 |
168 | 2. 更新版本:
169 |
170 | ```bash
171 | pnpm changeset:version
172 | ```
173 |
174 | ## 🐛 报告问题
175 |
176 | 在提交 issue 之前,请:
177 |
178 | 1. 搜索现有的 issues
179 | 2. 使用最新版本重现问题
180 | 3. 提供详细的重现步骤
181 | 4. 包含相关的错误信息和环境信息
182 |
183 | ## 💡 功能请求
184 |
185 | 我们欢迎功能建议!请:
186 |
187 | 1. 详细描述功能需求
188 | 2. 说明使用场景
189 | 3. 考虑是否符合项目目标
190 |
191 | ## 📋 Pull Request 流程
192 |
193 | 1. Fork 项目
194 | 2. 创建功能分支:`git checkout -b feature/amazing-feature`
195 | 3. 提交更改:`git commit -m 'feat: add amazing feature'`
196 | 4. 推送分支:`git push origin feature/amazing-feature`
197 | 5. 创建 Pull Request
198 |
199 | ### PR 检查清单
200 |
201 | - [ ] 代码通过所有测试
202 | - [ ] 添加了必要的测试
203 | - [ ] 更新了相关文档
204 | - [ ] 遵循代码规范
205 | - [ ] 提交信息符合规范
206 |
207 | ## 🤝 社区
208 |
209 | - 在 GitHub Discussions 中讨论想法
210 | - 在 Issues 中报告 bug
211 | - 通过 PR 贡献代码
212 |
213 | 感谢你的贡献!🎉
214 |
--------------------------------------------------------------------------------
/scripts/generate-component.mjs:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
4 | import { dirname, join } from 'path';
5 | import { fileURLToPath } from 'url';
6 |
7 | const __filename = fileURLToPath(import.meta.url);
8 | const __dirname = dirname(__filename);
9 |
10 | // 获取组件名称
11 | const componentName = process.argv[2];
12 |
13 | if (!componentName) {
14 | console.error('请提供组件名称: pnpm generate:component ComponentName');
15 | process.exit(1);
16 | }
17 |
18 | // 验证组件名称格式
19 | if (!/^[A-Z][a-zA-Z0-9]*$/.test(componentName)) {
20 | console.error('组件名称必须以大写字母开头,只能包含字母和数字');
21 | process.exit(1);
22 | }
23 |
24 | const componentDir = join(__dirname, '../packages/ui/src/components', componentName);
25 |
26 | // 检查组件是否已存在
27 | if (existsSync(componentDir)) {
28 | console.error(`组件 ${componentName} 已存在`);
29 | process.exit(1);
30 | }
31 |
32 | // 创建组件目录
33 | mkdirSync(componentDir, { recursive: true });
34 |
35 | // 组件模板
36 | const vueTemplate = `
37 |
38 |
39 |
40 |
41 |
42 |
52 |
53 |
56 | `;
57 |
58 | const typesTemplate = `export interface ${componentName}Props {
59 | // 在这里定义组件的 props
60 | }
61 |
62 | export interface ${componentName}Emits {
63 | // 在这里定义组件的 emits
64 | }
65 | `;
66 |
67 | const scssTemplate = `.v-${componentName.toLowerCase()} {
68 | // 在这里添加组件样式
69 | }
70 | `;
71 |
72 | const indexTemplate = `import ${componentName} from './${componentName}.vue';
73 | import { withInstall } from '../../_utils';
74 |
75 | export const V${componentName} = withInstall(${componentName});
76 | export default V${componentName};
77 |
78 | export * from './${componentName}.types';
79 | `;
80 |
81 | const testTemplate = `import { describe, it, expect } from 'vitest';
82 | import { mount } from '@vue/test-utils';
83 | import ${componentName} from '../${componentName}.vue';
84 | import type { ${componentName}Props } from '../${componentName}.types';
85 |
86 | describe('${componentName}', () => {
87 | it('renders correctly', () => {
88 | const wrapper = mount(${componentName});
89 |
90 | expect(wrapper.classes()).toContain('v-${componentName.toLowerCase()}');
91 | });
92 |
93 | // 在这里添加更多测试用例
94 | });
95 | `;
96 |
97 | // 写入文件
98 | writeFileSync(join(componentDir, `${componentName}.vue`), vueTemplate);
99 | writeFileSync(join(componentDir, `${componentName}.types.ts`), typesTemplate);
100 | writeFileSync(join(componentDir, `${componentName}.scss`), scssTemplate);
101 | writeFileSync(join(componentDir, 'index.ts'), indexTemplate);
102 |
103 | // 创建测试目录和文件
104 | const testDir = join(componentDir, '__tests__');
105 | mkdirSync(testDir, { recursive: true });
106 | writeFileSync(join(testDir, `${componentName}.spec.ts`), testTemplate);
107 |
108 | // 更新组件导出
109 | const componentsIndexPath = join(__dirname, '../packages/ui/src/components/index.ts');
110 | const componentsIndex = readFileSync(componentsIndexPath, 'utf-8');
111 |
112 | const newExport = `export * from './${componentName}';`;
113 | const updatedIndex = componentsIndex.trim() + '\n' + newExport + '\n';
114 |
115 | writeFileSync(componentsIndexPath, updatedIndex);
116 |
117 | console.log(`✅ 组件 ${componentName} 创建成功!`);
118 | console.log(`📁 位置: packages/ui/src/components/${componentName}`);
119 | console.log(`📝 请记得在 packages/ui/src/index.ts 中导出新组件`);
120 |
--------------------------------------------------------------------------------
/packages/lint-configs/eslint-config/index.mjs:
--------------------------------------------------------------------------------
1 | import eslint from '@eslint/js';
2 | import tseslint from 'typescript-eslint';
3 | import pluginVue from 'eslint-plugin-vue';
4 | import globals from 'globals';
5 |
6 | export default tseslint.config(
7 | // 全局忽略配置
8 | { ignores: ['**/node_modules', '**/dist', '**/*.js'] },
9 |
10 | // 基础配置
11 | eslint.configs.recommended, // 使用 ESLint 的推荐配置
12 | tseslint.configs.base, // 使用 TypeScript ESLint 的基础配置
13 | ...pluginVue.configs['flat/recommended'], // 使用 Vue ESLint 的推荐配置
14 | ...pluginVue.configs['flat/strongly-recommended'],
15 | ...pluginVue.configs['flat/essential'],
16 |
17 | // 通用规则配置(适用于所有文件)
18 | {
19 | languageOptions: {
20 | ecmaVersion: 2022,
21 | globals: {
22 | ...globals.browser,
23 | ...globals.es2021,
24 | ...globals.node,
25 | document: 'readonly',
26 | navigator: 'readonly',
27 | window: 'readonly',
28 | },
29 | parserOptions: {
30 | ecmaFeatures: {
31 | jsx: true,
32 | },
33 | ecmaVersion: 2022,
34 | sourceType: 'module',
35 | },
36 | sourceType: 'module',
37 | },
38 | rules: {
39 | // 'no-console': ['error', { allow: ['warn', 'error', 'info', 'clear'] }], // 禁止使用 console 语句,但允许 warn, error, info 和 clear
40 | 'no-debugger': 'error', // 禁止使用 debugger 语句
41 | 'prefer-const': 'error', // 强制使用 const 而不是 let
42 | 'sort-imports': ['error', { ignoreDeclarationSort: true }], // 强制排序导入语句,但忽略声明排序
43 | 'no-duplicate-imports': 'error', // 禁止重复导入
44 | 'no-unused-vars': 'off', // 禁用对未使用变量的检查(针对类型声明)
45 | 'no-var': 'error', // 禁止使用 var
46 | // typescript 相关规则
47 | '@typescript-eslint/no-unused-vars': [
48 | 'error',
49 | {
50 | args: 'all',
51 | argsIgnorePattern: '^_',
52 | caughtErrors: 'all',
53 | caughtErrorsIgnorePattern: '^_',
54 | destructuredArrayIgnorePattern: '^_',
55 | varsIgnorePattern: '^_',
56 | ignoreRestSiblings: true,
57 | },
58 | ],
59 | '@typescript-eslint/prefer-ts-expect-error': 'error', // 强制使用 @ts-expect-error 而不是 @ts-ignore
60 | '@typescript-eslint/consistent-type-imports': [
61 | 'error',
62 | {
63 | fixStyle: 'inline-type-imports', // 使用内联类型导入样式
64 | disallowTypeAnnotations: false, // 允许类型注解
65 | },
66 | ],
67 | '@typescript-eslint/no-import-type-side-effects': 'error', // 禁止导入类型时产生副作用
68 | },
69 | },
70 |
71 | // TypeScript 文件配置
72 | {
73 | files: ['**/*.ts', '**/*.tsx'],
74 | languageOptions: {
75 | parser: tseslint.parser,
76 | parserOptions: {
77 | createDefaultProgram: false,
78 | ecmaFeatures: {
79 | jsx: true,
80 | },
81 | ecmaVersion: 'latest',
82 | extraFileExtensions: ['.vue'],
83 | jsxPragma: 'React',
84 | project: './tsconfig.*.json',
85 | sourceType: 'module',
86 | },
87 | },
88 | // rules: {},
89 | },
90 |
91 | // Vue 文件配置
92 | {
93 | files: ['**/*.vue'],
94 | languageOptions: {
95 | parserOptions: {
96 | parser: '@typescript-eslint/parser', // 使用 TypeScript ESLint 解析器解析 Vue 文件中的 TypeScript
97 | },
98 | },
99 | rules: {
100 | ...pluginVue.configs.base.rules,
101 | // Vue 特定规则
102 | 'vue/max-attributes-per-line': 'off', // 关闭每行最多属性数的限制
103 | 'vue/singleline-html-element-content-newline': 'off', // 关闭单行 HTML 元素内容换行的限制
104 | 'vue/multi-word-component-names': 'off', // 关闭多单词组件名称的限制
105 | 'vue/html-self-closing': [
106 | 'error',
107 | {
108 | html: { component: 'always', normal: 'always', void: 'any' }, // 强制 HTML 组件和普通元素始终自闭合,void 元素可以自闭合或不自闭合
109 | math: 'always', // 强制 math 元素始终自闭合
110 | svg: 'always', // 强制 svg 元素始终自闭合
111 | },
112 | ],
113 | 'vue/no-unused-vars': [
114 | 'error',
115 | {
116 | ignorePattern: '^_',
117 | },
118 | ],
119 | 'vue/no-v-html': 'off',
120 | },
121 | },
122 | );
123 |
--------------------------------------------------------------------------------
/packages/ui/COMPONENT_GUIDE.md:
--------------------------------------------------------------------------------
1 | # 组件开发指南
2 |
3 | 本指南将帮助你在这个组件库中开发高质量的 Vue 组件。
4 |
5 | ## 🏗️ 组件结构
6 |
7 | 每个组件应该包含以下文件:
8 |
9 | ```
10 | ComponentName/
11 | ├── ComponentName.vue # 组件主文件
12 | ├── ComponentName.types.ts # TypeScript 类型定义
13 | ├── ComponentName.scss # 样式文件
14 | ├── index.ts # 导出文件
15 | └── __tests__/
16 | └── ComponentName.spec.ts # 测试文件
17 | ```
18 |
19 | ## 📝 组件模板
20 |
21 | ### 1. Vue 组件文件
22 |
23 | ```vue
24 |
25 |
36 |
37 |
38 |
39 |
40 |
57 |
58 |
61 | ```
62 |
63 | ### 2. 类型定义文件
64 |
65 | ```typescript
66 | export interface ComponentNameProps {
67 | /**
68 | * 组件类型
69 | */
70 | type?: 'default' | 'primary' | 'success' | 'warning' | 'danger';
71 |
72 | /**
73 | * 组件大小
74 | */
75 | size?: 'small' | 'medium' | 'large';
76 |
77 | /**
78 | * 是否禁用
79 | */
80 | disabled?: boolean;
81 | }
82 |
83 | export interface ComponentNameEmits {
84 | /**
85 | * 点击事件
86 | */
87 | click: [event: MouseEvent];
88 |
89 | /**
90 | * 值改变事件
91 | */
92 | change: [value: string];
93 | }
94 | ```
95 |
96 | ### 3. 样式文件
97 |
98 | ```scss
99 | .v-component-name {
100 | // 基础样式
101 | display: inline-block;
102 | position: relative;
103 |
104 | // 类型变体
105 | &--primary {
106 | // primary 样式
107 | }
108 |
109 | &--success {
110 | // success 样式
111 | }
112 |
113 | // 大小变体
114 | &--small {
115 | // small 样式
116 | }
117 |
118 | &--large {
119 | // large 样式
120 | }
121 |
122 | // 状态样式
123 | &.is-disabled {
124 | // 禁用状态
125 | opacity: 0.6;
126 | cursor: not-allowed;
127 | }
128 |
129 | &.is-active {
130 | // 激活状态
131 | }
132 | }
133 | ```
134 |
135 | ### 4. 导出文件
136 |
137 | ```typescript
138 | import ComponentName from './ComponentName.vue';
139 | import { withInstall } from '../../_utils';
140 |
141 | export const VComponentName = withInstall(ComponentName);
142 | export default VComponentName;
143 |
144 | export * from './ComponentName.types';
145 | ```
146 |
147 | ### 5. 测试文件
148 |
149 | ```typescript
150 | import { describe, it, expect } from 'vitest';
151 | import { mount } from '@vue/test-utils';
152 | import ComponentName from '../ComponentName.vue';
153 | import type { ComponentNameProps } from '../ComponentName.types';
154 |
155 | describe('ComponentName', () => {
156 | it('renders correctly', () => {
157 | const wrapper = mount(ComponentName);
158 | expect(wrapper.classes()).toContain('v-component-name');
159 | });
160 |
161 | it('applies correct type class', () => {
162 | const wrapper = mount(ComponentName, {
163 | props: { type: 'primary' } as ComponentNameProps,
164 | });
165 | expect(wrapper.classes()).toContain('v-component-name--primary');
166 | });
167 |
168 | it('emits events correctly', async () => {
169 | const wrapper = mount(ComponentName);
170 | await wrapper.trigger('click');
171 | expect(wrapper.emitted('click')).toBeTruthy();
172 | });
173 | });
174 | ```
175 |
176 | ## 🎨 设计规范
177 |
178 | ### 命名规范
179 |
180 | - **组件名**: 使用 PascalCase,如 `Button`、`DatePicker`
181 | - **CSS 类名**: 使用 BEM 规范,如 `.v-button`, `.v-button--primary`, `.v-button__icon`
182 | - **Props**: 使用 camelCase,如 `disabled`, `maxLength`
183 | - **Events**: 使用 camelCase,如 `click`, `change`, `update:modelValue`
184 |
185 | ### CSS 变量
186 |
187 | 使用 CSS 变量来支持主题定制:
188 |
189 | ```scss
190 | .v-button {
191 | --v-button-color: var(--color-text);
192 | --v-button-bg: var(--color-bg);
193 | --v-button-border: var(--color-border);
194 |
195 | color: var(--v-button-color);
196 | background-color: var(--v-button-bg);
197 | border-color: var(--v-button-border);
198 | }
199 | ```
200 |
201 | ### 响应式设计
202 |
203 | 考虑不同屏幕尺寸的适配:
204 |
205 | ```scss
206 | .v-component {
207 | // 移动端
208 | @media (max-width: 768px) {
209 | // 移动端样式
210 | }
211 |
212 | // 平板
213 | @media (min-width: 769px) and (max-width: 1024px) {
214 | // 平板样式
215 | }
216 |
217 | // 桌面端
218 | @media (min-width: 1025px) {
219 | // 桌面端样式
220 | }
221 | }
222 | ```
223 |
224 | ## 🔧 开发最佳实践
225 |
226 | ### 1. Props 设计
227 |
228 | - 提供合理的默认值
229 | - 使用 TypeScript 类型约束
230 | - 添加详细的 JSDoc 注释
231 | - 考虑向后兼容性
232 |
233 | ### 2. 事件处理
234 |
235 | - 使用描述性的事件名称
236 | - 传递有用的事件参数
237 | - 支持事件修饰符
238 |
239 | ### 3. 插槽设计
240 |
241 | - 提供有意义的默认内容
242 | - 使用作用域插槽传递数据
243 | - 考虑插槽的可扩展性
244 |
245 | ### 4. 可访问性
246 |
247 | - 添加适当的 ARIA 属性
248 | - 支持键盘导航
249 | - 确保颜色对比度符合标准
250 | - 提供屏幕阅读器支持
251 |
252 | ### 5. 性能优化
253 |
254 | - 使用 `v-memo` 优化重复渲染
255 | - 合理使用 `computed` 和 `watch`
256 | - 避免不必要的响应式数据
257 | - 考虑组件的懒加载
258 |
259 | ## 🧪 测试策略
260 |
261 | ### 单元测试
262 |
263 | - 测试组件的基本渲染
264 | - 测试 props 的正确应用
265 | - 测试事件的正确触发
266 | - 测试边界情况
267 |
268 | ### 集成测试
269 |
270 | - 测试组件间的交互
271 | - 测试复杂的用户操作流程
272 | - 测试数据流的正确性
273 |
274 | ### 可访问性测试
275 |
276 | - 使用 `@testing-library/vue` 进行可访问性测试
277 | - 测试键盘导航
278 | - 测试屏幕阅读器兼容性
279 |
280 | ## 📚 文档编写
281 |
282 | ### API 文档
283 |
284 | 为每个组件编写详细的 API 文档:
285 |
286 | ```markdown
287 | ## Props
288 |
289 | | 属性名 | 类型 | 默认值 | 说明 |
290 | | ------ | ------ | --------- | -------- |
291 | | type | string | 'default' | 按钮类型 |
292 | | size | string | 'medium' | 按钮大小 |
293 |
294 | ## Events
295 |
296 | | 事件名 | 参数 | 说明 |
297 | | ------ | ------------------- | ---------- |
298 | | click | (event: MouseEvent) | 点击时触发 |
299 |
300 | ## Slots
301 |
302 | | 插槽名 | 说明 |
303 | | ------- | -------- |
304 | | default | 按钮内容 |
305 | ```
306 |
307 | ### 使用示例
308 |
309 | 提供清晰的使用示例:
310 |
311 | ```vue
312 |
313 | 点击我
314 |
315 | ```
316 |
317 | ## 🚀 发布流程
318 |
319 | 1. 确保所有测试通过
320 | 2. 更新组件文档
321 | 3. 添加 changeset 记录
322 | 4. 提交 Pull Request
323 | 5. 代码审查通过后合并
324 |
325 | 遵循这些指南将帮助你创建高质量、一致性的组件!
326 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | // workbench
3 | "workbench.list.smoothScrolling": true,
4 | "workbench.startupEditor": "newUntitledFile",
5 | "workbench.tree.indent": 10,
6 | "workbench.editor.highlightModifiedTabs": true,
7 | "workbench.editor.closeOnFileDelete": true,
8 | "workbench.editor.limit.enabled": true,
9 | "workbench.editor.limit.perEditorGroup": true,
10 | "workbench.editor.limit.value": 5,
11 |
12 | // editor
13 | "editor.formatOnSave": true, // 保存的时候自动格式化
14 | "editor.tabSize": 2,
15 | "editor.detectIndentation": false,
16 | "editor.cursorBlinking": "expand",
17 | "editor.largeFileOptimizations": false,
18 | "editor.accessibilitySupport": "off",
19 | "editor.cursorSmoothCaretAnimation": "on",
20 | "editor.guides.bracketPairs": "active",
21 | "editor.inlineSuggest.enabled": true,
22 | "editor.suggestSelection": "recentlyUsedByPrefix",
23 | "editor.acceptSuggestionOnEnter": "smart",
24 | "editor.suggest.snippetsPreventQuickSuggestions": false,
25 | "editor.stickyScroll.enabled": true,
26 | "editor.hover.sticky": true,
27 | "editor.suggest.insertMode": "replace",
28 | "editor.bracketPairColorization.enabled": true,
29 | "editor.autoClosingBrackets": "beforeWhitespace",
30 | "editor.autoClosingDelete": "always",
31 | "editor.autoClosingOvertype": "always",
32 | "editor.autoClosingQuotes": "beforeWhitespace",
33 | "editor.wordSeparators": "`~!@#%^&*()=+[{]}\\|;:'\",.<>/?",
34 | "editor.codeActionsOnSave": {
35 | "source.fixAll.eslint": "explicit",
36 | "source.fixAll.stylelint": "explicit",
37 | "source.organizeImports": "never"
38 | },
39 | "editor.defaultFormatter": "esbenp.prettier-vscode",
40 | "[html]": {
41 | "editor.defaultFormatter": "esbenp.prettier-vscode"
42 | },
43 | "[css]": {
44 | "editor.defaultFormatter": "esbenp.prettier-vscode"
45 | },
46 | "[scss]": {
47 | "editor.defaultFormatter": "esbenp.prettier-vscode"
48 | },
49 | "[javascript]": {
50 | "editor.defaultFormatter": "esbenp.prettier-vscode"
51 | },
52 | "[typescript]": {
53 | "editor.defaultFormatter": "esbenp.prettier-vscode"
54 | },
55 | "[json]": {
56 | "editor.defaultFormatter": "esbenp.prettier-vscode"
57 | },
58 | "[jsonc]": {
59 | "editor.defaultFormatter": "esbenp.prettier-vscode"
60 | },
61 | "[vue]": {
62 | "editor.defaultFormatter": "esbenp.prettier-vscode"
63 | },
64 | "[markdown]": {
65 | "editor.defaultFormatter": "yzhang.markdown-all-in-one"
66 | },
67 | // extensions
68 | "extensions.ignoreRecommendations": true,
69 |
70 | // terminal
71 | "terminal.integrated.cursorBlinking": true,
72 | "terminal.integrated.persistentSessionReviveProcess": "never",
73 | "terminal.integrated.tabs.enabled": true,
74 | "terminal.integrated.scrollback": 10000,
75 | "terminal.integrated.stickyScroll.enabled": true,
76 |
77 | // files
78 | "files.eol": "\n",
79 | "files.insertFinalNewline": true,
80 | "files.simpleDialog.enable": true,
81 | "files.associations": {
82 | "*.ejs": "html",
83 | "*.art": "html",
84 | "**/tsconfig.json": "jsonc",
85 | "*.json": "jsonc",
86 | "package.json": "json"
87 | },
88 |
89 | "files.exclude": {
90 | "**/.eslintcache": true,
91 | "**/bower_components": true,
92 | "**/.turbo": true,
93 | "**/.idea": true,
94 | "**/tmp": true,
95 | "**/.git": true,
96 | "**/.svn": true,
97 | "**/.hg": true,
98 | "**/CVS": true,
99 | "**/.stylelintcache": true,
100 | "**/.DS_Store": true,
101 | "**/vite.config.mts.*": true,
102 | "**/tea.yaml": true
103 | },
104 | "files.watcherExclude": {
105 | "**/.git/objects/**": true,
106 | "**/.git/subtree-cache/**": true,
107 | "**/.vscode/**": true,
108 | "**/node_modules/**": true,
109 | "**/tmp/**": true,
110 | "**/bower_components/**": true,
111 | "**/dist/**": true,
112 | "**/yarn.lock": true
113 | },
114 |
115 | // search
116 | "search.searchEditor.singleClickBehaviour": "peekDefinition",
117 | "search.followSymlinks": false,
118 | // 在使用搜索功能时,将这些文件夹/文件排除在外
119 | "search.exclude": {
120 | "**/node_modules": true,
121 | "**/*.log": true,
122 | "**/*.log*": true,
123 | "**/bower_components": true,
124 | "**/dist": true,
125 | "**/elehukouben": true,
126 | "**/.git": true,
127 | "**/.github": true,
128 | "**/.gitignore": true,
129 | "**/.svn": true,
130 | "**/.DS_Store": true,
131 | "**/.vitepress/cache": true,
132 | "**/.idea": true,
133 | "**/.vscode": false,
134 | "**/.yarn": true,
135 | "**/tmp": true,
136 | "*.xml": true,
137 | "out": true,
138 | "dist": true,
139 | "node_modules": true,
140 | "CHANGELOG.md": true,
141 | "**/pnpm-lock.yaml": true,
142 | "**/yarn.lock": true
143 | },
144 |
145 | "debug.onTaskErrors": "debugAnyway",
146 | "diffEditor.ignoreTrimWhitespace": false,
147 | "npm.packageManager": "pnpm",
148 |
149 | "css.validate": false,
150 | "less.validate": false,
151 | "scss.validate": false,
152 |
153 | // extension
154 | "emmet.showSuggestionsAsSnippets": true,
155 | "emmet.triggerExpansionOnTab": false,
156 |
157 | "errorLens.enabledDiagnosticLevels": ["warning", "error"],
158 | "errorLens.excludeBySource": ["cSpell", "Grammarly", "eslint"],
159 |
160 | "stylelint.enable": true,
161 | "stylelint.packageManager": "pnpm",
162 | "stylelint.validate": ["css", "less", "postcss", "scss", "vue"],
163 | "stylelint.customSyntax": "postcss-html",
164 | "stylelint.snippet": ["css", "less", "postcss", "scss", "vue"],
165 |
166 | "typescript.inlayHints.enumMemberValues.enabled": true,
167 | "typescript.preferences.preferTypeOnlyAutoImports": true,
168 | "typescript.preferences.includePackageJsonAutoImports": "on",
169 |
170 | "eslint.validate": [
171 | "javascript",
172 | "typescript",
173 | "javascriptreact",
174 | "typescriptreact",
175 | "vue",
176 | "html",
177 | "markdown",
178 | "json",
179 | // 允许注释的 JSON 格式
180 | "jsonc",
181 | "json5"
182 | ],
183 |
184 | // 控制相关文件嵌套展示
185 | "explorer.fileNesting.enabled": true,
186 | "explorer.fileNesting.expand": false,
187 | "explorer.fileNesting.patterns": {
188 | "*.ts": "$(capture).test.ts, $(capture).test.tsx, $(capture).spec.ts, $(capture).spec.tsx, $(capture).d.ts",
189 | "*.tsx": "$(capture).test.ts, $(capture).test.tsx, $(capture).spec.ts, $(capture).spec.tsx,$(capture).d.ts",
190 | "*.env": "$(capture).env.*",
191 | "README.md": "README*,CHANGELOG*,LICENSE,CNAME,Todo*",
192 | "package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,.gitattributes,.gitignore,.gitpod.yml,.npmrc,.browserslistrc,.node-version,.git*,.tazerc.json",
193 | "eslint.config.mjs": ".eslintignore,.prettierignore,.stylelintignore,.commitlintrc.*,.prettierrc.*,prettier.config.*,stylelint.config.*,.lintstagedrc.mjs,cspell.json"
194 | },
195 | "commentTranslate.hover.enabled": false,
196 | "commentTranslate.multiLineMerge": true,
197 | "vue.server.hybridMode": true,
198 | "typescript.tsdk": "node_modules/typescript/lib",
199 | "oxc.enable": false
200 | }
201 |
--------------------------------------------------------------------------------
/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | [English](./README.md) | **简体中文**
2 |
3 | Vue3 Turbo Component Library Template 🚀
4 |
5 |
6 | 快速构建属于你的企业级 Vue 3 组件库,基于最新技术栈的 Monorepo 模板
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | [](https://v3.vuejs.org/)
25 | [](https://www.typescriptlang.org/)
26 | [](https://turbo.build/)
27 | [](https://pnpm.io/)
28 | [](LICENSE)
29 |
30 | 这是一个基于 `Turborepo + Vue 3.5 + TypeScript` 的现代化组件库模板,采用 Monorepo 架构管理多个包,预配置了完整的代码规范和开发工具链。该模板旨在帮助开发者专注于组件开发,而无需处理繁琐的底层配置,快速构建属于自己的企业级组件库。
31 |
32 | ## ✨ 核心特性
33 |
34 | - 🚀 **最新技术栈** - 基于 Vue 3.5 + TypeScript 5+,享受最新特性
35 | - 📦 **Monorepo 架构** - 使用 Turborepo 管理多个包,提升代码复用率
36 | - 🚫 **强制 pnpm** - 解决幽灵依赖问题,节省磁盘空间,提升安装速度
37 | - 🎨 **完整规范配置** - 集成 ESLint、Prettier、Stylelint、Commitlint 等代码规范
38 | - 📚 **文档支持** - 使用 VitePress 构建文档,支持国际化语言切换
39 | - 🔥 **按需引入** - 支持 Tree Shaking,减小最终打包体积
40 | - 🎯 **完整类型提示** - 全面的 TypeScript 类型定义,提升开发体验
41 | - 🛠️ **丰富工具集** - 内置常用 Hooks、工具函数和指令
42 | - 🔄 **热更新支持** - 开发时实时预览,提升开发效率
43 | - 🔧 **一键重命名** - 快速将 @mylib 替换为你的自定义包名
44 | - ⚡️ **多种构建方式** - 支持 Gulp 统一构建或各包独立构建
45 | - 📝 **版本管理** - 使用 Changeset 管理多包版本和发布流程
46 |
47 | ## 📁 项目结构
48 |
49 | ```
50 | ├── apps/
51 | │ └── docs/ # 组件库文档,基于 VitePress
52 | ├── packages/
53 | │ ├── ui/ # UI 组件库
54 | │ ├── hooks/ # 自定义 Hooks
55 | │ ├── directives/ # 自定义指令
56 | │ ├── utils/ # 工具函数库
57 | │ └── lint-configs/ # 代码规范配置
58 | ├── playground/ # 组件演示环境
59 | ├── build/ # 统一构建脚本
60 | └── scripts/ # 辅助脚本
61 | ```
62 |
63 | ## 🚀 快速开始
64 |
65 | ```bash
66 | # 1. 克隆项目模板
67 | git clone https://github.com/huangmingfu/vue3-turbo-component-lib-template.git
68 |
69 | # 2. 安装依赖
70 | pnpm install
71 |
72 | # 3. 启动开发环境
73 | pnpm dev
74 |
75 | # 4. 构建项目
76 | pnpm build
77 | ```
78 |
79 | ### 安装组件库到你的项目
80 |
81 | ```bash
82 | # 将 @mylib 替换为你自己的包名
83 | pnpm add @mylib/ui @mylib/utils @mylib/hooks @mylib/directives
84 |
85 | # 示例安装
86 | pnpm add @hmflib/ui @hmflib/utils @hmflib/hooks @hmflib/directives
87 | ```
88 |
89 | ## 🧰 开发命令
90 |
91 | ```bash
92 | # 开发相关
93 | pnpm dev # 启动所有包的开发环境
94 | pnpm dev:docs # 启动文档应用
95 | pnpm dev:play # 启动演练场
96 |
97 | # 构建相关
98 | pnpm build # 构建所有包
99 | pnpm build:docs # 构建文档应用
100 | pnpm build:gulp # 使用 gulp 统一打包
101 |
102 | # 测试相关
103 | pnpm test # 测试所有包
104 | pnpm test:ui # 测试 UI 包
105 | pnpm test:coverage # 测试所有包的覆盖率
106 |
107 | # 代码质量
108 | pnpm lint:all # 检查所有代码规范
109 | pnpm deps:check # 检查依赖更新
110 | pnpm deps:update # 更新所有依赖
111 |
112 | # 其他
113 | pnpm clean # 清理构建产物
114 | pnpm rename-pkg # 一键重命名包名
115 | pnpm generate:component # 生成新组件
116 | ```
117 |
118 | ## 🎯 为什么选择这个模板?
119 |
120 | ### 相比其他组件库模板的优势:
121 |
122 | 1. **技术前沿** - 基于最新版本的 Vue 3.5 和 TypeScript 5+,始终与技术发展同步
123 | 2. **开箱即用** - 预配置完整的开发工具链,无需额外配置即可开始开发
124 | 3. **灵活架构** - Monorepo 结构便于管理多个包,同时保持各模块的独立性
125 | 4. **企业级规范** - 集成完整的代码规范和提交规范,保证代码质量
126 | 5. **文档完善** - 内置文档系统,支持国际化,便于组件文档编写
127 | 6. **多种构建方式** - 支持统一构建和独立构建,适应不同团队需求
128 | 7. **易于定制** - 提供一键重命名脚本,快速定制为自己的组件库
129 |
130 | ## 📸 效果预览
131 |
132 | ### 文档系统
133 |
134 | > 支持国际化语言切换
135 |
136 | 
137 | 
138 | 
139 |
140 | ### 演练场
141 |
142 | > 实时预览和测试组件
143 |
144 | 
145 | 
146 |
147 | ## 🔧 技术栈
148 |
149 | - [Vue 3](https://vuejs.org/) - 渐进式 JavaScript 框架
150 | - [TypeScript](https://www.typescriptlang.org/) - JavaScript 的超集,提供类型安全
151 | - [Turborepo](https://turbo.build/repo) - 高性能的 Monorepo 构建系统
152 | - [VitePress](https://vitepress.dev/) - 基于 Vite 的静态站点生成器
153 | - [Vite](https://vitejs.dev/) - 新一代前端构建工具
154 | - [pnpm](https://pnpm.io/) - 快速、节省磁盘空间的包管理器
155 | - [ESLint](https://eslint.org/) - JavaScript/TypeScript 代码质量检查工具
156 | - [Prettier](https://prettier.io/) - 代码格式化工具
157 | - [Stylelint](https://stylelint.io/) - CSS/SCSS/Less 代码检查工具
158 | - [Commitlint](https://commitlint.js.org/) - 提交信息规范检查工具
159 | - [husky](https://typicode.github.io/husky/) - Git 提交钩子管理工具
160 | - [lint-staged](https://github.com/lint-staged/lint-staged) - 对 Git 暂存文件进行 lint 检查
161 | - [Changesets](https://github.com/changesets/changesets) - 版本管理和发布工具
162 |
163 | ## 📚 相关链接
164 |
165 | > 部分代码和结构设计参考了 [Vben5](https://github.com/vbenjs/vue-vben-admin)
166 |
167 | - [Vue 3 官方文档](https://vuejs.org/)
168 | - [TypeScript 官方文档](https://www.typescriptlang.org/)
169 | - [Turborepo 官方文档](https://turbo.build/repo)
170 | - [VitePress 官方文档](https://vitepress.dev/)
171 | - [Vben Admin](https://github.com/vbenjs/vue-vben-admin)
172 |
173 | ## ❓ 常见问题
174 |
175 | ### 1. 为什么推荐使用 pnpm?
176 |
177 | pnpm 相比 npm 和 yarn 有以下优势:
178 |
179 | - 解决了幽灵依赖和幻影依赖问题
180 | - 节省大量磁盘空间
181 | - 安装速度更快
182 | - 保证 node_modules 结构的一致性
183 |
184 | ### 2. 如何自定义包名?
185 |
186 | 项目默认使用 `@mylib` 作为包名前缀,你可以通过以下命令一键替换:
187 |
188 | ```bash
189 | # 将 @mylib 替换为你的自定义包名,例如 @yourname
190 | pnpm rename-pkg "@mylib" "@yourname"
191 | ```
192 |
193 | ### 3. 如何生成新组件?
194 |
195 | 使用内置脚本可以快速生成新组件:
196 |
197 | ```bash
198 | pnpm generate:component
199 | ```
200 |
201 | ### 4. 遇到命令执行失败怎么办?
202 |
203 | 如果遇到 `rm -rf` 或其他 shell 命令执行失败的问题,请使用 Git Bash 终端运行命令。
204 | 
205 |
206 | 如果 `pnpm run dev` 运行失败,请先执行构建命令:
207 |
208 | ```bash
209 | pnpm run build
210 | pnpm run dev
211 | ```
212 |
213 | ## 🤝 贡献指南
214 |
215 | 欢迎任何形式的贡献!
216 |
217 | 1. Fork 本仓库
218 | 2. 创建你的特性分支 (`git checkout -b feature/AmazingFeature`)
219 | 3. 提交你的改动 (`git commit -m 'Add some AmazingFeature'`)
220 | 4. 推送到分支 (`git push origin feature/AmazingFeature`)
221 | 5. 打开一个 Pull Request
222 |
223 | ## 📄 许可证
224 |
225 | [MIT](LICENSE)
226 |
227 | ---
228 |
229 | ⭐ 如果你喜欢这个项目,请给它一个 star!你的支持是我们持续改进的动力!
230 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **English** | [简体中文](./README.zh-CN.md)
2 |
3 | Vue3 Turbo Component Library Template 🚀
4 |
5 |
6 | 快速构建属于你的企业级 Vue 3 组件库,基于最新技术栈的 Monorepo 模板
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | [](https://v3.vuejs.org/)
25 | [](https://www.typescriptlang.org/)
26 | [](https://turbo.build/)
27 | [](https://pnpm.io/)
28 | [](LICENSE)
29 |
30 | A modern component library template based on `Turborepo + Vue 3.5 + TypeScript`, using Monorepo architecture to manage multiple packages with pre-configured code standards and development toolchain. This template helps developers focus on component development without dealing with complicated underlying configurations, quickly building their own enterprise-level component library.
31 |
32 | ## ✨ Key Features
33 |
34 | - 🚀 **Cutting-edge Tech Stack** - Built on Vue 3.5 + TypeScript 5+, enjoy the latest features
35 | - 📦 **Monorepo Architecture** - Managed with Turborepo for multiple packages, improving code reusability
36 | - 🚫 **Enforced pnpm** - Resolves phantom dependencies, saves disk space, improves installation speed
37 | - 🎨 **Complete Standards** - Integrated ESLint, Prettier, Stylelint, Commitlint and other code standards
38 | - 📚 **Documentation Support** - Built with VitePress, supports internationalization
39 | - 🔥 **On-demand Import** - Supports Tree Shaking to reduce final bundle size
40 | - 🎯 **Full Type Support** - Comprehensive TypeScript type definitions for better DX
41 | - 🛠️ **Rich Toolset** - Built-in common Hooks, utility functions and directives
42 | - 🔄 **HMR Support** - Real-time preview during development, boosts productivity
43 | - 🔧 **One-click Renaming** - Quickly replace @mylib with your custom package name
44 | - ⚡️ **Multiple Build Modes** - Supports unified build with Gulp or individual package builds
45 | - 📝 **Version Management** - Uses Changeset for multi-package versioning and release workflow
46 |
47 | ## 📁 Project Structure
48 |
49 | ```
50 | ├── apps/
51 | │ └── docs/ # Component library documentation based on VitePress
52 | ├── packages/
53 | │ ├── ui/ # UI component library
54 | │ ├── hooks/ # Custom Hooks
55 | │ ├── directives/ # Custom directives
56 | │ ├── utils/ # Utility functions
57 | │ └── lint-configs/ # Code standard configurations
58 | ├── playground/ # Component demo environment
59 | ├── build/ # Unified build scripts
60 | └── scripts/ # Helper scripts
61 | ```
62 |
63 | ## 🚀 Quick Start
64 |
65 | ```bash
66 | # 1. Clone the template
67 | git clone https://github.com/huangmingfu/vue3-turbo-component-lib-template.git
68 |
69 | # 2. Install dependencies
70 | pnpm install
71 |
72 | # 3. Start development environment
73 | pnpm dev
74 |
75 | # 4. Build the project
76 | pnpm build
77 | ```
78 |
79 | ### Install the component library in your project
80 |
81 | ```bash
82 | # Replace @mylib with your own package name
83 | pnpm add @mylib/ui @mylib/utils @mylib/hooks @mylib/directives
84 |
85 | # Example installation
86 | pnpm add @hmflib/ui @hmflib/utils @hmflib/hooks @hmflib/directives
87 | ```
88 |
89 | ## 🧰 Development Commands
90 |
91 | ```bash
92 | # Development
93 | pnpm dev # Start development environment for all packages
94 | pnpm dev:docs # Start documentation application
95 | pnpm dev:play # Start playground
96 |
97 | # Building
98 | pnpm build # Build all packages
99 | pnpm build:docs # Build documentation application
100 | pnpm build:gulp # Unified build with gulp
101 |
102 | # Testing
103 | pnpm test # Test all packages
104 | pnpm test:ui # Test UI package
105 | pnpm test:coverage # Test coverage for all packages
106 |
107 | # Code Quality
108 | pnpm lint:all # Check all code standards
109 | pnpm deps:check # Check for dependency updates
110 | pnpm deps:update # Update all dependencies
111 |
112 | # Others
113 | pnpm clean # Clean build artifacts
114 | pnpm rename-pkg # One-click package renaming
115 | pnpm generate:component # Generate new component
116 | ```
117 |
118 | ## 🎯 Why Choose This Template?
119 |
120 | ### Advantages over other component library templates:
121 |
122 | 1. **Cutting-edge Technology** - Based on the latest Vue 3.5 and TypeScript 5+, always in sync with technological development
123 | 2. **Ready to Use** - Pre-configured complete development toolchain, start developing without additional setup
124 | 3. **Flexible Architecture** - Monorepo structure for managing multiple packages while maintaining module independence
125 | 4. **Enterprise-grade Standards** - Integrated complete code and commit standards to ensure code quality
126 | 5. **Comprehensive Documentation** - Built-in documentation system with internationalization support
127 | 6. **Multiple Build Options** - Supports both unified and independent builds to meet different team needs
128 | 7. **Easy Customization** - One-click renaming script to quickly customize to your own component library
129 |
130 | ## 📸 Preview
131 |
132 | ### Documentation System
133 |
134 | > Supports internationalization
135 |
136 | 
137 | 
138 | 
139 |
140 | ### Playground
141 |
142 | > Real-time preview and testing of components
143 |
144 | 
145 | 
146 |
147 | ## 🔧 Tech Stack
148 |
149 | - [Vue 3](https://vuejs.org/) - Progressive JavaScript framework
150 | - [TypeScript](https://www.typescriptlang.org/) - Superset of JavaScript with type safety
151 | - [Turborepo](https://turbo.build/repo) - High-performance Monorepo build system
152 | - [VitePress](https://vitepress.dev/) - Vite-powered static site generator
153 | - [Vite](https://vitejs.dev/) - Next-generation frontend build tool
154 | - [pnpm](https://pnpm.io/) - Fast, disk space efficient package manager
155 | - [ESLint](https://eslint.org/) - JavaScript/TypeScript code quality tool
156 | - [Prettier](https://prettier.io/) - Code formatter
157 | - [Stylelint](https://stylelint.io/) - CSS/SCSS/Less code linter
158 | - [Commitlint](https://commitlint.js.org/) - Commit message linting tool
159 | - [husky](https://typicode.github.io/husky/) - Git hooks manager
160 | - [lint-staged](https://github.com/lint-staged/lint-staged) - Run linters on git staged files
161 | - [Changesets](https://github.com/changesets/changesets) - Versioning and release management tool
162 |
163 | ## 📚 Related Links
164 |
165 | > Some code and structure design references [Vben5](https://github.com/vbenjs/vue-vben-admin)
166 |
167 | - [Vue 3 Official Documentation](https://vuejs.org/)
168 | - [TypeScript Official Documentation](https://www.typescriptlang.org/)
169 | - [Turborepo Official Documentation](https://turbo.build/repo)
170 | - [VitePress Official Documentation](https://vitepress.dev/)
171 | - [Vben Admin](https://github.com/vbenjs/vue-vben-admin)
172 |
173 | ## ❓ FAQ
174 |
175 | ### 1. Why recommend pnpm?
176 |
177 | pnpm has the following advantages over npm and yarn:
178 |
179 | - Solves phantom and doppelganger dependencies issues
180 | - Saves significant disk space
181 | - Faster installation speed
182 | - Ensures consistent node_modules structure
183 |
184 | ### 2. How to customize package names?
185 |
186 | The project uses `@mylib` as the default package name prefix. You can replace it with one command:
187 |
188 | ```bash
189 | # Replace @mylib with your custom package name, e.g. @yourname
190 | pnpm rename-pkg "@mylib" "@yourname"
191 | ```
192 |
193 | ### 3. How to generate new components?
194 |
195 | Use the built-in script to quickly generate new components:
196 |
197 | ```bash
198 | pnpm generate:component
199 | ```
200 |
201 | ### 4. What to do if command execution fails?
202 |
203 | If you encounter issues executing `rm -rf` or other shell commands, please use Git Bash terminal to run the commands.
204 | 
205 |
206 | If `pnpm run dev` fails, first execute the build command:
207 |
208 | ```bash
209 | pnpm run build
210 | pnpm run dev
211 | ```
212 |
213 | ## 🤝 Contributing
214 |
215 | Contributions of any kind are welcome!
216 |
217 | 1. Fork the repository
218 | 2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
219 | 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
220 | 4. Push to the branch (`git push origin feature/AmazingFeature`)
221 | 5. Open a Pull Request
222 |
223 | ## 📄 License
224 |
225 | [MIT](LICENSE)
226 |
227 | ---
228 |
229 | ⭐ If you like this project, please give it a star! Your support is our motivation for continuous improvement!
230 |
--------------------------------------------------------------------------------