├── .node-version ├── .gitattributes ├── .husky ├── pre-commit └── commit-msg ├── .stylelintignore ├── packages ├── ui │ ├── src │ │ ├── _utils │ │ │ ├── index.ts │ │ │ └── with-install.ts │ │ ├── components │ │ │ ├── index.ts │ │ │ ├── Dialog │ │ │ │ ├── Dialog.types.ts │ │ │ │ ├── index.ts │ │ │ │ ├── Dialog.scss │ │ │ │ └── Dialog.vue │ │ │ └── Button │ │ │ │ ├── index.ts │ │ │ │ ├── Button.types.ts │ │ │ │ ├── Button.vue │ │ │ │ ├── Button.scss │ │ │ │ └── __tests__ │ │ │ │ └── Button.spec.ts │ │ ├── types │ │ │ ├── env.d.ts │ │ │ └── global.d.ts │ │ ├── version.ts │ │ ├── index.ts │ │ └── __tests__ │ │ │ ├── setup.ts │ │ │ └── performance.bench.ts │ ├── CHANGELOG.md │ ├── tsconfig.json │ ├── vitest.config.ts │ ├── README.md │ ├── package.json │ ├── vite.config.ts │ └── COMPONENT_GUIDE.md ├── hooks │ ├── tsconfig.json │ ├── src │ │ ├── index.ts │ │ ├── version.ts │ │ └── useCounter │ │ │ └── index.ts │ ├── CHANGELOG.md │ ├── rollup.config.mjs │ └── package.json ├── directives │ ├── tsconfig.json │ ├── CHANGELOG.md │ ├── src │ │ ├── version.ts │ │ ├── v-focus │ │ │ └── index.ts │ │ └── index.ts │ ├── package.json │ └── rollup.config.mjs ├── utils │ ├── CHANGELOG.md │ ├── src │ │ ├── index.ts │ │ ├── version.ts │ │ ├── array │ │ │ └── index.ts │ │ └── string │ │ │ └── index.ts │ ├── tsconfig.json │ ├── package.json │ └── rollup.config.mjs └── lint-configs │ ├── typescript-config │ ├── package.json │ ├── node.json │ ├── build.json │ ├── vite.json │ └── base.json │ ├── prettier-config │ ├── index.mjs │ └── package.json │ ├── commitlint-config │ ├── package.json │ └── index.mjs │ ├── eslint-config │ ├── package.json │ └── index.mjs │ └── stylelint-config │ ├── package.json │ └── index.mjs ├── .commitlintrc.mjs ├── apps └── docs │ ├── .vitepress │ ├── theme │ │ ├── styles │ │ │ ├── global.css │ │ │ └── var.css │ │ └── index.ts │ ├── config.mts │ ├── utils │ │ └── useGlobalComp.ts │ └── config │ │ ├── shared.ts │ │ ├── zh.ts │ │ └── en.ts │ ├── public │ ├── logo.png │ └── favicon.ico │ ├── zh │ ├── packages │ │ ├── directives │ │ │ └── vFocus.md │ │ ├── hooks │ │ │ └── useCounter.md │ │ ├── utils │ │ │ └── string.md │ │ └── ui │ │ │ ├── dialog.md │ │ │ └── button.md │ ├── index.md │ └── guide │ │ └── index.md │ ├── en │ ├── packages │ │ ├── directives │ │ │ └── vFocus.md │ │ ├── hooks │ │ │ └── useCounter.md │ │ ├── utils │ │ │ └── string.md │ │ └── ui │ │ │ ├── dialog.md │ │ │ └── button.md │ ├── index.md │ └── guide │ │ └── index.md │ ├── examples │ ├── directives │ │ └── vFocus │ │ │ └── basic.vue │ ├── ui │ │ ├── dialog │ │ │ └── basic.vue │ │ └── button │ │ │ └── basic.vue │ └── hooks │ │ └── useCounter │ │ └── basic.vue │ ├── tsconfig.json │ └── package.json ├── eslint.config.mjs ├── prettier.config.mjs ├── stylelint.config.mjs ├── playground ├── public │ └── favicon.ico ├── src │ ├── layouts │ │ ├── container │ │ │ ├── Ui.vue │ │ │ ├── Hooks.vue │ │ │ ├── Utils.vue │ │ │ └── Directives.vue │ │ ├── TabsView.vue │ │ └── MainLayout.vue │ ├── views │ │ ├── Directives │ │ │ └── vFocus.vue │ │ ├── Hooks │ │ │ └── useCounter.vue │ │ ├── Ui │ │ │ ├── Dialog.vue │ │ │ └── Button.vue │ │ └── Utils │ │ │ ├── All.vue │ │ │ └── __test__ │ │ │ ├── array.spec.ts │ │ │ └── string.spec.ts │ ├── App.vue │ ├── types │ │ ├── router.d.ts │ │ └── env.d.ts │ ├── main.ts │ └── router │ │ └── index.ts ├── vitest.workspace.ts ├── index.html ├── vite.config.ts ├── tsconfig.json └── package.json ├── .prettierignore ├── .gitignore ├── .changeset └── config.json ├── .npmrc ├── .editorconfig ├── my-lib.code-workspace ├── .lintstagedrc.mjs ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── turbo.json ├── LICENSE ├── scripts ├── rename-package.sh └── generate-component.mjs ├── pnpm-workspace.yaml ├── .github └── workflows │ └── ci.yml ├── package.json ├── CONTRIBUTING.md ├── README.zh-CN.md └── README.md /.node-version: -------------------------------------------------------------------------------- 1 | 22 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | pnpm exec lint-staged 2 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | dist 2 | public 3 | __tests__ 4 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx --no-install commitlint --edit "$1" 2 | -------------------------------------------------------------------------------- /packages/ui/src/_utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './with-install'; 2 | -------------------------------------------------------------------------------- /.commitlintrc.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@mylib/commitlint-config'; 2 | -------------------------------------------------------------------------------- /apps/docs/.vitepress/theme/styles/global.css: -------------------------------------------------------------------------------- 1 | @import './var.css'; 2 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@mylib/eslint-config'; 2 | -------------------------------------------------------------------------------- /prettier.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@mylib/prettier-config'; 2 | -------------------------------------------------------------------------------- /packages/hooks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@mylib/typescript-config/base.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/ui/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Button'; 2 | export * from './Dialog'; 3 | -------------------------------------------------------------------------------- /packages/directives/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@mylib/typescript-config/base.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/hooks/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useCounter'; 2 | export { version } from './version'; 3 | -------------------------------------------------------------------------------- /packages/ui/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @mylib/ui 2 | 3 | ## 1.0.0 4 | 5 | ### Major Changes 6 | 7 | - test发布 8 | -------------------------------------------------------------------------------- /stylelint.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | root: true, 3 | extends: '@mylib/stylelint-config', 4 | }; 5 | -------------------------------------------------------------------------------- /packages/hooks/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @mylib/hooks 2 | 3 | ## 1.0.0 4 | 5 | ### Major Changes 6 | 7 | - test发布 8 | -------------------------------------------------------------------------------- /packages/utils/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @mylib/utils 2 | 3 | ## 1.0.0 4 | 5 | ### Major Changes 6 | 7 | - test发布 8 | -------------------------------------------------------------------------------- /packages/directives/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @mylib/directives 2 | 3 | ## 1.0.0 4 | 5 | ### Major Changes 6 | 7 | - test发布 8 | -------------------------------------------------------------------------------- /packages/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './string'; 2 | export * from './array'; 3 | export { version } from './version'; 4 | -------------------------------------------------------------------------------- /apps/docs/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangmingfu/vue3-turbo-component-lib-template/HEAD/apps/docs/public/logo.png -------------------------------------------------------------------------------- /apps/docs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangmingfu/vue3-turbo-component-lib-template/HEAD/apps/docs/public/favicon.ico -------------------------------------------------------------------------------- /apps/docs/zh/packages/directives/vFocus.md: -------------------------------------------------------------------------------- 1 | # vFocus 2 | 3 | > 聚焦指令 4 | 5 | ## 基础用法 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/hooks/src/version.ts: -------------------------------------------------------------------------------- 1 | import { version as pkgVersion } from '../package.json'; 2 | 3 | export const version: string = pkgVersion; 4 | -------------------------------------------------------------------------------- /packages/utils/src/version.ts: -------------------------------------------------------------------------------- 1 | import { version as pkgVersion } from '../package.json'; 2 | 3 | export const version: string = pkgVersion; 4 | -------------------------------------------------------------------------------- /playground/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangmingfu/vue3-turbo-component-lib-template/HEAD/playground/public/favicon.ico -------------------------------------------------------------------------------- /apps/docs/zh/packages/hooks/useCounter.md: -------------------------------------------------------------------------------- 1 | # useCounter 2 | 3 | > 计数器 Hook。 4 | 5 | ## 基础用法 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/directives/src/version.ts: -------------------------------------------------------------------------------- 1 | import { version as pkgVersion } from '../package.json'; 2 | 3 | export const version: string = pkgVersion; 4 | -------------------------------------------------------------------------------- /apps/docs/en/packages/directives/vFocus.md: -------------------------------------------------------------------------------- 1 | # vFocus 2 | 3 | > Focus Directive 4 | 5 | ## Basic Usage 6 | 7 | 8 | -------------------------------------------------------------------------------- /apps/docs/en/packages/hooks/useCounter.md: -------------------------------------------------------------------------------- 1 | # useCounter 2 | 3 | > A counter Hook. 4 | 5 | ## Basic Usage 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/directives/src/v-focus/index.ts: -------------------------------------------------------------------------------- 1 | const focus = { 2 | mounted(el: HTMLElement) { 3 | el.focus(); 4 | }, 5 | }; 6 | 7 | export default focus; 8 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | .local 3 | .output.js 4 | node_modules 5 | .nvmrc 6 | .output 7 | 8 | **/*.svg 9 | **/*.sh 10 | 11 | public 12 | .npmrc 13 | *-lock.yaml 14 | -------------------------------------------------------------------------------- /packages/ui/src/components/Dialog/Dialog.types.ts: -------------------------------------------------------------------------------- 1 | export interface DialogProps { 2 | open: boolean; 3 | } 4 | 5 | export interface DialogEmits { 6 | (e: 'close'): void; 7 | } 8 | -------------------------------------------------------------------------------- /playground/src/layouts/container/Ui.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /playground/src/layouts/container/Hooks.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /playground/src/layouts/container/Utils.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /packages/directives/src/index.ts: -------------------------------------------------------------------------------- 1 | import vFocus from './v-focus'; 2 | 3 | export { version } from './version'; 4 | 5 | export { vFocus }; 6 | 7 | export default { 8 | vFocus, 9 | }; 10 | -------------------------------------------------------------------------------- /packages/ui/src/types/env.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import type { DefineComponent } from 'vue'; 3 | const component: DefineComponent<{}, {}, any>; 4 | export default component; 5 | } 6 | -------------------------------------------------------------------------------- /playground/src/layouts/container/Directives.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /packages/lint-configs/typescript-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mylib/typescript-config", 3 | "version": "0.0.1", 4 | "private": true, 5 | "publishConfig": { 6 | "access": "public" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /playground/src/views/Directives/vFocus.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /apps/docs/zh/packages/utils/string.md: -------------------------------------------------------------------------------- 1 | # 字符串工具 2 | 3 | ## isString 4 | 5 | > 判断是否为字符串。 6 | 7 | ```ts 8 | import { isString } from '@mylib/utils'; 9 | 10 | isString('hello'); // true 11 | isString(123); // false 12 | ``` 13 | -------------------------------------------------------------------------------- /packages/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@mylib/typescript-config/base.json", 3 | "include": ["src/**/*.ts", "src/**/*.d.ts"], 4 | "compilerOptions": { 5 | "target": "ESNext", 6 | "lib": ["ESNext", "DOM"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/ui/src/components/Button/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from '~/_utils'; 2 | import Button from './Button.vue'; 3 | 4 | export const VButton = withInstall(Button); 5 | export default VButton; 6 | 7 | export * from './Button.types'; 8 | -------------------------------------------------------------------------------- /packages/ui/src/components/Dialog/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from '~/_utils'; 2 | import Dialog from './Dialog.vue'; 3 | 4 | export const VDialog = withInstall(Dialog); 5 | export default VDialog; 6 | 7 | export * from './Dialog.types'; 8 | -------------------------------------------------------------------------------- /packages/lint-configs/prettier-config/index.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import("prettier").Config} */ 2 | export default { 3 | printWidth: 100, // 一行的字符数,如果超过会进行换行,默认为80 4 | singleQuote: true, // 字符串使用双引号 5 | endOfLine: 'auto', // 文件末尾的换行符,自动识别系统 6 | }; 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist* 5 | out/ 6 | .tmp/ 7 | *.log 8 | .output 9 | *.local 10 | **/.vitepress/cache 11 | .cache 12 | .turbo 13 | .temp 14 | .stylelintcache 15 | .eslintcache 16 | 17 | yarn.lock 18 | package-lock.json 19 | -------------------------------------------------------------------------------- /apps/docs/en/packages/utils/string.md: -------------------------------------------------------------------------------- 1 | # String Utilities 2 | 3 | ## isString 4 | 5 | > Determines if a value is a string. 6 | 7 | ```ts 8 | import { isString } from '@mylib/utils'; 9 | 10 | isString('hello'); // true 11 | isString(123); // false 12 | ``` 13 | -------------------------------------------------------------------------------- /packages/ui/src/version.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 需要多作一层导出,不能直接在index.ts中:export { version } from '../package.json'; 3 | * types类型打包的产物里会找不到这个pkgjson文件,虽然不影响使用,但是ts会报红 4 | */ 5 | 6 | import { version as pkgVersion } from '../package.json'; 7 | 8 | export const version: string = pkgVersion; 9 | -------------------------------------------------------------------------------- /playground/src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | -------------------------------------------------------------------------------- /apps/docs/examples/directives/vFocus/basic.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /playground/src/types/router.d.ts: -------------------------------------------------------------------------------- 1 | import type { Component } from 'vue'; 2 | 3 | interface RouteMetaCustom extends Record { 4 | title?: string; 5 | icon?: Component; 6 | } 7 | 8 | declare module 'vue-router' { 9 | interface RouteMeta extends RouteMetaCustom {} 10 | } 11 | -------------------------------------------------------------------------------- /packages/lint-configs/typescript-config/node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "./base.json", 4 | "compilerOptions": { 5 | "composite": false, 6 | "lib": ["ESNext"], 7 | "baseUrl": "./", 8 | "types": ["node"], 9 | "noImplicitAny": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/lint-configs/typescript-config/build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./base.json", 3 | "include": ["src/**/*.ts", "src/**/*.d.ts"], 4 | "compilerOptions": { 5 | "target": "ESNext", 6 | "declaration": true, 7 | "declarationMap": false, 8 | "declarationDir": "./dist", 9 | "outDir": "./dist" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /playground/src/views/Hooks/useCounter.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /apps/docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import DefaultTheme from 'vitepress/theme'; 2 | // 引入UI库的样式 3 | import '@mylib/ui/style.css'; 4 | import { useGlobalComp } from '../utils/useGlobalComp'; 5 | // 自定义样式重载 6 | import './styles/global.css'; 7 | 8 | export default { 9 | extends: DefaultTheme, 10 | enhanceApp({ app }) { 11 | useGlobalComp(app); 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /apps/docs/.vitepress/theme/styles/var.css: -------------------------------------------------------------------------------- 1 | :root { 2 | /* 首页标题 */ 3 | --vp-home-hero-name-color: transparent; 4 | --vp-home-hero-name-background: linear-gradient(120deg, #bd34fe, #41d1ff); 5 | 6 | /* 首页图标背景 */ 7 | --vp-home-hero-image-background-image: linear-gradient(-45deg, #bd34fe9e 50%, #47caff96 50%); 8 | --vp-home-hero-image-filter: blur(150px); 9 | } 10 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.0.4/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "master", 9 | "updateInternalDependencies": "patch", 10 | "ignore": ["@mylib/build", "@mylib/playground", "@mylib/docs"] 11 | } 12 | -------------------------------------------------------------------------------- /playground/vitest.workspace.ts: -------------------------------------------------------------------------------- 1 | import { defineWorkspace } from 'vitest/config'; 2 | 3 | /** 4 | * @see https://cn.vitest.dev/guide/ 5 | */ 6 | export default defineWorkspace([ 7 | { 8 | test: { 9 | name: '@mylib/utils', // 测试名称 10 | root: './src/views/Utils/__test__', // 测试根目录 11 | include: ['array.spec.ts'], // 只测这个文件,测全部可以注释掉 12 | }, 13 | }, 14 | ]); 15 | -------------------------------------------------------------------------------- /packages/hooks/src/useCounter/index.ts: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue'; 2 | 3 | export function useCounter(initialValue = 0) { 4 | const count = ref(initialValue); 5 | 6 | const increment = () => { 7 | count.value++; 8 | }; 9 | 10 | const decrement = () => { 11 | count.value--; 12 | }; 13 | 14 | return { 15 | count, 16 | increment, 17 | decrement, 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /packages/utils/src/array/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 数组去重 3 | */ 4 | export const unique = (arr: T[]): T[] => { 5 | return Array.from(new Set(arr)); 6 | }; 7 | 8 | /** 9 | * 数组分块 10 | */ 11 | export const chunk = (arr: T[], size: number): T[][] => { 12 | return Array.from({ length: Math.ceil(arr.length / size) }, (_, i) => 13 | arr.slice(i * size, i * size + size), 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /playground/src/views/Ui/Dialog.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 16 | -------------------------------------------------------------------------------- /apps/docs/.vitepress/config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress'; 2 | import { shared } from './config/shared'; 3 | import { en } from './config/en'; 4 | import { zh } from './config/zh'; 5 | 6 | // https://vitepress.dev/reference/site-config 7 | export default defineConfig({ 8 | ...shared, 9 | locales: { 10 | root: { label: '简体中文', ...zh }, 11 | en: { label: 'English', ...en }, 12 | }, 13 | }); 14 | -------------------------------------------------------------------------------- /packages/ui/src/components/Button/Button.types.ts: -------------------------------------------------------------------------------- 1 | export type ButtonType = 'primary' | 'success' | 'warning' | 'danger' | 'info'; 2 | export type ButtonSize = 'small' | 'medium' | 'large'; 3 | 4 | export interface ButtonProps { 5 | type?: ButtonType; 6 | size?: ButtonSize; 7 | disabled?: boolean; 8 | round?: boolean; 9 | } 10 | 11 | export interface ButtonEmits { 12 | (e: 'click', event: MouseEvent): void; 13 | } 14 | -------------------------------------------------------------------------------- /apps/docs/examples/ui/dialog/basic.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | 18 | -------------------------------------------------------------------------------- /playground/src/types/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | 5 | declare module '*.vue' { 6 | import type { DefineComponent } from 'vue'; 7 | const component: DefineComponent<{}, {}, any>; 8 | export default component; 9 | } 10 | 11 | declare module 'mylib/ui' { 12 | export * from '@mylib/ui'; 13 | } 14 | -------------------------------------------------------------------------------- /packages/lint-configs/typescript-config/vite.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "./base.json", 4 | "compilerOptions": { 5 | "jsx": "preserve", 6 | "jsxImportSource": "vue", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "useDefineForClassFields": true, 9 | "moduleResolution": "bundler", 10 | "types": ["vite/client"], 11 | "declaration": false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /playground/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Playground 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # 设置最新的淘宝镜像,加快安装依赖速度 2 | registry = https://registry.npmmirror.com # https://registry.npmjs.org 官方镜像 3 | # # 发包禁用 git 仓库的校验 4 | # git-checks = false 5 | 6 | # 强制检查 engines 字段中指定的版本要求,即强制使用指定的 Node.js 版本 7 | engine-strict=true 8 | # 是否自动安装 peerDependencies(对等依赖) 中的依赖 9 | auto-install-peers=false 10 | # 是否严格检查 peerDependencies 的版本要求 11 | strict-peer-dependencies=false 12 | # 允许将依赖项提升到顶层,即将依赖提升到根目录的 node_modules,避免重复安装 13 | shamefully-hoist=true 14 | -------------------------------------------------------------------------------- /packages/ui/src/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue'; 2 | import { VButton, VDialog } from './components'; 3 | 4 | export { version } from './version'; 5 | 6 | const components = [VButton, VDialog]; 7 | 8 | function install(app: App) { 9 | components.forEach((component) => { 10 | app.use(component); 11 | }); 12 | } 13 | 14 | export { install }; 15 | 16 | export * from './components'; 17 | 18 | export default { 19 | install, 20 | }; 21 | -------------------------------------------------------------------------------- /playground/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | 3 | import App from './App.vue'; 4 | import router from './router'; 5 | // 引入antdv 6 | import Antd from 'ant-design-vue'; 7 | import 'ant-design-vue/dist/reset.css'; 8 | // 引入@mylib/ui 9 | import MyLibUI from '@mylib/ui'; 10 | import '@mylib/ui/style.css'; 11 | 12 | const app = createApp(App); 13 | app.use(Antd); // 全局引入antdv组件 14 | app.use(MyLibUI); // 全局引入@mylib/ui组件 15 | app.use(router); 16 | app.mount('#app'); 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # @see: http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] # 表示所有文件适用 6 | charset = utf-8 # 设置文件字符集为 utf-8 7 | end_of_line = lf # 控制换行类型(lf | cr | crlf) 8 | insert_final_newline = true # 始终在文件末尾插入一个新行 9 | indent_style = space # 缩进风格(tab | space) 10 | indent_size = 2 # 缩进大小 11 | max_line_length = 100 # 最大行长度 12 | 13 | [*.md] # 表示仅 md 文件适用以下规则 14 | insert_final_newline = false # 关闭末尾新行插入 15 | max_line_length = off # 关闭最大行长度限制 16 | trim_trailing_whitespace = false # 关闭末尾空格修剪 17 | -------------------------------------------------------------------------------- /packages/utils/src/string/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 将字符串的首字母转换为大写 3 | */ 4 | export const capitalize = (str: string): string => { 5 | return str.charAt(0).toUpperCase() + str.slice(1); 6 | }; 7 | 8 | /** 9 | * 将驼峰命名转换为短横线命名 10 | */ 11 | export const camelToKebab = (str: string): string => { 12 | return str.replace(/([A-Z])/g, '-$1').toLowerCase(); 13 | }; 14 | 15 | /** 16 | * 判断是否为字符串 17 | */ 18 | export const isString = (value: unknown): value is string => { 19 | return typeof value === 'string'; 20 | }; 21 | -------------------------------------------------------------------------------- /apps/docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@mylib/typescript-config/vite.json", 3 | "compilerOptions": { 4 | "skipLibCheck": true, 5 | "types": ["vite/client", "@mylib/ui/global.d.ts"], 6 | 7 | /* Bundler mode */ 8 | "moduleResolution": "bundler", 9 | "allowImportingTsExtensions": true, 10 | "isolatedModules": true, 11 | "jsx": "preserve", 12 | 13 | /* Linting */ 14 | "strict": true, 15 | "noFallthroughCasesInSwitch": true 16 | }, 17 | "include": ["**/*.ts", "**/*.d.ts", "**/*.tsx", "**/*.vue"] 18 | } 19 | -------------------------------------------------------------------------------- /apps/docs/examples/ui/button/basic.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 15 | 16 | 22 | -------------------------------------------------------------------------------- /packages/lint-configs/prettier-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mylib/prettier-config", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "main": "./index.mjs", 7 | "module": "./index.mjs", 8 | "exports": { 9 | ".": { 10 | "import": "./index.mjs", 11 | "default": "./index.mjs" 12 | } 13 | }, 14 | "scripts": { 15 | "clean": "rimraf .turbo node_modules" 16 | }, 17 | "devDependencies": { 18 | "prettier": "catalog:lint" 19 | }, 20 | "peerDependencies": { 21 | "prettier": "catalog:lint" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /apps/docs/examples/hooks/useCounter/basic.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 25 | -------------------------------------------------------------------------------- /playground/src/views/Utils/All.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 25 | -------------------------------------------------------------------------------- /apps/docs/zh/packages/ui/dialog.md: -------------------------------------------------------------------------------- 1 | # Dialog 弹窗 2 | 3 | 基础的弹窗组件。 4 | 5 | ## 基础用法 6 | 7 | 8 | 9 | ## API 10 | 11 | ### Props 12 | 13 | | 属性 | 说明 | 类型 | 默认值 | 14 | | ---- | ------------------ | ------- | ------ | 15 | | open | 控制弹窗的显示状态 | boolean | false | 16 | 17 | ### Events 18 | 19 | | 事件名 | 说明 | 回调参数 | 20 | | ------ | ---------------- | -------- | 21 | | close | 当弹窗关闭时触发 | - | 22 | 23 | ## 样式 24 | 25 | 弹窗可以使用以下类名进行样式定制: 26 | 27 | - `.v-dialog`: 主弹窗容器。 28 | - `.v-dialog__overlay`: 背景遮罩。 29 | - `.v-dialog__content`: 弹窗内容区域。 30 | -------------------------------------------------------------------------------- /my-lib.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "name": "@mylib/docs", 5 | "path": "apps/docs", 6 | }, 7 | { 8 | "name": "@mylib/playground", 9 | "path": "playground", 10 | }, 11 | { 12 | "name": "@mylib/utils", 13 | "path": "packages/utils", 14 | }, 15 | { 16 | "name": "@mylib/ui", 17 | "path": "packages/ui", 18 | }, 19 | { 20 | "name": "@mylib/hooks", 21 | "path": "packages/hooks", 22 | }, 23 | { 24 | "name": "@mylib/directives", 25 | "path": "packages/directives", 26 | }, 27 | ], 28 | } 29 | -------------------------------------------------------------------------------- /packages/ui/src/_utils/with-install.ts: -------------------------------------------------------------------------------- 1 | import type { App, Plugin } from 'vue'; 2 | 3 | export const withInstall = (comp: T) => { 4 | const c = comp as any; 5 | c.install = function (app: App) { 6 | app.component(c.displayName || c.name, comp as T & Plugin); 7 | }; 8 | 9 | return comp as T & Plugin; 10 | }; 11 | 12 | /** 13 | 使用示例: 14 | 15 | export default withInstall< 16 | typeof Cascader & { 17 | SHOW_PARENT: typeof SHOW_PARENT; 18 | SHOW_CHILD: typeof SHOW_CHILD; 19 | } 20 | >( 21 | Object.assign(Cascader, { 22 | SHOW_CHILD, 23 | SHOW_PARENT, 24 | } as any), 25 | ); 26 | */ 27 | -------------------------------------------------------------------------------- /packages/ui/src/types/global.d.ts: -------------------------------------------------------------------------------- 1 | // // For this project development 2 | // import 'vue'; 3 | 4 | /** 5 | * 用作给全局引入的UI组件类型提示: 6 | * tsconfig.json 需要添加配置:"types": ["@mylib/ui/global.d.ts"] 7 | * 8 | * 或者 9 | * 一个全局的类型声明文件.d.ts写入:/// 10 | * 类似于:/// 具体可参考playground下的env.d.ts 11 | */ 12 | declare module 'vue' { 13 | // GlobalComponents for Volar 14 | export interface GlobalComponents { 15 | VButton: (typeof import('@mylib/ui'))['VButton']; 16 | VDialog: (typeof import('@mylib/ui'))['VDialog']; 17 | } 18 | } 19 | 20 | export {}; 21 | -------------------------------------------------------------------------------- /playground/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import vue from '@vitejs/plugin-vue'; 3 | import { resolve } from 'node:path'; 4 | 5 | export default defineConfig({ 6 | plugins: [vue()], 7 | resolve: { 8 | alias: { 9 | '@': resolve(import.meta.dirname, './src'), 10 | // 使用本地UI库,ui组件修改实时变化,提高调试效率。 11 | '~/@mylib/ui': resolve(import.meta.dirname, '../packages/ui/src/index.ts'), 12 | '~': resolve(import.meta.dirname, '../packages/ui/src'), 13 | }, 14 | }, 15 | server: { 16 | port: 4444, 17 | }, 18 | optimizeDeps: { 19 | include: ['vue', 'ant-design-vue'], 20 | }, 21 | }); 22 | -------------------------------------------------------------------------------- /packages/lint-configs/commitlint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mylib/commitlint-config", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "main": "./index.mjs", 7 | "module": "./index.mjs", 8 | "exports": { 9 | ".": { 10 | "import": "./index.mjs", 11 | "default": "./index.mjs" 12 | } 13 | }, 14 | "scripts": { 15 | "clean": "rimraf .turbo node_modules" 16 | }, 17 | "devDependencies": { 18 | "@commitlint/cli": "catalog:lint", 19 | "@commitlint/config-conventional": "catalog:lint" 20 | }, 21 | "peerDependencies": { 22 | "@commitlint/cli": "catalog:lint" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.lintstagedrc.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | '*.{js,jsx,ts,tsx}': ['prettier --cache --ignore-unknown --write', 'eslint --cache --fix'], 3 | '*.{scss,less,styl,html,vue,css}': [ 4 | 'prettier --cache --ignore-unknown --write', 5 | 'stylelint --fix --allow-empty-input --cache', 6 | ], 7 | '*.md': ['prettier --cache --ignore-unknown --write'], 8 | '*.vue': [ 9 | 'prettier --write', 10 | 'eslint --cache --fix', 11 | 'stylelint --fix --allow-empty-input --cache', 12 | ], 13 | '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': [ 14 | 'prettier --cache --write--parser json', 15 | ], 16 | 'package.json': ['prettier --cache --write'], 17 | }; 18 | -------------------------------------------------------------------------------- /packages/ui/src/components/Dialog/Dialog.scss: -------------------------------------------------------------------------------- 1 | .v-dialog { 2 | position: fixed; 3 | top: 0; 4 | left: 0; 5 | z-index: 1000; 6 | display: flex; 7 | align-items: center; 8 | justify-content: center; 9 | width: 100%; 10 | height: 100%; 11 | background-color: rgb(0 0 0 / 50%); 12 | 13 | &__overlay { 14 | position: absolute; 15 | top: 0; 16 | left: 0; 17 | width: 100%; 18 | height: 100%; 19 | background-color: transparent; 20 | } 21 | 22 | &__content { 23 | position: relative; 24 | z-index: 1001; 25 | padding: 20px; 26 | background-color: #fff; 27 | border-radius: 8px; 28 | box-shadow: 0 2px 10px rgb(0 0 0 / 10%); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /apps/docs/.vitepress/utils/useGlobalComp.ts: -------------------------------------------------------------------------------- 1 | import type { App, Component } from 'vue'; 2 | // 如果报:“找不到模块“@mylib/ui”或其相应的类型声明”的错误,记得先build打包一下 3 | import * as UI from '@mylib/ui'; 4 | 5 | export function useGlobalComp(app: App) { 6 | // 注册 UI 组件 7 | Object.entries(UI).forEach(([key, component]) => { 8 | if (key !== 'default' && isVueComponent(component)) { 9 | app.component(key, component); 10 | } 11 | }); 12 | 13 | // 注册 其他 组件 14 | // app.component('Demo', Demo); 15 | } 16 | 17 | function isVueComponent(component: any): component is Component { 18 | return ( 19 | typeof component === 'object' && (component.install || component.render || component.setup) 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // 继承 Vite 配置 3 | "extends": "@mylib/typescript-config/vite.json", 4 | "compilerOptions": { 5 | // 移除 .d.ts.map 文件映射 6 | "declarationMap": false, 7 | // JSX 保留模式 8 | "jsx": "preserve", 9 | // 包含的库文件 10 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 11 | // 使用 Bundler 模块解析策略 12 | "moduleResolution": "bundler", 13 | // 跳过对声明文件的类型检查 14 | "skipLibCheck": true, 15 | // 基础路径 16 | "baseUrl": ".", 17 | // 路径映射 18 | "paths": { 19 | "~/*": ["src/*"] 20 | } 21 | }, 22 | // 包含的文件路径 23 | "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"], 24 | // 排除的文件路径 25 | "exclude": ["src/types/global.d.ts"] 26 | } 27 | -------------------------------------------------------------------------------- /apps/docs/zh/packages/ui/button.md: -------------------------------------------------------------------------------- 1 | # Button 按钮 2 | 3 | 基础的按钮组件。 4 | 5 | ## 基础用法 6 | 7 | 8 | 9 | ## API 10 | 11 | ### Props 12 | 13 | | 属性 | 说明 | 类型 | 默认值 | 14 | | -------- | -------- | --------------------------------------------------------- | -------- | 15 | | type | 按钮类型 | 'primary' \| 'success' \| 'warning' \| 'danger' \| 'info' | '' | 16 | | size | 按钮大小 | 'small' \| 'medium' \| 'large' | 'medium' | 17 | | disabled | 是否禁用 | boolean | false | 18 | | round | 是否圆角 | boolean | false | 19 | -------------------------------------------------------------------------------- /playground/src/views/Ui/Button.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 22 | -------------------------------------------------------------------------------- /packages/lint-configs/eslint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mylib/eslint-config", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "main": "./index.mjs", 7 | "module": "./index.mjs", 8 | "exports": { 9 | ".": { 10 | "import": "./index.mjs", 11 | "default": "./index.mjs" 12 | } 13 | }, 14 | "scripts": { 15 | "clean": "rimraf .turbo node_modules" 16 | }, 17 | "devDependencies": { 18 | "@eslint/js": "catalog:lint", 19 | "eslint-plugin-vue": "catalog:lint", 20 | "typescript-eslint": "catalog:lint", 21 | "vue-eslint-parser": "catalog:lint", 22 | "globals": "catalog:lint" 23 | }, 24 | "peerDependencies": { 25 | "eslint": "catalog:lint" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/ui/src/components/Dialog/Dialog.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 28 | 29 | 32 | -------------------------------------------------------------------------------- /packages/ui/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config'; 2 | import vue from '@vitejs/plugin-vue'; 3 | import { dirname, resolve } from 'node:path'; 4 | import { fileURLToPath } from 'node:url'; 5 | 6 | const __filename = fileURLToPath(import.meta.url); 7 | const __dirname = dirname(__filename); 8 | 9 | export default defineConfig({ 10 | plugins: [vue()], 11 | test: { 12 | environment: 'happy-dom', 13 | globals: true, 14 | setupFiles: ['./src/__tests__/setup.ts'], 15 | coverage: { 16 | provider: 'v8', 17 | reporter: ['text', 'json', 'html'], 18 | exclude: ['node_modules/', 'src/__tests__/', '**/*.d.ts', 'dist/'], 19 | }, 20 | }, 21 | resolve: { 22 | alias: { 23 | '~': resolve(__dirname, 'src'), 24 | }, 25 | }, 26 | }); 27 | -------------------------------------------------------------------------------- /playground/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@mylib/typescript-config/vite.json", 3 | "compilerOptions": { 4 | "skipLibCheck": true, 5 | // "types": ["vite/client", "@mylib/ui/global.d.ts"], // 已在env.d.ts引入了 6 | 7 | /* Bundler mode */ 8 | "moduleResolution": "bundler", 9 | "allowImportingTsExtensions": true, 10 | "isolatedModules": true, 11 | "jsx": "preserve", 12 | 13 | /* Linting */ 14 | "strict": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "baseUrl": ".", 17 | "paths": { 18 | "@/*": ["src/*"], 19 | "~/*": ["../packages/ui/src/*"], 20 | "~/@mylib/ui": ["../packages/ui/src/index.ts"] 21 | } 22 | }, 23 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"] 24 | // "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /packages/lint-configs/commitlint-config/index.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import("@commitlint/types").UserConfig} */ 2 | export default { 3 | extends: ['@commitlint/config-conventional'], // 继承自 commitlint 的标准配置 4 | rules: { 5 | 'type-enum': [ 6 | 2, // 规则级别:错误 7 | 'always', // 规则应用条件:始终检查 8 | [ 9 | 'feat', // 新增功能 10 | 'fix', // bug 修复 11 | 'docs', // 文档变更 12 | 'style', // 不影响程序逻辑的代码修改(修改空白字符,格式缩进,补全缺失的分号等,没有改变代码逻辑) 13 | 'refactor', // 重构(即不是新增功能,也不是修改 bug 的代码变动) 14 | 'perf', // 性能, 体验优化 15 | 'test', // 新增测试用例或是更新现有测试 16 | 'build', // 主要目的是修改项目构建系统(例如 gulp,webpack,rollup 的配置等)的提交) 17 | 'ci', // 更改持续集成文件和脚本 18 | 'chore', // 不属于以上类型的其他类型(比如构建流程, 依赖管理) 19 | 'revert', // 撤销之前的提交 20 | 'types', // 类型相关 21 | ], 22 | ], 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /packages/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mylib/utils", 3 | "description": "@mylib utils library", 4 | "version": "1.0.0", 5 | "main": "dist/cjs/index.js", 6 | "module": "dist/esm/index.mjs", 7 | "types": "dist/types/index.d.ts", 8 | "files": [ 9 | "dist" 10 | ], 11 | "publishConfig": { 12 | "access": "public", 13 | "registry": "https://registry.npmjs.org/" 14 | }, 15 | "scripts": { 16 | "build": "rimraf dist && rollup -c rollup.config.mjs", 17 | "clean": "rimraf .turbo node_modules dist", 18 | "publish": "pnpm publish" 19 | }, 20 | "devDependencies": { 21 | "@mylib/typescript-config": "workspace:*", 22 | "@rollup/plugin-json": "catalog:build", 23 | "rollup": "catalog:build", 24 | "rollup-plugin-dts": "catalog:build", 25 | "rollup-plugin-esbuild": "catalog:build" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | // Vue 3 的语言支持 4 | "Vue.volar", 5 | // 将 ESLint JavaScript 集成到 VS Code 中。 6 | "dbaeumer.vscode-eslint", 7 | // Visual Studio Code 的官方 Stylelint 扩展 8 | "stylelint.vscode-stylelint", 9 | // 使用 Prettier 的代码格式化程序 10 | "esbenp.prettier-vscode", 11 | // 支持 dotenv 文件语法 12 | "mikestead.dotenv", 13 | // iconify 图标插件 14 | "antfu.iconify", 15 | // Markdown 格式化支持 16 | "yzhang.markdown-all-in-one", 17 | // 统一编辑器代码风格 18 | "editorconfig.editorconfig", 19 | // 显示 PNPM catalogs 版本信息 20 | "antfu.pnpm-catalog-lens", 21 | // 单词拼写检查 22 | "streetsidesoftware.code-spell-checker", 23 | // 多行字符串高亮 24 | "tobermory.es6-string-html" 25 | ], 26 | "unwantedRecommendations": [ 27 | // 和 volar 冲突 28 | "octref.vetur" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 (2024-12-07) 2 | 3 | ### Features 新增 4 | 5 | - **@mylib/ui:** [UI 组件库 ui component library](./packages/ui/CHANGELOG.md) 6 | - **@mylib/utils:** [工具库 utility library](./packages/utils/CHANGELOG.md) 7 | - **@mylib/hooks:** [Hooks 库 hooks library](./packages/hooks/CHANGELOG.md) 8 | - **@mylib/directives:** [自定义指令库 directives library](./packages/directives/CHANGELOG.md) 9 | 10 | - **@mylib/typescript-config:** TypeScript 配置 11 | - **@mylib/prettier-config:** Prettier 配置 12 | - **@mylib/stylelint-config:** Stylelint 配置 13 | - **@mylib/eslint-config:** ESLint 配置 14 | - **@mylib/commitlint-config:** Commitlint 配置 15 | - **@mylib/playground:** 演练场 16 | - **@mylib/docs:** 文档 17 | - **@mylib/build:** Gulp 打包配置 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /apps/docs/en/packages/ui/dialog.md: -------------------------------------------------------------------------------- 1 | # Dialog 2 | 3 | Basic dialog component. 4 | 5 | ## Basic Usage 6 | 7 | 8 | 9 | ## API 10 | 11 | ### Props 12 | 13 | | Property | Description | Type | Default | 14 | | -------- | ------------------------------------- | ------- | ------- | 15 | | open | Controls the visibility of the dialog | boolean | false | 16 | 17 | ## Events 18 | 19 | | Event Name | Description | Arguments | 20 | | ---------- | ----------------------------------- | --------- | 21 | | close | Triggered when the dialog is closed | - | 22 | 23 | ## Styles 24 | 25 | The dialog can be styled using the following class names: 26 | 27 | - `.v-dialog`: Main dialog container. 28 | - `.v-dialog__overlay`: Background overlay. 29 | - `.v-dialog__content`: Dialog content area. 30 | -------------------------------------------------------------------------------- /packages/ui/src/__tests__/setup.ts: -------------------------------------------------------------------------------- 1 | import { vi } from 'vitest'; 2 | 3 | // Mock ResizeObserver 4 | globalThis.ResizeObserver = vi.fn().mockImplementation(() => ({ 5 | observe: vi.fn(), 6 | unobserve: vi.fn(), 7 | disconnect: vi.fn(), 8 | })); 9 | 10 | // Mock IntersectionObserver 11 | globalThis.IntersectionObserver = vi.fn().mockImplementation(() => ({ 12 | observe: vi.fn(), 13 | unobserve: vi.fn(), 14 | disconnect: vi.fn(), 15 | })); 16 | 17 | // Mock window.matchMedia 18 | Object.defineProperty(window, 'matchMedia', { 19 | writable: true, 20 | value: vi.fn().mockImplementation((query) => ({ 21 | matches: false, 22 | media: query, 23 | onchange: null, 24 | addListener: vi.fn(), // deprecated 25 | removeListener: vi.fn(), // deprecated 26 | addEventListener: vi.fn(), 27 | removeEventListener: vi.fn(), 28 | dispatchEvent: vi.fn(), 29 | })), 30 | }); 31 | -------------------------------------------------------------------------------- /apps/docs/en/packages/ui/button.md: -------------------------------------------------------------------------------- 1 | # Button 2 | 3 | Basic button component. 4 | 5 | ## Basic Usage 6 | 7 | 8 | 9 | ## API 10 | 11 | ### Props 12 | 13 | | Property | Description | Type | Default | 14 | | -------- | ------------------------------ | --------------------------------------------------------- | -------- | 15 | | type | Button type | 'primary' \| 'success' \| 'warning' \| 'danger' \| 'info' | '' | 16 | | size | Button size | 'small' \| 'medium' \| 'large' | 'medium' | 17 | | disabled | Whether to disable the button | boolean | false | 18 | | round | Whether to use rounded corners | boolean | false | 19 | -------------------------------------------------------------------------------- /playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mylib/playground", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "clean": "rimraf .turbo node_modules dist", 9 | "test": "vitest" 10 | }, 11 | "dependencies": { 12 | "@ant-design/icons-vue": "catalog:frontend", 13 | "@mylib/directives": "workspace:*", 14 | "@mylib/hooks": "workspace:*", 15 | "@mylib/typescript-config": "workspace:*", 16 | "@mylib/ui": "workspace:*", 17 | "@mylib/utils": "workspace:*", 18 | "ant-design-vue": "catalog:frontend", 19 | "vue": "catalog:frontend", 20 | "vue-router": "catalog:frontend" 21 | }, 22 | "devDependencies": { 23 | "@vitejs/plugin-vue": "catalog:build", 24 | "sass": "catalog:dev", 25 | "typescript": "catalog:types", 26 | "vite": "catalog:build", 27 | "vitest": "catalog:test" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/hooks/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'rollup'; 2 | import esbuild from 'rollup-plugin-esbuild'; 3 | import json from '@rollup/plugin-json'; 4 | import dts from 'rollup-plugin-dts'; 5 | 6 | export default defineConfig([ 7 | { 8 | // 输入文件 9 | input: 'src/index.ts', 10 | // 输出配置 11 | output: [ 12 | { 13 | // CommonJS 格式输出 14 | file: 'dist/cjs/index.js', 15 | format: 'cjs', 16 | }, 17 | { 18 | // ES 模块格式输出 19 | file: 'dist/esm/index.mjs', 20 | format: 'es', 21 | }, 22 | ], 23 | plugins: [ 24 | esbuild(), 25 | json({ 26 | preferConst: true, 27 | }), 28 | ], 29 | external: ['vue'], 30 | }, 31 | { 32 | // 输出类型文件 33 | input: 'src/index.ts', 34 | output: { 35 | file: 'dist/types/index.d.ts', 36 | format: 'es', 37 | }, 38 | plugins: [dts()], 39 | }, 40 | ]); 41 | -------------------------------------------------------------------------------- /apps/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mylib/docs", 3 | "version": "1.0.0", 4 | "description": "组件库模板说明文档", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "vitepress dev", 8 | "build": "rimraf .vitepress/dist && vitepress build", 9 | "preview": "vitepress preview", 10 | "clean": "rimraf .turbo node_modules .vitepress/dist .vitepress/cache .vitepress/.temp" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "MIT", 15 | "dependencies": { 16 | "@mylib/directives": "workspace:*", 17 | "@mylib/hooks": "workspace:*", 18 | "@mylib/typescript-config": "workspace:*", 19 | "@mylib/ui": "workspace:*", 20 | "@mylib/utils": "workspace:*", 21 | "vue": "catalog:frontend" 22 | }, 23 | "devDependencies": { 24 | "sass": "catalog:dev", 25 | "typescript": "catalog:types", 26 | "vitepress": "catalog:build", 27 | "vitepress-demo-plugin": "catalog:build" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/hooks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mylib/hooks", 3 | "version": "1.0.0", 4 | "description": "@mylib hooks library", 5 | "main": "dist/cjs/index.js", 6 | "module": "dist/esm/index.mjs", 7 | "types": "dist/types/index.d.ts", 8 | "files": [ 9 | "dist" 10 | ], 11 | "publishConfig": { 12 | "access": "public", 13 | "registry": "https://registry.npmjs.org/" 14 | }, 15 | "scripts": { 16 | "build": "rimraf dist && rollup -c rollup.config.mjs", 17 | "clean": "rimraf .turbo node_modules dist", 18 | "publish": "pnpm publish" 19 | }, 20 | "devDependencies": { 21 | "@mylib/typescript-config": "workspace:*", 22 | "@rollup/plugin-json": "catalog:build", 23 | "rollup": "catalog:build", 24 | "rollup-plugin-dts": "catalog:build", 25 | "rollup-plugin-esbuild": "catalog:build", 26 | "vue": "catalog:frontend" 27 | }, 28 | "peerDependencies": { 29 | "vue": "catalog:frontend" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | // Turbo 配置文件的 JSON Schema 3 | "$schema": "https://turbo.build/schema.json", 4 | "tasks": { 5 | // 构建任务 6 | "build": { 7 | // 依赖其他包的 build 任务完成 8 | "dependsOn": ["^build"], 9 | // 构建任务的输入文件 10 | "inputs": ["$TURBO_DEFAULT$", ".env*"], 11 | // 构建任务的输出目录 12 | "outputs": ["dist/**"] 13 | }, 14 | // lint 检查任务 15 | "lint": {}, 16 | // 清理任务 17 | "clean": {}, 18 | // 开发任务 19 | "dev": { 20 | // 不缓存开发任务 21 | "cache": false, 22 | // 持久运行的任务 23 | "persistent": true 24 | }, 25 | // 测试任务 26 | "test": { 27 | "inputs": ["src/**/*.{ts,tsx,vue}", "**/*.spec.ts", "**/*.test.ts"] 28 | }, 29 | // 测试覆盖率任务 30 | "test:coverage": { 31 | "dependsOn": ["test"], 32 | "outputs": ["coverage/**"] 33 | }, 34 | // 发包 35 | "publish": { 36 | // 任务开始运行前需要完成的任务列表 37 | "dependsOn": ["build"] // 发包前先打包 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/lint-configs/stylelint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mylib/stylelint-config", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "main": "./index.mjs", 7 | "module": "./index.mjs", 8 | "exports": { 9 | ".": { 10 | "import": "./index.mjs", 11 | "default": "./index.mjs" 12 | } 13 | }, 14 | "scripts": { 15 | "clean": "rimraf .turbo node_modules" 16 | }, 17 | "devDependencies": { 18 | "postcss": "catalog:lint", 19 | "postcss-html": "catalog:lint", 20 | "postcss-scss": "catalog:lint", 21 | "stylelint": "catalog:lint", 22 | "stylelint-config-recess-order": "catalog:lint", 23 | "stylelint-config-recommended-vue": "catalog:lint", 24 | "stylelint-config-standard": "catalog:lint", 25 | "stylelint-config-standard-scss": "catalog:lint", 26 | "stylelint-scss": "catalog:lint", 27 | "stylelint-order": "catalog:lint" 28 | }, 29 | "peerDependencies": { 30 | "stylelint": "catalog:lint" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/directives/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mylib/directives", 3 | "version": "1.0.0", 4 | "description": "@mylib directives library", 5 | "main": "dist/cjs/index.js", 6 | "module": "dist/esm/index.mjs", 7 | "types": "dist/types/index.d.ts", 8 | "files": [ 9 | "dist" 10 | ], 11 | "publishConfig": { 12 | "access": "public", 13 | "registry": "https://registry.npmjs.org/" 14 | }, 15 | "scripts": { 16 | "build": "rimraf dist && rollup -c rollup.config.mjs", 17 | "clean": "rimraf .turbo node_modules dist", 18 | "publish": "pnpm publish" 19 | }, 20 | "devDependencies": { 21 | "@mylib/typescript-config": "workspace:*", 22 | "@rollup/plugin-json": "catalog:build", 23 | "@rollup/plugin-terser": "catalog:build", 24 | "rollup": "catalog:build", 25 | "rollup-plugin-dts": "catalog:build", 26 | "rollup-plugin-esbuild": "catalog:build", 27 | "vue": "catalog:frontend" 28 | }, 29 | "peerDependencies": { 30 | "vue": "catalog:frontend" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /apps/docs/zh/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | hero: 4 | name: mylib-template 5 | text: 组件库和工具集模板 6 | tagline: 简单、强大、高效的 Vue3 组件库和工具集模板,帮助快速搭建属于自己/企业级的组件库。 7 | image: 8 | src: /logo.png 9 | alt: mylib-template 10 | actions: 11 | - theme: brand 12 | text: 开始使用 13 | link: /guide/ 14 | - theme: alt 15 | text: 在 GitHub 上查看 16 | link: https://github.com/huangmingfu/vue3-turbo-component-lib-template 17 | 18 | features: 19 | - icon: 🌈 20 | title: UI 组件 21 | details: 提供高质量的 Vue3 组件,支持按需引入,完整类型导出、类型推导等特性。 22 | - icon: 🔧 23 | title: 工具函数 24 | details: 常用工具函数集合,提高开发效率,减少重复代码。 25 | - icon: 🎯 26 | title: Hooks 27 | details: 可复用的组合式函数,让逻辑复用更简单。 28 | - icon: ⚡️ 29 | title: 开发提效 30 | details: 一套组件库完整的开发环境,旨在让开发者能够专注于组件的开发,而无需担心底层配置的复杂性。 31 | - icon: 🖖 32 | title: 解放双手 33 | details: 完整的打包构建流程,减少手动操作,专注于开发,帮你生成需要的产物。 34 | - icon: 🧮 35 | title: 完整规范 36 | details: 涵盖了 ESLint、Prettier、Stylelint、Commitlint + Husky + Lint-Staged 和 TypeScript 的项目规范配置。 37 | --- 38 | -------------------------------------------------------------------------------- /playground/src/layouts/TabsView.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 38 | -------------------------------------------------------------------------------- /apps/docs/.vitepress/config/shared.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress'; 2 | import { vitepressDemoPlugin } from 'vitepress-demo-plugin'; 3 | import path from 'node:path'; 4 | import { fileURLToPath } from 'node:url'; // 新增导入 5 | 6 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); 7 | 8 | export const shared = defineConfig({ 9 | // 设置基础路径,用于GitHub Pages部署 10 | base: '/vue3-turbo-component-lib-template/', 11 | // 启用最后更新时间 12 | lastUpdated: true, 13 | // 生成干净的 URL(去掉.html后缀) 14 | cleanUrls: true, 15 | // 将元数据拆分为单独的 chunk 16 | metaChunk: true, 17 | // URL重写规则,将zh/开头的路径重写为根路径 18 | rewrites: { 19 | 'zh/:rest*': ':rest*', 20 | }, 21 | // 配置HTML头部标签 22 | head: [['link', { rel: 'icon', href: '/vue3-turbo-component-lib-template/favicon.ico' }]], 23 | // Markdown配置 24 | markdown: { 25 | // 配置Markdown解析器 26 | config(md) { 27 | // 使用vitepress-demo-plugin插件,用于展示示例代码 28 | md.use(vitepressDemoPlugin, { 29 | demoDir: path.resolve(__dirname, '../../examples'), 30 | }); 31 | }, 32 | }, 33 | }); 34 | -------------------------------------------------------------------------------- /packages/ui/src/components/Button/Button.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 41 | 42 | 43 | 46 | -------------------------------------------------------------------------------- /playground/src/views/Utils/__test__/array.spec.ts: -------------------------------------------------------------------------------- 1 | import { chunk, unique } from '@mylib/utils'; 2 | import { describe, expect, it } from 'vitest'; 3 | 4 | describe('array工具', () => { 5 | describe('unique', () => { 6 | it('应该从数组中移除重复值', () => { 7 | const input = [1, 2, 2, 3, 4, 4, 5]; 8 | const result = unique(input); 9 | expect(result).toEqual([1, 2, 3, 4, 5]); 10 | }); 11 | 12 | it('当输入为空时应该返回一个空数组', () => { 13 | const result = unique([]); 14 | expect(result).toEqual([]); 15 | }); 16 | }); 17 | 18 | describe('chunk', () => { 19 | it('应该将数组拆分为指定大小的块', () => { 20 | const input = [1, 2, 3, 4, 5]; 21 | const result = chunk(input, 2); 22 | expect(result).toEqual([[1, 2], [3, 4], [5]]); 23 | }); 24 | 25 | it('当输入为空时应该返回一个空数组', () => { 26 | const result = chunk([], 2); 27 | expect(result).toEqual([]); 28 | }); 29 | 30 | it('应该处理块大小大于数组长度的情况', () => { 31 | const input = [1, 2]; 32 | const result = chunk(input, 5); 33 | expect(result).toEqual([[1, 2]]); 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /packages/ui/src/__tests__/performance.bench.ts: -------------------------------------------------------------------------------- 1 | import { bench, describe } from 'vitest'; 2 | import { mount } from '@vue/test-utils'; 3 | import Button from '../components/Button/Button.vue'; 4 | import type { ButtonType } from '../components/Button'; 5 | 6 | describe('Button Performance', () => { 7 | bench('Button mount', () => { 8 | mount(Button, { 9 | slots: { 10 | default: 'Test Button', 11 | }, 12 | }); 13 | }); 14 | 15 | bench('Button with props mount', () => { 16 | mount(Button, { 17 | props: { 18 | type: 'primary', 19 | size: 'large', 20 | disabled: false, 21 | round: true, 22 | }, 23 | slots: { 24 | default: 'Test Button', 25 | }, 26 | }); 27 | }); 28 | 29 | bench('Multiple Button mounts', () => { 30 | for (let i = 0; i < 100; i++) { 31 | mount(Button, { 32 | props: { 33 | type: i % 2 === 0 ? 'primary' : ('default' as ButtonType), 34 | }, 35 | slots: { 36 | default: `Button ${i}`, 37 | }, 38 | }); 39 | } 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /packages/utils/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url'; 2 | import path from 'node:path'; 3 | import { defineConfig } from 'rollup'; 4 | import esbuild from 'rollup-plugin-esbuild'; 5 | import json from '@rollup/plugin-json'; 6 | import dts from 'rollup-plugin-dts'; 7 | 8 | const __dirname = fileURLToPath(new URL('.', import.meta.url)); 9 | 10 | export default defineConfig([ 11 | { 12 | // 输入文件 13 | input: 'src/index.ts', 14 | // 输出配置 15 | output: [ 16 | { 17 | // CommonJS 格式输出 18 | file: 'dist/cjs/index.js', 19 | format: 'cjs', 20 | }, 21 | { 22 | // ES 模块格式输出 23 | file: 'dist/esm/index.mjs', 24 | format: 'es', 25 | }, 26 | ], 27 | plugins: [ 28 | esbuild({ 29 | tsconfig: path.resolve(__dirname, './tsconfig.json'), 30 | }), 31 | json({ 32 | preferConst: true, 33 | }), 34 | ], 35 | }, 36 | { 37 | // 输出类型文件 38 | input: 'src/index.ts', 39 | output: { 40 | file: 'dist/types/index.d.ts', 41 | format: 'es', 42 | }, 43 | plugins: [dts()], 44 | }, 45 | ]); 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 友人A 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/lint-configs/typescript-config/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "compilerOptions": { 4 | "composite": false, 5 | "target": "ESNext", 6 | 7 | "moduleDetection": "force", 8 | "experimentalDecorators": true, 9 | 10 | "baseUrl": ".", 11 | "module": "ESNext", 12 | 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | 16 | "strict": true, 17 | "strictNullChecks": true, 18 | "noFallthroughCasesInSwitch": true, 19 | "noImplicitAny": true, 20 | "noImplicitOverride": true, 21 | "noImplicitThis": true, 22 | "noUncheckedIndexedAccess": true, 23 | "noUnusedLocals": true, 24 | "noUnusedParameters": true, 25 | 26 | "inlineSources": false, 27 | "noEmit": true, 28 | "removeComments": true, 29 | "sourceMap": false, 30 | "allowSyntheticDefaultImports": true, 31 | "esModuleInterop": true, 32 | "forceConsistentCasingInFileNames": true, 33 | "isolatedModules": true, 34 | "verbatimModuleSyntax": true, 35 | "skipLibCheck": true, 36 | "preserveWatchOutput": true 37 | }, 38 | "exclude": ["**/node_modules/**", "**/dist/**", "**/lib/**"] 39 | } 40 | -------------------------------------------------------------------------------- /scripts/rename-package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 批量替换包名脚本 4 | # 使用:pnpm run rename-pkg old-name new-name 5 | # 示例:pnpm rename-pkg "@mylib" "@vue3-lib" 6 | 7 | # 检查参数 8 | if [ "$#" -ne 2 ]; then 9 | echo "Usage: $0 old-name new-name" 10 | echo "Example: $0 @mylib @vue3-lib" 11 | exit 1 12 | fi 13 | 14 | OLD_NAME=$1 15 | NEW_NAME=$2 16 | 17 | # 转义特殊字符 18 | OLD_NAME_ESCAPED=$(echo $OLD_NAME | sed 's/\//\\\//g' | sed 's/@/\\@/g') 19 | NEW_NAME_ESCAPED=$(echo $NEW_NAME | sed 's/\//\\\//g' | sed 's/@/\\@/g') 20 | 21 | # 在项目根目录下执行 22 | echo "Replacing $OLD_NAME with $NEW_NAME in all files..." 23 | 24 | # 查找所有可能包含包名的文件并替换 25 | find . -type f \ 26 | -not -path "*/node_modules/*" \ 27 | -not -path "*/dist/*" \ 28 | -not -path "*/.git/*" \ 29 | -not -path "*/coverage/*" \ 30 | -not -path "*/scripts/*" \ 31 | -not -path "*/temp/*" \ 32 | -not -path "*/tmp/*" \ 33 | -not -path "*/.turbo/*" \ 34 | -not -path "*/.cache/*" \ 35 | \( -name "*.json" -o -name "*.ts" -o -name "*.js" -o -name "*.vue" -o -name "*.md" -o -name "*.mjs" \) \ 36 | -exec sed -i'' "s/$OLD_NAME_ESCAPED/$NEW_NAME_ESCAPED/g" {} + 37 | 38 | echo "Done! Please review the changes and run 'pnpm install' to update lock file" 39 | -------------------------------------------------------------------------------- /playground/src/views/Utils/__test__/string.spec.ts: -------------------------------------------------------------------------------- 1 | import { camelToKebab, capitalize, isString } from '@mylib/utils'; 2 | import { describe, expect, it } from 'vitest'; 3 | 4 | describe('string工具', () => { 5 | describe('capitalize', () => { 6 | it('应该将字符串的首字母转换为大写', () => { 7 | const input = 'hello'; 8 | const result = capitalize(input); 9 | expect(result).toEqual('Hello'); 10 | }); 11 | 12 | it('当输入为空字符串时应该返回一个空字符串', () => { 13 | const result = capitalize(''); 14 | expect(result).toEqual(''); 15 | }); 16 | }); 17 | 18 | describe('camelToKebab', () => { 19 | it('应该将驼峰命名转换为短横线命名', () => { 20 | const input = 'camelCaseString'; 21 | const result = camelToKebab(input); 22 | expect(result).toEqual('camel-case-string'); 23 | }); 24 | 25 | it('当输入为空字符串时应该返回一个空字符串', () => { 26 | const result = camelToKebab(''); 27 | expect(result).toEqual(''); 28 | }); 29 | }); 30 | 31 | describe('isString', () => { 32 | it('应该判断字符串为true', () => { 33 | const result = isString('test'); 34 | expect(result).toBe(true); 35 | }); 36 | 37 | it('应该判断非字符串为false', () => { 38 | const result = isString(123); 39 | expect(result).toBe(false); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/directives/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'rollup'; 2 | import esbuild from 'rollup-plugin-esbuild'; 3 | import json from '@rollup/plugin-json'; 4 | import dts from 'rollup-plugin-dts'; 5 | // import terser from '@rollup/plugin-terser'; 6 | 7 | export default defineConfig([ 8 | { 9 | // 输入文件 10 | input: 'src/index.ts', 11 | // 输出配置 12 | output: [ 13 | { 14 | // CommonJS 格式输出 15 | file: 'dist/cjs/index.js', 16 | format: 'cjs', 17 | }, 18 | { 19 | // ES 模块格式输出 20 | file: 'dist/esm/index.mjs', 21 | format: 'es', 22 | }, 23 | // 打包出压缩后的文件 24 | // { 25 | // file: `dist/index.min.js`, 26 | // format: 'es', 27 | // plugins: [terser()], 28 | // }, 29 | ], 30 | plugins: [ 31 | esbuild({ 32 | target: 'es2018', 33 | // minify: true, // 压缩代码,比 terser 快 20-40 倍,压缩率只差 1%-2%。 34 | }), 35 | json({ 36 | preferConst: true, 37 | }), 38 | // terser(), // 压缩代码(体积减小了,但是不方便查看打包后的代码来排查问题) 39 | ], 40 | external: ['vue'], 41 | }, 42 | { 43 | // 输出类型文件 44 | input: 'src/index.ts', 45 | output: { 46 | file: 'dist/types/index.d.ts', 47 | format: 'es', 48 | }, 49 | plugins: [dts()], 50 | }, 51 | ]); 52 | -------------------------------------------------------------------------------- /packages/ui/README.md: -------------------------------------------------------------------------------- 1 | # @mylib/ui 2 | 3 | Vue 3 组件库,基于 Vue 3 + TypeScript 构建的现代化组件库。 4 | 5 | ## 特性 6 | 7 | - 🚀 基于 Vue 3 + TypeScript 构建 8 | - 📦 支持按需引入 9 | - 💪 使用 Monorepo + pnpm 工作区管理 10 | - 📝 完整的类型定义 11 | - 🔧 完善的开发工具链 12 | 13 | ## 安装 14 | 15 | ```bash 16 | npm install @mylib/ui 17 | 18 | yarn add @mylib/ui 19 | 20 | pnpm add @mylib/ui 21 | ``` 22 | 23 | ## 快速开始 24 | 25 | ### 全局引入 26 | 27 | ```ts 28 | // main.ts 29 | import { createApp } from 'vue'; 30 | import App from './App.vue'; 31 | 32 | import VUI from '@mylib/ui'; 33 | import '@mylib/ui/style.css'; 34 | 35 | const app = createApp(App); 36 | app.use(VUI); 37 | app.mount('#app'); 38 | ``` 39 | 40 | ### 按需引入 41 | 42 | ```ts 43 | // main.ts 44 | import { createApp } from 'vue'; 45 | import App from './App.vue'; 46 | 47 | import { Button } from '@mylib/ui'; 48 | import '@mylib/ui/style.css'; 49 | 50 | const app = createApp(App); 51 | app.use(Button); 52 | app.mount('#app'); 53 | ``` 54 | 55 | ## 使用示例 56 | 57 | ```vue 58 | 69 | 70 | 75 | ``` 76 | -------------------------------------------------------------------------------- /packages/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mylib/ui", 3 | "description": "@mylib ui library", 4 | "version": "1.0.0", 5 | "type": "module", 6 | "main": "dist/cjs/index.js", 7 | "module": "dist/esm/index.mjs", 8 | "types": "dist/types/index.d.ts", 9 | "exports": { 10 | ".": { 11 | "types": "./dist/types/index.d.ts", 12 | "import": "./dist/esm/index.mjs", 13 | "require": "./dist/cjs/index.js" 14 | }, 15 | "./style.css": "./dist/style.css", 16 | "./*": "./dist/*" 17 | }, 18 | "files": [ 19 | "dist", 20 | "CHANGELOG.md" 21 | ], 22 | "publishConfig": { 23 | "access": "public", 24 | "registry": "https://registry.npmjs.org/" 25 | }, 26 | "scripts": { 27 | "build": "rimraf dist && vite build", 28 | "test": "vitest", 29 | "test:ui": "vitest --ui", 30 | "test:coverage": "vitest --coverage", 31 | "test:bench": "vitest bench", 32 | "clean": "rimraf .turbo node_modules dist", 33 | "publish": "pnpm publish" 34 | }, 35 | "devDependencies": { 36 | "@mylib/typescript-config": "workspace:*", 37 | "@types/node": "catalog:types", 38 | "@vitejs/plugin-vue": "catalog:build", 39 | "@vitejs/plugin-vue-jsx": "catalog:build", 40 | "@vitest/ui": "catalog:test", 41 | "@vue/test-utils": "catalog:test", 42 | "happy-dom": "catalog:test", 43 | "sass": "catalog:dev", 44 | "typescript": "catalog:types", 45 | "vite": "catalog:build", 46 | "vite-plugin-dts": "catalog:build", 47 | "vitest": "catalog:test", 48 | "vue": "catalog:frontend" 49 | }, 50 | "peerDependencies": { 51 | "vue": "catalog:frontend" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /apps/docs/zh/guide/index.md: -------------------------------------------------------------------------------- 1 | # 快速开始 2 | 3 | ## 介绍 4 | 5 | mylib-template 是一个基于 Vue3 的组件库和工具集模板项目,包含以下几个部分: 6 | 7 | - UI 组件库:提供常用的 UI 组件 8 | - 工具函数:提供常用的工具函数 9 | - Hooks:提供可复用的组合式函数 10 | - Directives:提供常用的指令 11 | 12 | ## 安装 13 | 14 | 使用包管理器安装: 15 | 16 | ::: code-group 17 | 18 | ```bash [npm] 19 | npm install @mylib/ui @mylib/utils @mylib/hooks @mylib/directives 20 | ``` 21 | 22 | ```bash [yarn] 23 | yarn add @mylib/ui @mylib/utils @mylib/hooks @mylib/directives 24 | ``` 25 | 26 | ```bash [pnpm] 27 | pnpm add @mylib/ui @mylib/utils @mylib/hooks @mylib/directives 28 | ``` 29 | 30 | ```bash [bun] 31 | bun add @mylib/ui @mylib/utils @mylib/hooks @mylib/directives 32 | ``` 33 | 34 | ::: 35 | 36 | ## 使用 37 | 38 | ### UI 组件 39 | 40 | ```ts 41 | // 全局引入 42 | import { createApp } from 'vue'; 43 | import UI from '@mylib/ui'; 44 | import '@mylib/ui/style.css'; 45 | const app = createApp(App); 46 | app.use(UI); 47 | // tsconfig.json 还需要添加以下配置以获得类型提示: 48 | // "types": ["@mylib/ui/global.d.ts"] 49 | 50 | // 按需引入 51 | import { Button } from '@mylib/ui'; 52 | import '@mylib/ui/style.css'; 53 | const app = createApp(App); 54 | app.use(Button); 55 | ``` 56 | 57 | ### 工具函数 58 | 59 | ```ts 60 | import { isString } from '@mylib/utils'; 61 | console.log(isString('hello')); // true 62 | ``` 63 | 64 | ### Hooks 65 | 66 | ```ts 67 | import { useCounter } from '@mylib/hooks'; 68 | const { count, increment, decrement } = useCounter(); 69 | ``` 70 | 71 | ### 指令 72 | 73 | ```ts 74 | import { vFocus } from '@mylib/directives'; 75 | // 全局引入 76 | app.directive('focus', vFocus); 77 | 78 | // 按需引入 79 | import { vFocus } from '@mylib/directives'; 80 | app.directive('focus', vFocus); 81 | ``` 82 | -------------------------------------------------------------------------------- /playground/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { type RouteRecordRaw, createRouter, createWebHistory } from 'vue-router'; 2 | import { 3 | CommentOutlined, 4 | ExperimentOutlined, 5 | SettingOutlined, 6 | ToolOutlined, 7 | } from '@ant-design/icons-vue'; 8 | 9 | export const routes: RouteRecordRaw[] = [ 10 | { 11 | path: '/ui', 12 | name: 'UI', 13 | meta: { 14 | title: 'UI 组件', 15 | icon: CommentOutlined, 16 | }, 17 | component: () => import('@/layouts/container/Ui.vue'), 18 | }, 19 | { 20 | path: '/hooks', 21 | name: 'Hooks', 22 | meta: { 23 | title: 'Hooks', 24 | icon: ExperimentOutlined, 25 | }, 26 | component: () => import('@/layouts/container/Hooks.vue'), 27 | }, 28 | { 29 | path: '/directives', 30 | name: 'Directives', 31 | meta: { 32 | title: 'Directives', 33 | icon: SettingOutlined, 34 | }, 35 | component: () => import('@/layouts/container/Directives.vue'), 36 | }, 37 | { 38 | path: '/utils', 39 | name: 'Utils', 40 | meta: { 41 | title: 'Utils', 42 | icon: ToolOutlined, 43 | }, 44 | component: () => import('@/layouts/container/Utils.vue'), 45 | }, 46 | ]; 47 | 48 | const router = createRouter({ 49 | history: createWebHistory(), 50 | routes: [ 51 | { 52 | path: '/', 53 | component: () => import('@/layouts/MainLayout.vue'), 54 | children: [ 55 | { 56 | path: '', 57 | redirect: '/ui', 58 | }, 59 | ...routes, 60 | ], 61 | }, 62 | { 63 | path: '/:pathMatch(.*)*', 64 | redirect: '/ui', 65 | }, 66 | ], 67 | }); 68 | 69 | export default router; 70 | -------------------------------------------------------------------------------- /packages/lint-configs/stylelint-config/index.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import("stylelint").Config} */ 2 | export default { 3 | // 继承的配置 4 | extends: [ 5 | 'stylelint-config-standard', // 标准配置 6 | 'stylelint-config-recommended-vue', // Vue 推荐配置 7 | 'stylelint-config-recess-order', // CSS 属性排序配置 8 | 'stylelint-config-standard-scss', // SCSS 标准配置 9 | ], 10 | // 针对特定文件的覆盖配置 11 | overrides: [ 12 | { 13 | files: ['**/*.(scss|css|vue|html)'], // 匹配 SCSS/CSS/Vue/HTML 文件 14 | customSyntax: 'postcss-scss', // 使用 PostCSS SCSS 语法解析器 15 | }, 16 | { 17 | files: ['**/*.(vue|html)'], // 匹配 Vue/HTML 文件 18 | customSyntax: 'postcss-html', // 使用 PostCSS HTML 语法解析器 19 | }, 20 | ], 21 | // 规则配置 22 | rules: { 23 | // 基础规则 24 | 'selector-class-pattern': null, // 关闭类选择器命名规则检查 25 | 'no-descending-specificity': null, // 关闭选择器优先级降序检查 26 | 'no-invalid-double-slash-comments': null, // 允许使用双斜杠注释 27 | 28 | // SCSS 特定规则 29 | 'at-rule-no-unknown': null, // 关闭 at 规则未知检查 30 | 'scss/at-rule-no-unknown': true, // 启用 SCSS 的 at 规则检查 31 | 'function-no-unknown': null, // 关闭函数未知检查 32 | 'scss/function-no-unknown': [ 33 | true, // 启用 SCSS 函数未知检查 34 | { 35 | ignoreFunctions: ['mix', 'lighten', 'darken', 'rgba', 'v-bind'], // 忽略这些常用 SCSS 函数 36 | }, 37 | ], 38 | // 关闭 SCSS 全局函数名称检查 39 | 'scss/no-global-function-names': null, 40 | 41 | // 其他规则 42 | 'property-no-unknown': [ 43 | true, // 启用属性未知检查 44 | { 45 | ignoreProperties: ['//'], // 忽略双斜杠注释 46 | ignoreSelectors: [':export', ':import'], // 忽略 CSS Module 的导入导出选择器 47 | }, 48 | ], 49 | 'no-empty-source': null, // 允许空源文件 50 | }, 51 | }; 52 | -------------------------------------------------------------------------------- /apps/docs/en/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | hero: 4 | name: mylib-template 5 | text: Component Library and Utility Template 6 | tagline: A simple, powerful, and efficient Vue3 component library and utility template to help you quickly build your own or enterprise-level component library. 7 | image: 8 | src: /logo.png 9 | alt: mylib-template 10 | actions: 11 | - theme: brand 12 | text: Get Started 13 | link: /en/guide/ 14 | - theme: alt 15 | text: View on GitHub 16 | link: https://github.com/huangmingfu/vue3-turbo-component-lib-template 17 | 18 | features: 19 | - icon: 🛠️ 20 | title: UI Components 21 | details: Provides high-quality Vue3 components with features like on-demand import and theme customization 22 | - icon: 🔧 23 | title: Utility Functions 24 | details: Collection of commonly used utility functions to improve development efficiency and reduce code duplication 25 | - icon: 🎯 26 | title: Hooks 27 | details: Reusable composition functions for easier logic reuse 28 | - icon: ⚡️ 29 | title: Improve Development Efficiency 30 | details: A complete development environment for the component library, designed to allow developers to focus on component development without worrying about the complexity of underlying configurations. 31 | - icon: 🖖 32 | title: Hands-Free Experience 33 | details: A comprehensive build and packaging process that reduces manual operations, allowing you to focus on development while generating the necessary artifacts automatically. 34 | - icon: 🧮 35 | title: Comprehensive Standards 36 | details: Includes project standard configurations for ESLint, Prettier, Stylelint, Commitlint + Husky + Lint-Staged, and TypeScript to ensure consistent and maintainable code quality. 37 | --- 38 | -------------------------------------------------------------------------------- /packages/ui/src/components/Button/Button.scss: -------------------------------------------------------------------------------- 1 | @use 'sass:color'; 2 | 3 | .v-button { 4 | $types: ( 5 | primary: #409eff, 6 | success: #67c23a, 7 | warning: #e6a23c, 8 | danger: #f56c6c, 9 | info: #909399, 10 | ); 11 | 12 | box-sizing: border-box; 13 | display: inline-flex; 14 | align-items: center; 15 | justify-content: center; 16 | height: 32px; 17 | padding: 8px 15px; 18 | font-size: 14px; 19 | font-weight: 500; 20 | line-height: 1; 21 | color: #606266; 22 | text-align: center; 23 | white-space: nowrap; 24 | cursor: pointer; 25 | outline: none; 26 | border-radius: 4px; 27 | transition: 0.1s; 28 | 29 | // 尺寸 30 | &--medium { 31 | padding: 8px 15px; 32 | font-size: 14px; 33 | } 34 | 35 | &--small { 36 | height: 24px; 37 | padding: 5px 11px; 38 | font-size: 12px; 39 | } 40 | 41 | &--large { 42 | height: 40px; 43 | padding: 12px 19px; 44 | font-size: 16px; 45 | } 46 | 47 | // 状态 48 | &.is-disabled { 49 | cursor: not-allowed; 50 | opacity: 0.5; 51 | } 52 | 53 | &.is-round { 54 | border-radius: 20px; 55 | } 56 | 57 | // 类型 58 | @each $type, $color in $types { 59 | &--#{$type} { 60 | color: #fff; 61 | background-color: $color; 62 | border-color: $color; 63 | 64 | &:hover { 65 | $hover-color: color.mix(#fff, $color, 20%); 66 | 67 | background: $hover-color; 68 | border-color: $hover-color; 69 | } 70 | } 71 | 72 | &.is-plain.v-button--#{$type} { 73 | color: $color; 74 | background: color.mix(#fff, $color, 90%); 75 | border-color: color.mix(#fff, $color, 60%); 76 | 77 | &:hover { 78 | color: #fff; 79 | background: $color; 80 | border-color: $color; 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /apps/docs/.vitepress/config/zh.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress'; 2 | 3 | export const zh = defineConfig({ 4 | lang: 'zh-Hans', 5 | title: '组件库模板文档', 6 | description: '一个基于 Vue3 的组件库和工具集', 7 | themeConfig: { 8 | logo: '/logo.png', 9 | // https://vitepress.dev/reference/default-theme-config 10 | nav: [ 11 | { text: '首页', link: '/' }, 12 | // { text: '其他', link: '/markdown-examples' }, 13 | { text: '博客', link: 'https://huangmingfu.github.io/my-blog' }, 14 | { 15 | text: '更多', 16 | items: [ 17 | { 18 | text: '更新日志', 19 | link: 'https://github.com/huangmingfu/vue3-turbo-component-lib-template/blob/master/CHANGELOG.md', 20 | }, 21 | // { 22 | // text: '参与贡献', 23 | // link: '', 24 | // }, 25 | ], 26 | }, 27 | ], 28 | sidebar: [ 29 | { 30 | text: '快速开始', 31 | items: [{ text: '介绍', link: '/guide/index' }], 32 | }, 33 | { 34 | text: '组件(@mylib/ui)', 35 | items: [ 36 | { text: 'Button 按钮', link: '/packages/ui/button' }, 37 | { text: 'Dialog 对话框', link: '/packages/ui/dialog' }, 38 | ], 39 | }, 40 | { 41 | text: 'Hooks(@mylib/hooks)', 42 | items: [{ text: 'useCounter 计数器', link: '/packages/hooks/useCounter' }], 43 | }, 44 | { 45 | text: '指令(@mylib/directives)', 46 | items: [{ text: 'vFocus 聚焦', link: '/packages/directives/vFocus' }], 47 | }, 48 | { 49 | text: '工具函数(@mylib/utils)', 50 | items: [{ text: '字符串工具', link: '/packages/utils/string' }], 51 | }, 52 | ], 53 | socialLinks: [ 54 | { icon: 'github', link: 'https://github.com/huangmingfu/vue3-turbo-component-lib-template' }, 55 | ], 56 | }, 57 | }); 58 | -------------------------------------------------------------------------------- /apps/docs/.vitepress/config/en.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress'; 2 | 3 | export const en = defineConfig({ 4 | lang: 'en-US', 5 | title: 'Library Template Doc', 6 | description: 'A Vue3-based Component Library and Utility Collection', 7 | themeConfig: { 8 | logo: '/logo.png', 9 | // https://vitepress.dev/reference/default-theme-config 10 | nav: [ 11 | { text: 'Home', link: '/' }, 12 | // { text: 'Others', link: '/markdown-examples' }, 13 | { text: 'Blog', link: 'https://huangmingfu.github.io/my-blog' }, 14 | { 15 | text: 'More', 16 | items: [ 17 | { 18 | text: 'Changelog', 19 | link: 'https://github.com/huangmingfu/vue3-turbo-component-lib-template/blob/master/CHANGELOG.md', 20 | }, 21 | // { 22 | // text: 'Contribute', 23 | // link: '', 24 | // }, 25 | ], 26 | }, 27 | ], 28 | sidebar: [ 29 | { 30 | text: 'Quick Start', 31 | items: [{ text: 'Introduction', link: 'en/guide/index' }], 32 | }, 33 | { 34 | text: 'Components (@mylib/ui)', 35 | items: [ 36 | { text: 'Button', link: 'en/packages/ui/button' }, 37 | { text: 'Dialog', link: 'en/packages/ui/dialog' }, 38 | ], 39 | }, 40 | { 41 | text: 'Hooks (@mylib/hooks)', 42 | items: [{ text: 'useCounter', link: 'en/packages/hooks/useCounter' }], 43 | }, 44 | { 45 | text: 'Directives (@mylib/directives)', 46 | items: [{ text: 'vFocus', link: 'en/packages/directives/vFocus' }], 47 | }, 48 | { 49 | text: 'Utilities (@mylib/utils)', 50 | items: [{ text: 'String Utils', link: 'en/packages/utils/string' }], 51 | }, 52 | ], 53 | socialLinks: [ 54 | { icon: 'github', link: 'https://github.com/huangmingfu/vue3-turbo-component-lib-template' }, 55 | ], 56 | }, 57 | }); 58 | -------------------------------------------------------------------------------- /playground/src/layouts/MainLayout.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 50 | 51 | 64 | -------------------------------------------------------------------------------- /apps/docs/en/guide/index.md: -------------------------------------------------------------------------------- 1 | # Quick Start 2 | 3 | ## Introduction 4 | 5 | mylib-template is a component library and toolkit template project based on Vue3, consisting of the following parts: 6 | 7 | - UI Component Library: Provides commonly used UI components 8 | - Utility Functions: Offers common utility functions 9 | - Hooks: Provides reusable composable functions 10 | - Directives: Offers commonly used directives 11 | 12 | ## Installation 13 | 14 | Install using a package manager: 15 | 16 | ::: code-group 17 | 18 | ```bash [npm] 19 | npm install @mylib/ui @mylib/utils @mylib/hooks @mylib/directives 20 | ``` 21 | 22 | ```bash [yarn] 23 | yarn add @mylib/ui @mylib/utils @mylib/hooks @mylib/directives 24 | ``` 25 | 26 | ```bash [pnpm] 27 | pnpm add @mylib/ui @mylib/utils @mylib/hooks @mylib/directives 28 | ``` 29 | 30 | ```bash [bun] 31 | bun add @mylib/ui @mylib/utils @mylib/hooks @mylib/directives 32 | ``` 33 | 34 | ::: 35 | 36 | ## Usage 37 | 38 | ### UI Components 39 | 40 | ```ts 41 | // Global import 42 | import { createApp } from 'vue'; 43 | import UI from '@mylib/ui'; 44 | import '@mylib/ui/style.css'; 45 | const app = createApp(App); 46 | app.use(UI); 47 | // Additionally, add the following configuration to tsconfig.json for type hints: 48 | // "types": ["@mylib/ui/global.d.ts"] 49 | 50 | // Import on demand 51 | import { Button } from '@mylib/ui'; 52 | import '@mylib/ui/style.css'; 53 | const app = createApp(App); 54 | app.use(Button); 55 | ``` 56 | 57 | ### Utility Functions 58 | 59 | ```ts 60 | import { isString } from '@mylib/utils'; 61 | console.log(isString('hello')); // true 62 | ``` 63 | 64 | ### Hooks 65 | 66 | ```ts 67 | import { useCounter } from '@mylib/hooks'; 68 | const { count, increment, decrement } = useCounter(); 69 | ``` 70 | 71 | ### Directives 72 | 73 | ```ts 74 | import { vFocus } from '@mylib/directives'; 75 | // Global import 76 | app.directive('focus', vFocus); 77 | 78 | // Import on demand 79 | import { vFocus } from '@mylib/directives'; 80 | app.directive('focus', vFocus); 81 | ``` 82 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - apps/* 3 | - packages/* 4 | - packages/lint-configs/* 5 | - playground 6 | - build 7 | catalogs: 8 | frontend: 9 | 'vue': ^3.5.22 10 | ant-design-vue: ^4.2.6 11 | vue-router: ^4.6.3 12 | '@ant-design/icons-vue': ^7.0.1 13 | dev: 14 | 'sass': ^1.93.3 15 | rimraf: ^6.1.0 16 | '@changesets/cli': ^2.29.7 17 | types: 18 | '@types/node': ^24.10.0 19 | 'typescript': ^5.9.3 20 | build: 21 | turbo: ^2.6.0 22 | rollup: ^4.52.5 23 | '@rollup/plugin-json': ^6.1.0 24 | '@rollup/plugin-terser': ^0.4.4 25 | rollup-plugin-dts: ^6.2.3 26 | rollup-plugin-esbuild: ^6.2.1 27 | 'vite': ^7.1.12 28 | vitepress: ^1.6.4 29 | '@vitejs/plugin-vue': ^6.0.1 30 | '@vitejs/plugin-vue-jsx': ^5.1.1 31 | 'vite-plugin-dts': ^4.5.4 32 | vitepress-demo-plugin: ^1.5.0 33 | gulp: ^5.0.1 34 | gulp-clean: ^0.4.0 35 | rollup-plugin-copy: ^3.5.0 36 | rollup-plugin-scss: ^4.0.1 37 | '@babel/preset-env': ^7.28.5 38 | '@rollup/plugin-alias': ^6.0.0 39 | '@rollup/plugin-babel': ^6.1.0 40 | '@rollup/plugin-node-resolve': ^16.0.3 41 | lint: 42 | eslint: ^9.39.1 43 | globals: ^16.5.0 44 | prettier: ^3.6.2 45 | stylelint: ^16.25.0 46 | stylelint-config-recess-order: ^7.4.0 47 | stylelint-config-recommended-vue: ^1.6.1 48 | stylelint-config-standard: ^39.0.1 49 | stylelint-config-standard-scss: ^16.0.0 50 | stylelint-scss: ^6.12.1 51 | postcss: ^8.5.6 52 | postcss-html: ^1.8.0 53 | postcss-scss: ^4.0.9 54 | '@eslint/js': 9.39.1 55 | eslint-plugin-vue: ^10.5.1 56 | typescript-eslint: ^8.46.3 57 | '@commitlint/cli': ^20.1.0 58 | '@commitlint/config-conventional': ^20.0.0 59 | 'vue-eslint-parser': ^10.2.0 60 | husky: ^9.1.7 61 | lint-staged: ^16.2.6 62 | 'stylelint-order': ^7.0.0 63 | test: 64 | vitest: ^4.0.7 65 | happy-dom: ^20.0.10 66 | '@vitest/ui': ^4.0.7 67 | '@vue/test-utils': ^2.4.6 68 | 69 | onlyBuiltDependencies: 70 | - esbuild 71 | -------------------------------------------------------------------------------- /packages/ui/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import vue from '@vitejs/plugin-vue'; 3 | import vueJsx from '@vitejs/plugin-vue-jsx'; 4 | // 导入 TypeScript 声明文件插件 5 | import dts from 'vite-plugin-dts'; 6 | // node 7 | import path from 'node:path'; 8 | import fs from 'node:fs'; 9 | 10 | // 导出 Vite 配置 11 | export default defineConfig({ 12 | resolve: { 13 | alias: { 14 | '~': path.resolve(import.meta.dirname, 'src'), 15 | }, 16 | }, 17 | plugins: [ 18 | vue(), 19 | vueJsx(), 20 | dts({ 21 | // 包含的文件类型 22 | include: ['src/**/*.{vue,ts,tsx}'], 23 | exclude: ['src/__tests__/*', 'src/**/*.{test,spec,stories,demo}.{vue,ts,tsx}'], 24 | // 输出目录 25 | outDir: ['dist/types'], 26 | // 写入文件前的处理 27 | beforeWriteFile: (filePath, content) => ({ 28 | // 替换文件路径中的 '/src/' 为 '/',不然类型产物都会被放在src文件夹下面 29 | filePath: filePath.replace('/src/', '/'), 30 | content, 31 | }), 32 | }), 33 | // 自定义复制插件(可以使用 vite-plugin-static-copy 插件代替) 34 | { 35 | name: 'copy-global-dts', 36 | closeBundle() { 37 | // 复制文件global.d.ts到dist里 38 | const srcPath = path.resolve(import.meta.dirname, 'src/types/global.d.ts'); 39 | const destPath = path.resolve(import.meta.dirname, 'dist/global.d.ts'); 40 | fs.copyFileSync(srcPath, destPath); 41 | }, 42 | }, 43 | ], 44 | build: { 45 | target: 'esnext', // 目标版本 46 | outDir: 'dist', // 输出目录 47 | emptyOutDir: true, // 清空输出目录 48 | minify: false, // 方便查看打包后的代码(排查问题),禁用最小化混淆,默认为esbuild 49 | // 库配置 50 | lib: { 51 | // 入口文件 52 | entry: path.resolve(import.meta.dirname, 'src/index.ts'), 53 | // 输出格式 54 | formats: ['es', 'cjs'], 55 | // 输出文件名 56 | fileName: (format) => { 57 | return `${format === 'es' ? 'esm' : 'cjs'}/[name].${format === 'es' ? 'mjs' : 'js'}`; 58 | }, 59 | // CSS 输出文件名 60 | cssFileName: 'style', 61 | }, 62 | rollupOptions: { 63 | // 外部依赖 64 | external: ['vue'], 65 | // 输出配置 66 | output: { 67 | // 导出方式 68 | exports: 'named', 69 | // 保留原始模块结构,而不是将所有模块合并成一个大文件 70 | preserveModules: true, 71 | // 将 src 目录设置为模块的根目录,这样输出的文件就会直接从 src 的子目录开始,去掉 src 这一层。 72 | preserveModulesRoot: 'src', 73 | }, 74 | }, 75 | }, 76 | }); 77 | -------------------------------------------------------------------------------- /packages/ui/src/components/Button/__tests__/Button.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from 'vitest'; 2 | import { mount } from '@vue/test-utils'; 3 | import Button from '../Button.vue'; 4 | import type { ButtonProps } from '../Button.types'; 5 | 6 | describe('Button', () => { 7 | it('renders correctly', () => { 8 | const wrapper = mount(Button, { 9 | slots: { 10 | default: 'Test Button', 11 | }, 12 | }); 13 | 14 | expect(wrapper.text()).toBe('Test Button'); 15 | expect(wrapper.classes()).toContain('v-button'); 16 | }); 17 | 18 | it('applies correct type class', () => { 19 | const wrapper = mount(Button, { 20 | props: { 21 | type: 'primary', 22 | } as ButtonProps, 23 | }); 24 | 25 | expect(wrapper.classes()).toContain('v-button--primary'); 26 | }); 27 | 28 | it('applies correct size class', () => { 29 | const wrapper = mount(Button, { 30 | props: { 31 | size: 'large', 32 | } as ButtonProps, 33 | }); 34 | 35 | expect(wrapper.classes()).toContain('v-button--large'); 36 | }); 37 | 38 | it('applies disabled state correctly', () => { 39 | const wrapper = mount(Button, { 40 | props: { 41 | disabled: true, 42 | } as ButtonProps, 43 | }); 44 | 45 | expect(wrapper.classes()).toContain('is-disabled'); 46 | expect(wrapper.attributes('disabled')).toBeDefined(); 47 | }); 48 | 49 | it('applies round style correctly', () => { 50 | const wrapper = mount(Button, { 51 | props: { 52 | round: true, 53 | } as ButtonProps, 54 | }); 55 | 56 | expect(wrapper.classes()).toContain('is-round'); 57 | }); 58 | 59 | it('emits click event when clicked', async () => { 60 | const wrapper = mount(Button); 61 | 62 | await wrapper.trigger('click'); 63 | 64 | expect(wrapper.emitted('click')).toBeTruthy(); 65 | expect(wrapper.emitted('click')).toHaveLength(1); 66 | }); 67 | 68 | it('does not emit click event when disabled', async () => { 69 | const wrapper = mount(Button, { 70 | props: { 71 | disabled: true, 72 | } as ButtonProps, 73 | }); 74 | 75 | await wrapper.trigger('click'); 76 | 77 | expect(wrapper.emitted('click')).toBeFalsy(); 78 | }); 79 | 80 | it('passes click event object correctly', async () => { 81 | const wrapper = mount(Button); 82 | 83 | await wrapper.trigger('click'); 84 | 85 | const clickEvents = wrapper.emitted('click') as MouseEvent[][]; 86 | expect(clickEvents[0][0]).toBeInstanceOf(MouseEvent); 87 | }); 88 | }); 89 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Pages 2 | 3 | # 触发条件,push到master分支或者pull request到master分支 4 | on: 5 | push: 6 | branches: [master] 7 | pull_request: 8 | branches: [master] 9 | 10 | # 支持手动在工作流上触发 11 | workflow_dispatch: 12 | 13 | # 设置时区 14 | env: 15 | TZ: Asia/Shanghai 16 | 17 | # 权限设置 18 | permissions: 19 | # 允许读取仓库内容的权限。 20 | contents: read 21 | # 允许写入 GitHub Pages 的权限。 22 | pages: write 23 | # 允许写入 id-token 的权限。 24 | id-token: write 25 | 26 | # 并发控制配置 27 | concurrency: 28 | group: pages 29 | cancel-in-progress: false 30 | 31 | # 定义执行任务 32 | jobs: 33 | # 构建任务 34 | build: 35 | runs-on: ubuntu-latest 36 | 37 | # node v20 运行 38 | strategy: 39 | matrix: 40 | node-version: [20] 41 | 42 | steps: 43 | # 拉取代码 44 | - name: Checkout 45 | uses: actions/checkout@v3 46 | with: 47 | # 保留 Git 信息 48 | fetch-depth: 0 49 | 50 | # 设置使用 Node.js 版本 51 | - name: Use Node.js ${{ matrix.node-version }} 52 | uses: actions/setup-node@v3 53 | with: 54 | node-version: ${{ matrix.node-version }} 55 | 56 | # 使用 最新的 PNPM 57 | # 你也可以指定为具体的版本 58 | - uses: pnpm/action-setup@v2 59 | name: Install pnpm 60 | with: 61 | version: latest 62 | # version: 9 63 | run_install: false 64 | 65 | # 安装依赖 66 | - name: Install dependencies 67 | run: pnpm install --frozen-lockfile 68 | 69 | # 运行测试 70 | - name: Run tests 71 | run: pnpm run test 72 | # 运行代码检查 73 | - name: Run linting 74 | run: pnpm run lint:all 75 | 76 | # 构建项目 77 | # 需要先构建 @mylib/ui 等包后再构建docs 78 | # 不能只 pnpm run build:docs 会报如:failed to resolve entry for package "@mylib/hooks"的错误 79 | - name: Build docs project 80 | run: | 81 | echo ${{ github.workspace }} 82 | pnpm run build 83 | 84 | # 资源拷贝 85 | - name: Build with Jekyll 86 | uses: actions/jekyll-build-pages@v1 87 | with: 88 | source: ./apps/docs/.vitepress/dist 89 | destination: ./_site 90 | 91 | # 上传 _site 的资源,用于后续部署 92 | - name: Upload artifact 93 | uses: actions/upload-pages-artifact@v3 94 | 95 | # 部署任务 96 | deploy: 97 | environment: 98 | name: github-pages 99 | url: ${{ steps.deployment.outputs.page_url }} 100 | runs-on: ubuntu-latest 101 | needs: build 102 | steps: 103 | - name: Deploy to GitHub Pages 104 | id: deployment 105 | uses: actions/deploy-pages@v4 106 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue3-component-lib-template", 3 | "description": "This is a modern component library template based on Turborepo + Vue 3.5 + TypeScript.", 4 | "version": "1.0.0", 5 | "packageManager": "pnpm@10.20.0", 6 | "author": "huangmingfu <212149997@qq.com>", 7 | "license": "MIT", 8 | "homepage": "https://github.com/huangmingfu/vue3-turbo-component-lib-template", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/huangmingfu/vue3-turbo-component-lib-template" 12 | }, 13 | "bugs": "https://github.com/huangmingfu/vue3-turbo-component-lib-template/issues", 14 | "keywords": [ 15 | "component library template", 16 | "component library", 17 | "ui framework", 18 | "ui", 19 | "turborepo", 20 | "monorepo", 21 | "vue3 typescript", 22 | "vite6", 23 | "turbo" 24 | ], 25 | "scripts": { 26 | "dev": "turbo run dev", 27 | "dev:docs": "pnpm -F @mylib/docs run dev", 28 | "dev:play": "pnpm -F @mylib/playground run dev", 29 | "build": "turbo run build", 30 | "build:docs": "pnpm -F @mylib/docs run build", 31 | "build:gulp": "gulp -f build/gulpfile.js", 32 | "test": "turbo run test", 33 | "test:ui": "pnpm -F @mylib/ui run test:ui", 34 | "test:coverage": "turbo run test:coverage", 35 | "publish": "turbo run publish", 36 | "lint:eslint": "eslint --max-warnings 0 \"**/*.{ts,tsx,js,jsx,cjs,mjs,vue}\" --fix", 37 | "lint:format": "prettier --write \"**/*.{js,jsx,cjs,ts,tsx,mjs,mts,md,vue,scss,css,less,html,json}\"", 38 | "lint:style": "stylelint \"**/*.{css,scss,less}\" --fix", 39 | "lint:all": "pnpm run lint:eslint && pnpm run lint:style && pnpm run lint:format", 40 | "clean": "turbo run clean --continue && rimraf .turbo dist && rm -rf node_modules", 41 | "changeset:version": "pnpm changeset && pnpm changeset version", 42 | "deps:update": "pnpm update -r --latest", 43 | "deps:check": "pnpm outdated -r", 44 | "preinstall": "npx only-allow pnpm", 45 | "postinstall": "turbo run build", 46 | "prepare": "husky install", 47 | "rename-pkg": "bash ./scripts/rename-package.sh", 48 | "generate:component": "node scripts/generate-component.mjs" 49 | }, 50 | "devDependencies": { 51 | "@changesets/cli": "catalog:dev", 52 | "@commitlint/cli": "catalog:lint", 53 | "@mylib/commitlint-config": "workspace:*", 54 | "@mylib/directives": "workspace:*", 55 | "@mylib/eslint-config": "workspace:*", 56 | "@mylib/hooks": "workspace:*", 57 | "@mylib/prettier-config": "workspace:*", 58 | "@mylib/stylelint-config": "workspace:*", 59 | "@mylib/typescript-config": "workspace:*", 60 | "@mylib/ui": "workspace:*", 61 | "@mylib/utils": "workspace:*", 62 | "eslint": "catalog:lint", 63 | "husky": "catalog:lint", 64 | "lint-staged": "catalog:lint", 65 | "prettier": "catalog:lint", 66 | "rollup": "catalog:build", 67 | "stylelint": "catalog:lint", 68 | "turbo": "catalog:build", 69 | "typescript": "catalog:types", 70 | "vue": "catalog:frontend", 71 | "rimraf": "catalog:dev" 72 | }, 73 | "engines": { 74 | "node": ">=20", 75 | "pnpm": ">=9" 76 | }, 77 | "pnpm": { 78 | "peerDependencyRules": { 79 | "ignoreMissing": [ 80 | "@algolia/client-search", 81 | "search-insights" 82 | ] 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 贡献指南 2 | 3 | 感谢你对这个项目的关注!我们欢迎任何形式的贡献。 4 | 5 | ## 🚀 快速开始 6 | 7 | ### 环境要求 8 | 9 | - Node.js >= 20 10 | - pnpm >= 9 11 | 12 | ### 本地开发 13 | 14 | 1. Fork 并克隆仓库 15 | 16 | ```bash 17 | git clone https://github.com/your-username/vue3-turbo-component-lib-template.git 18 | cd vue3-turbo-component-lib-template 19 | ``` 20 | 21 | 2. 安装依赖 22 | 23 | ```bash 24 | pnpm install 25 | ``` 26 | 27 | 3. 启动开发环境 28 | 29 | ```bash 30 | # 启动所有包的开发环境 31 | pnpm dev 32 | 33 | # 或者启动特定的应用 34 | pnpm dev:docs # 启动文档 35 | pnpm dev:play # 启动 playground 36 | ``` 37 | 38 | ## 📝 开发规范 39 | 40 | ### 代码规范 41 | 42 | 项目使用以下工具确保代码质量: 43 | 44 | - **ESLint**: JavaScript/TypeScript 代码检查 45 | - **Prettier**: 代码格式化 46 | - **Stylelint**: CSS/SCSS 样式检查 47 | - **Commitlint**: Git 提交信息规范 48 | 49 | 运行代码检查: 50 | 51 | ```bash 52 | pnpm lint:all 53 | ``` 54 | 55 | ### 提交规范 56 | 57 | 我们使用 [Conventional Commits](https://www.conventionalcommits.org/) 规范: 58 | 59 | ``` 60 | [optional scope]: 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 = ` 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 | 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 | 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 | GitHub stars 12 | 13 | 14 | GitHub issues 15 | 16 | 17 | GitHub 18 | 19 | 20 | GitHub forks 21 | 22 |

23 | 24 | [![Vue.js](https://img.shields.io/badge/Vue.js-3.5-42b883?style=flat-square&logo=vue.js&logoColor=white)](https://v3.vuejs.org/) 25 | [![TypeScript](https://img.shields.io/badge/TypeScript-5.0-3178c6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/) 26 | [![Turborepo](https://img.shields.io/badge/Turborepo-%23000000?style=flat-square&logo=turborepo&logoColor=white)](https://turbo.build/) 27 | [![pnpm](https://img.shields.io/badge/pnpm-%23F69220?style=flat-square&logo=pnpm&logoColor=white)](https://pnpm.io/) 28 | [![License](https://img.shields.io/github/license/huangmingfu/vue3-turbo-component-lib-template?style=flat-square)](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 | ![](https://huangmingfu.github.io/drawing-bed/images/pic-go/202412291431548.png) 137 | ![](https://huangmingfu.github.io/drawing-bed/images/pic-go/202411271629728.png) 138 | ![](https://huangmingfu.github.io/drawing-bed/images/pic-go/202411271629672.png) 139 | 140 | ### 演练场 141 | 142 | > 实时预览和测试组件 143 | 144 | ![](https://huangmingfu.github.io/drawing-bed/images/pic-go/202411271630381.png) 145 | ![](https://huangmingfu.github.io/drawing-bed/images/pic-go/202411271631563.png) 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 | ![](https://huangmingfu.github.io/drawing-bed/images/pic-go/202412251542234.png) 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 | GitHub stars 12 | 13 | 14 | GitHub issues 15 | 16 | 17 | GitHub 18 | 19 | 20 | GitHub forks 21 | 22 |

23 | 24 | [![Vue.js](https://img.shields.io/badge/Vue.js-3.5-42b883?style=flat-square&logo=vue.js&logoColor=white)](https://v3.vuejs.org/) 25 | [![TypeScript](https://img.shields.io/badge/TypeScript-5.0-3178c6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/) 26 | [![Turborepo](https://img.shields.io/badge/Turborepo-%23000000?style=flat-square&logo=turborepo&logoColor=white)](https://turbo.build/) 27 | [![pnpm](https://img.shields.io/badge/pnpm-%23F69220?style=flat-square&logo=pnpm&logoColor=white)](https://pnpm.io/) 28 | [![License](https://img.shields.io/github/license/huangmingfu/vue3-turbo-component-lib-template?style=flat-square)](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 | ![](https://huangmingfu.github.io/drawing-bed/images/pic-go/202412291431548.png) 137 | ![](https://huangmingfu.github.io/drawing-bed/images/pic-go/202411271629728.png) 138 | ![](https://huangmingfu.github.io/drawing-bed/images/pic-go/202411271629672.png) 139 | 140 | ### Playground 141 | 142 | > Real-time preview and testing of components 143 | 144 | ![](https://huangmingfu.github.io/drawing-bed/images/pic-go/202411271630381.png) 145 | ![](https://huangmingfu.github.io/drawing-bed/images/pic-go/202411271631563.png) 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 | ![](https://huangmingfu.github.io/drawing-bed/images/pic-go/202412251542234.png) 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 | --------------------------------------------------------------------------------