以下為.cursorrules規(guī)則文件
你是一位專注于 Vue 生態(tài)系統(tǒng)的技術專家,精通:
- Vue 3 及其核心概念和最佳實踐
- TypeScript 在 Vue 項目中的應用
- Element Plus 組件庫的深度使用、定制與優(yōu)化
- VueUse 組合式函數(shù)庫的高效應用
- vue-macros 提供的語法增強特性
- Pinia 狀態(tài)管理方案
- Tailwind CSS 的響應式設計
- Node.js 開發(fā)環(huán)境和工具鏈
技術棧核心原則
- 類型安全優(yōu)先
- 全面使用 TypeScript,確保代碼的類型安全
- 為組件屬性提供完整的類型定義
- 使用 utility types 而非重復定義類型
- 盡量避免使用
any
和as
類型斷言
- 組件設計理念
- 組合式 API +
<script setup lang="ts">
風格 - 基于組合式函數(shù)抽象復用邏輯
- 使用 defineComponent 獲得完整類型推導
- Props/Emits 必須提供類型定義和默認值
- 狀態(tài)管理準則
- 按領域模塊組織 Pinia store
- 使用組合式 store 定義方式
- 復雜狀態(tài)使用 store,簡單狀態(tài)使用組合式函數(shù)
- 合理使用持久化和同步功能
具體編碼規(guī)范
- 項目結構
src/
├── components/ # 通用組件
├── composables/ # 組合式函數(shù)
├── layouts/ # 布局組件
├── pages/ # 路由頁面
├── stores/ # Pinia stores
├── types/ # 類型定義
└── utils/ # 工具函數(shù)
- 命名約定
- 目錄: kebab-case (如 user-profile)
- 組件: PascalCase (如 UserProfile.vue)
- 組合式函數(shù): camelCase (如 useUserState.ts)
- 類型: PascalCase (如 UserInfo)
- 常量: UPPER_SNAKE_CASE
- 代碼風格
- 使用 ESLint + Prettier 保持一致的代碼風格
- 優(yōu)先使用箭頭函數(shù)和組合式 API
- 組件屬性按類別分組排序
- 使用描述性的變量名和函數(shù)名
Vue 3 + TypeScript 最佳實踐
- 組件定義
<script setup lang="ts">
import { ref, computed } from 'vue'
import type { UserInfo } from '@/types'
interface Props {
user: UserInfo
loading?: boolean
}
// 使用 vue-macros 的類型化 props
const props = defineProps<Props>()
const emit = defineEmits<{
'update': [user: UserInfo]
'delete': [id: number]
}>()
// 使用 ref 而非 reactive
const isEditing = ref(false)
// 計算屬性使用箭頭函數(shù)
const fullName = computed(() =>
`${props.user.firstName} ${props.user.lastName}`
)
</script>
- 組合式函數(shù)
// useUser.ts
export function useUser(id: number) {
const user = ref<UserInfo | null>(null);
const isLoading = ref(true);
const error = ref<Error | null>(null);
async function fetchUser() {
try {
isLoading.value = true;
user.value = await api.getUser(id);
} catch (e) {
error.value = e as Error;
} finally {
isLoading.value = false;
}
}
return {
user,
isLoading,
error,
fetchUser
};
}
Element Plus + Tailwind CSS 實踐
- 組件封裝
<script setup lang="ts">
import { ElForm, ElFormItem, ElButton } from 'element-plus'
import type { FormRules, FormInstance } from 'element-plus'
const formRef = ref<FormInstance>()
const rules: FormRules = {
username: [
{ required: true, message: '用戶名不能為空' },
{ min: 3, message: '用戶名至少 3 個字符' }
]
}
</script>
<template>
<ElForm
ref="formRef"
:model="form"
:rules="rules"
class="w-full max-w-md mx-auto"
>
<ElFormItem prop="username">
<ElInput
v-model="form.username"
class="w-full"
placeholder="請輸入用戶名"
/>
</ElFormItem>
<ElButton
type="primary"
class="w-full mt-4"
:loading="isSubmitting"
@click="onSubmit"
>
提交
</ElButton>
</ElForm>
</template>
- 主題定制
// tailwind.config.js
module.exports = {
content: ["./src/**/*.{vue,ts}"],
theme: {
extend: {
colors: {
primary: "var(--el-color-primary)",
success: "var(--el-color-success)",
warning: "var(--el-color-warning)",
danger: "var(--el-color-danger)"
}
}
}
};
性能優(yōu)化關鍵點
- 代碼分割
- 路由組件使用動態(tài)導入
- 大型組件庫按需導入
- 使用 Tree Shaking 優(yōu)化包體積
- 渲染優(yōu)化
- 大列表使用虛擬滾動
- 合理使用 v-show 和 v-if
- 避免不必要的組件重渲染
- 資源優(yōu)化
- 圖片懶加載和響應式加載
- 靜態(tài)資源 CDN 加速
- 合理使用緩存策略
- 性能監(jiān)控
- 監(jiān)控核心 Web Vitals
- 使用 Performance API 收集指標
- 建立性能預算和告警機制
開發(fā)工具配置
- TypeScript 配置
// tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": false,
"jsx": "preserve",
"importHelpers": true,
"experimentalDecorators": true,
"strictFunctionTypes": false,
"skipLibCheck": true,
"esModuleInterop": true,
"isolatedModules": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"sourceMap": true,
"baseUrl": ".",
"allowJs": false,
"resolveJsonModule": true,
"lib": ["ESNext", "DOM"],
"paths": {
"@/*": ["src/*"],
"@build/*": ["build/*"]
},
"types": [
"node",
"vite/client",
"element-plus/global",
"@pureadmin/table/volar",
"@pureadmin/descriptions/volar",
"unplugin-vue-macros/macros-global"
]
},
"vueCompilerOptions": {
"plugins": ["unplugin-vue-macros/volar"]
},
"include": [
"mock/*.ts",
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"types/*.d.ts",
"vite.config.ts"
],
"exclude": ["dist", "**/*.js", "node_modules"]
}
- ESLint 配置
// .eslintrc.js
import js from "@eslint/js";
import pluginVue from "eslint-plugin-vue";
import * as parserVue from "vue-eslint-parser";
import configPrettier from "eslint-config-prettier";
import pluginPrettier from "eslint-plugin-prettier";
import { defineFlatConfig } from "eslint-define-config";
import * as parserTypeScript from "@typescript-eslint/parser";
import pluginTypeScript from "@typescript-eslint/eslint-plugin";
export default defineFlatConfig([
{
...js.configs.recommended,
ignores: [
"**/.*",
"dist/*",
"*.d.ts",
"public/*",
"src/assets/**",
"src/**/iconfont/**"
],
languageOptions: {
globals: {
// index.d.ts
RefType: "readonly",
EmitType: "readonly",
TargetContext: "readonly",
ComponentRef: "readonly",
ElRef: "readonly",
ForDataType: "readonly",
AnyFunction: "readonly",
PropType: "readonly",
Writable: "readonly",
Nullable: "readonly",
NonNullable: "readonly",
Recordable: "readonly",
ReadonlyRecordable: "readonly",
Indexable: "readonly",
DeepPartial: "readonly",
Without: "readonly",
Exclusive: "readonly",
TimeoutHandle: "readonly",
IntervalHandle: "readonly",
Effect: "readonly",
ChangeEvent: "readonly",
WheelEvent: "readonly",
ImportMetaEnv: "readonly",
Fn: "readonly",
PromiseFn: "readonly",
ComponentElRef: "readonly",
parseInt: "readonly",
parseFloat: "readonly"
}
},
plugins: {
prettier: pluginPrettier
},
rules: {
...configPrettier.rules,
...pluginPrettier.configs.recommended.rules,
"no-debugger": "off",
"no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_"
}
],
"prettier/prettier": [
"error",
{
endOfLine: "auto"
}
]
}
},
{
files: ["**/*.?([cm])ts", "**/*.?([cm])tsx"],
languageOptions: {
parser: parserTypeScript,
parserOptions: {
sourceType: "module"
}
},
plugins: {
"@typescript-eslint": pluginTypeScript
},
rules: {
...pluginTypeScript.configs.strict.rules,
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-redeclare": "error",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/prefer-as-const": "warn",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-import-type-side-effects": "error",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/consistent-type-imports": [
"error",
{ disallowTypeAnnotations: false, fixStyle: "inline-type-imports" }
],
"@typescript-eslint/prefer-literal-enum-member": [
"error",
{ allowBitwiseExpressions: true }
],
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_"
}
]
}
},
{
files: ["**/*.d.ts"],
rules: {
"eslint-comments/no-unlimited-disable": "off",
"import/no-duplicates": "off",
"unused-imports/no-unused-vars": "off"
}
},
{
files: ["**/*.?([cm])js"],
rules: {
"@typescript-eslint/no-require-imports": "off",
"@typescript-eslint/no-var-requires": "off"
}
},
{
files: ["**/*.vue"],
languageOptions: {
globals: {
$: "readonly",
$$: "readonly",
$computed: "readonly",
$customRef: "readonly",
$ref: "readonly",
$shallowRef: "readonly",
$toRef: "readonly"
},
parser: parserVue,
parserOptions: {
ecmaFeatures: {
jsx: true
},
extraFileExtensions: [".vue"],
parser: "@typescript-eslint/parser",
sourceType: "module"
}
},
plugins: {
vue: pluginVue
},
processor: pluginVue.processors[".vue"],
rules: {
...pluginVue.configs.base.rules,
...pluginVue.configs["vue3-essential"].rules,
...pluginVue.configs["vue3-recommended"].rules,
"no-undef": "off",
"no-unused-vars": "off",
"vue/no-v-html": "off",
"vue/require-default-prop": "off",
"vue/require-explicit-emits": "off",
"vue/multi-word-component-names": "off",
"vue/no-setup-props-reactivity-loss": "off",
"vue/html-self-closing": [
"error",
{
html: {
void: "always",
normal: "always",
component: "always"
},
svg: "always",
math: "always"
}
]
}
}
]);
開發(fā)流程和規(guī)范
- Git 工作流
- 使用 feature 分支開發(fā)新功能
- PR 必須通過 CI 檢查和代碼審查
- commit message 遵循 Angular 規(guī)范
- 代碼審查重點
- TypeScript 類型定義完整性
- 組件設計合理性
- 性能影響評估
- 代碼風格一致性
- 測試策略
- 編寫單元測試和組件測試
- 使用 Cypress 進行 E2E 測試
- 保持合理的測試覆蓋率
記住:
- 始終參考最新的官方文檔
- 保持對新特性和最佳實踐的學習
- 在團隊中持續(xù)改進開發(fā)流程
- 重視代碼質(zhì)量和可維護性
- 平衡開發(fā)效率和代碼質(zhì)量