第122课:工程化实践——Vue 3 项目初始化与目录结构 上一课我们搭建了 React 的企业级项目骨架。本节课将使用 Vue 3 + TypeScript + Vite 技术栈,从零构建一个同样具备工程化约束的 Vue 3 单页应用骨架。我们将覆盖项目初始化、TypeScript 严格配置、ESLint + Prettier 规范、Husky + lint-staged 提交拦截、环境变量与 API 模块封装、以及 Vue 3 特有的目录结构分层设计原则——包括 Composables、Pinia Store、以及 Vue Router 4 的路由分层。学完本课,你将能够快速初始化一个结构清晰、约束到位、可立即投入团队开发的 Vue 3 工程模板。
1. 项目初始化:Vite + Vue 3 + TypeScript 模板 1.1 使用 Vite 创建项目 1 2 3 4 5 6 7 8 pnpm create vite my-vue-app --template vue-ts cd my-vue-apppnpm install
Vite 的 vue-ts 模板默认包含 vite.config.ts、tsconfig.json、src/App.vue、src/main.ts 等文件。与 React 模板一样,我们需要进行深度定制以适配企业级标准。
1.2 初始清理 删除 Vite 模板中的演示代码,为实际项目骨架做准备:
1 2 3 rm src/components/HelloWorld.vue src/style.css src/assets/vue.svg
将 src/App.vue 精简为:
1 2 3 4 5 6 <script setup lang="ts"> </script> <template> <div>My Vue App</div> </template>
将 src/main.ts 调整为:
1 2 3 4 5 import { createApp } from 'vue' ;import App from './App.vue' ;const app = createApp (App );app.mount ('#app' );
2. TypeScript 严格配置 Vue 3 的 TypeScript 配置需要额外处理 .vue 文件的类型声明。默认的 tsconfig.json 已经通过 references 引用了 tsconfig.app.json(Vite 5+ 模板)。我们需要在 tsconfig.app.json 中进行定制。
2.1 更新 tsconfig.app.json 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 { "compilerOptions" : { "target" : "ES2022" , "lib" : [ "ES2022" , "DOM" , "DOM.Iterable" ] , "module" : "ESNext" , "moduleResolution" : "bundler" , "jsx" : "preserve" , "strict" : true , "noUnusedLocals" : true , "noUnusedParameters" : true , "noFallthroughCasesInSwitch" : true , "forceConsistentCasingInFileNames" : true , "skipLibCheck" : true , "esModuleInterop" : true , "allowSyntheticDefaultImports" : true , "resolveJsonModule" : true , "isolatedModules" : true , "noEmit" : true , "baseUrl" : "." , "paths" : { "@/*" : [ "src/*" ] } } , "include" : [ "src/**/*.ts" , "src/**/*.tsx" , "src/**/*.vue" , "src/**/*.d.ts" ] }
关键选项说明 :
jsx: "preserve":Vue 3 的 JSX 支持需要此设置。TypeScript 不转换 JSX,由 Vue 编译器处理。
isolatedModules: true:与 Vite 的 esbuild 转译兼容。
paths:定义 @/* 路径别名,映射到 src/ 目录。
include:必须包含 .vue 文件路径,否则 TypeScript 无法识别 Vue 单文件组件。
2.2 配置 Vite 路径别名 在 vite.config.ts 中同步路径别名:
1 2 3 4 5 6 7 8 9 10 11 12 import { defineConfig } from 'vite' ;import vue from '@vitejs/plugin-vue' ;import { fileURLToPath, URL } from 'url' ;export default defineConfig ({ plugins : [vue ()], resolve : { alias : { '@' : fileURLToPath (new URL ('./src' , import .meta .url )), }, }, });
2.3 Vue 类型声明 确保 src/vite-env.d.ts(Vite 模板默认生成)包含 Vue 的类型声明:
1 2 3 4 5 6 7 declare module '*.vue' { import type { DefineComponent } from 'vue' ; const component : DefineComponent <{}, {}, any >; export default component; }
3. 代码规范:ESLint + Prettier + Husky + lint-staged 3.1 安装 ESLint 相关依赖 1 pnpm add -D eslint prettier eslint-plugin-vue @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-prettier husky lint-staged vue-tsc
3.2 ESLint 配置 创建 .eslintrc.cjs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 module .exports = { root : true , env : { browser : true , es2022 : true , node : true }, extends : [ 'eslint:recommended' , 'plugin:vue/vue3-recommended' , 'plugin:@typescript-eslint/recommended' , 'prettier' , ], parser : 'vue-eslint-parser' , parserOptions : { parser : '@typescript-eslint/parser' , ecmaVersion : 'latest' , sourceType : 'module' , }, rules : { 'vue/multi-word-component-names' : 'off' , '@typescript-eslint/no-unused-vars' : ['error' , { argsIgnorePattern : '^_' }], 'no-console' : ['warn' , { allow : ['warn' , 'error' ] }], 'prefer-const' : 'error' , 'eqeqeq' : ['error' , 'always' ], }, };
与 React 配置的关键差异 :
使用 vue-eslint-parser 作为主解析器,@typescript-eslint/parser 作为其子解析器(处理 <script> 中的 TypeScript)。
extends 中包含了 plugin:vue/vue3-recommended 启用 Vue 3 的官方推荐规则集。
3.3 Prettier 配置 与第 121 课 React 项目的 Prettier 配置一致,创建 .prettierrc:
1 2 3 4 5 6 7 8 9 10 11 12 { "printWidth" : 100 , "tabWidth" : 2 , "useTabs" : false , "semi" : true , "singleQuote" : true , "quoteProps" : "as-needed" , "trailingComma" : "all" , "bracketSpacing" : true , "arrowParens" : "always" , "endOfLine" : "lf" }
创建 .prettierignore:
1 2 3 4 dist/ node_modules/ coverage/ pnpm-lock.yaml
3.4 Husky + lint-staged 配置
编辑 .husky/pre-commit:
在 package.json 中添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 { "lint-staged" : { "*.{vue,ts,tsx,js,jsx}" : [ "eslint --fix" , "prettier --write" ] , "*.{css,scss,md,json}" : [ "prettier --write" ] } , "scripts" : { "dev" : "vite" , "build" : "vue-tsc --noEmit && vite build" , "preview" : "vite preview" , "lint" : "eslint src --ext .vue,.ts,.tsx --max-warnings 0" , "lint:fix" : "eslint src --ext .vue,.ts,.tsx --fix" , "format" : "prettier --write \"src/**/*.{vue,ts,tsx,css,scss,md,json}\"" , "typecheck" : "vue-tsc --noEmit" , "prepare" : "husky" } }
注意 :Vue 3 项目使用 vue-tsc --noEmit 进行类型检查,而非 tsc --noEmit。vue-tsc 是 Vue 官方提供的 TypeScript 类型检查工具,能正确识别 .vue 文件。lint-staged 的文件匹配模式需要包含 *.vue 文件。
4. 环境变量与 API 模块封装 4.1 环境变量文件 1 2 3 4 5 6 7 8 VITE_APP_TITLE=My Vue App VITE_API_BASE_URL=http://localhost:3000/api VITE_API_BASE_URL=https://api.example.com
在 src/vite-env.d.ts 中追加环境变量类型声明:
1 2 3 4 5 6 7 8 9 10 interface ImportMetaEnv { readonly VITE_APP_TITLE : string ; readonly VITE_API_BASE_URL : string ; } interface ImportMeta { readonly env : ImportMetaEnv ; }
4.2 API 客户端封装 在 src/api/client.ts 中创建通用 HTTP 客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 const API_BASE_URL = import .meta .env .VITE_API_BASE_URL ;interface RequestConfig extends Omit <RequestInit , 'body'> { body?: unknown ; params?: Record <string , string | number | undefined >; } class HttpClient { private async request<T>(endpoint : string , config : RequestConfig = {}): Promise <T> { const { body, params, ...init } = config; let url = `${API_BASE_URL} ${endpoint} ` ; if (params) { const searchParams = new URLSearchParams (); Object .entries (params).forEach (([key, value] ) => { if (value !== undefined ) searchParams.set (key, String (value)); }); const qs = searchParams.toString (); if (qs) url += `?${qs} ` ; } const headers : Record <string , string > = { 'Content-Type' : 'application/json' , ...(init.headers as Record <string , string >), }; const token = localStorage .getItem ('token' ); if (token) { headers['Authorization' ] = `Bearer ${token} ` ; } const response = await fetch (url, { ...init, headers, body : body ? JSON .stringify (body) : undefined , }); if (!response.ok ) { const error = await response.json ().catch (() => ({ message : response.statusText })); throw new Error (error.message || `HTTP Error ${response.status} ` ); } if (response.status === 204 ) return undefined as T; return response.json (); } get<T>(endpoint : string , config?: RequestConfig ) { return this .request <T>(endpoint, { ...config, method : 'GET' }); } post<T>(endpoint : string , body?: unknown , config?: RequestConfig ) { return this .request <T>(endpoint, { ...config, method : 'POST' , body }); } put<T>(endpoint : string , body?: unknown , config?: RequestConfig ) { return this .request <T>(endpoint, { ...config, method : 'PUT' , body }); } patch<T>(endpoint : string , body?: unknown , config?: RequestConfig ) { return this .request <T>(endpoint, { ...config, method : 'PATCH' , body }); } delete <T>(endpoint : string , config?: RequestConfig ) { return this .request <T>(endpoint, { ...config, method : 'DELETE' }); } } export const http = new HttpClient ();
4.3 API 模块示例 创建 src/api/user.api.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import { http } from './client' ;export interface User { id : number ; name : string ; email : string ; role : string ; } export const userApi = { getUsers : (params?: { page?: number ; size?: number } ) => http.get <User []>('/users' , { params }), getUserById : (id: number ) => http.get <User >(`/users/${id} ` ), createUser : (data: Omit<User, 'id' > ) => http.post <User >('/users' , data), updateUser : (id: number , data: Partial<User> ) => http.patch <User >(`/users/${id} ` , data), deleteUser : (id: number ) => http.delete <void >(`/users/${id} ` ), };
5. 目录结构分层设计 5.1 推荐目录结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 my-vue-app/ ├── public/ │ └── favicon.svg ├── src/ │ ├── api/ # API 请求模块 │ │ ├── client.ts # 通用 HTTP 客户端 │ │ └── user.api.ts # 用户相关 API │ ├── assets/ # 静态资源 │ ├── components/ # 通用 UI 组件 │ │ ├── ui/ # 基础 UI 组件(BaseButton、BaseInput、BaseModal) │ │ └── layout/ # 布局组件(AppHeader、AppSidebar、AppFooter) │ ├── composables/ # 组合式函数(Composables) │ │ ├── useAuth.ts │ │ └── useDebounce.ts │ ├── pages/ # 页面组件(按路由组织) │ │ ├── Home/ │ │ │ └── index.vue │ │ ├── Users/ │ │ └── NotFound/ │ │ └── index.vue │ ├── router/ # 路由配置 │ │ └── index.ts │ ├── stores/ # 状态管理(Pinia Store) │ │ ├── useAuthStore.ts │ │ └── useAppStore.ts │ ├── styles/ # 全局样式与 CSS 变量 │ │ ├── globals.css │ │ └── variables.css │ ├── types/ # 共享 TypeScript 类型定义 │ │ └── common.ts │ ├── utils/ # 工具函数 │ │ ├── format.ts │ │ └── storage.ts │ ├── App.vue │ ├── main.ts │ └── vite-env.d.ts ├── .env.development ├── .env.production ├── .eslintrc.cjs ├── .prettierrc ├── .prettierignore ├── .gitignore ├── index.html ├── package.json ├── pnpm-lock.yaml ├── tsconfig.json ├── tsconfig.app.json ├── tsconfig.node.json └── vite.config.ts
5.2 分层原则
**composables/**:Vue 3 的核心复用单元。将可复用的响应式逻辑和副作用封装为 useXxx 函数。与 React 的 hooks/ 目录职能一致。
**stores/**:Pinia Store 的集中目录。每个 Store 负责一个业务领域的状态管理,通过 Setup Store 语法定义。
**components/**:通用 UI 组件。ui/ 下的基础组件通过 Props 和 Emits 与外部交互,不应直接访问路由或 Store(除非是专门的 Provider 组件)。
**pages/**:路由级别的页面入口。它们组合 Composables、Stores 和组件。
5.3 命名约定
类型
规则
示例
页面组件
PascalCase 目录 + index.vue
Home/index.vue
通用 UI 组件
PascalCase
BaseButton.vue
Composable 文件
camelCase,以 use 开头
useAuth.ts
Pinia Store 文件
camelCase,以 use 开头,以 Store 结尾
useAuthStore.ts
工具函数文件
camelCase
format.ts
API 模块文件
与资源名对应,resource.api.ts
user.api.ts
6. Pinia Store 示例:认证 Store 在 src/stores/useAuthStore.ts 中创建认证 Store(Setup Store 语法):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import { defineStore } from 'pinia' ;import { ref, computed } from 'vue' ;import type { User } from '@/api/user.api' ;import { userApi } from '@/api/user.api' ;export const useAuthStore = defineStore ('auth' , () => { const token = ref<string | null >(localStorage .getItem ('token' )); const currentUser = ref<User | null >(null ); const loading = ref (false ); const isAuthenticated = computed (() => !!token.value ); async function login (username: string , password: string ) { loading.value = true ; try { const response = await fetch ('/api/login' , { method : 'POST' , body : JSON .stringify ({ username, password }), }); const data = await response.json (); token.value = data.token ; localStorage .setItem ('token' , data.token ); currentUser.value = data.user ; } finally { loading.value = false ; } } function logout ( ) { token.value = null ; currentUser.value = null ; localStorage .removeItem ('token' ); } return { token, currentUser, loading, isAuthenticated, login, logout }; }, { persist : { pick : ['token' ], }, });
设计要点 :
使用 Setup Store 语法(defineStore 的回调函数内使用 ref、computed),与 <script setup> 心智模型一致。
token 持久化到 localStorage(通过 pinia-plugin-persistedstate 插件),刷新后保持登录状态。
currentUser 不持久化——每次刷新后通过 API 重新获取(或从 token 中解析)。
7. 路由配置:Vue Router 4 集成 7.1 安装 Vue Router
7.2 创建路由配置 在 src/router/index.ts 中定义路由表,使用懒加载 拆分页面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import { createRouter, createWebHistory } from 'vue-router' ;const router = createRouter ({ history : createWebHistory (), routes : [ { path : '/' , name : 'home' , component : () => import ('@/pages/Home/index.vue' ), meta : { title : '首页' }, }, { path : '/users' , name : 'users' , component : () => import ('@/pages/Users/index.vue' ), meta : { title : '用户管理' , requiresAuth : true }, }, { path : '/:pathMatch(.*)*' , name : 'not-found' , component : () => import ('@/pages/NotFound/index.vue' ), meta : { title : '页面未找到' }, }, ], }); router.afterEach ((to ) => { document .title = to.meta .title ? `${to.meta.title} - My Vue App` : 'My Vue App' ; }); export default router;
在 src/main.ts 中注册路由和 Pinia:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import { createApp } from 'vue' ;import { createPinia } from 'pinia' ;import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' ;import App from './App.vue' ;import router from './router' ;import './styles/globals.css' ;const app = createApp (App );const pinia = createPinia ();pinia.use (piniaPluginPersistedstate); app.use (pinia); app.use (router); app.mount ('#app' );
在 src/App.vue 中使用 <router-view>:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <script setup lang="ts"> </script> <template> <div id="app"> <nav> <router-link to="/">首页</router-link> <router-link to="/users">用户管理</router-link> </nav> <main> <router-view /> </main> </div> </template>
7.3 受保护路由(可选扩展) 对于需要登录认证的路由,可以创建 router/guards.ts 并在全局 beforeEach 中使用 Pinia Store:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import { useAuthStore } from '@/stores/useAuthStore' ;import type { NavigationGuardNext , RouteLocationNormalized } from 'vue-router' ;export function authGuard ( to: RouteLocationNormalized, from : RouteLocationNormalized, next: NavigationGuardNext, ) { const authStore = useAuthStore (); if (to.meta .requiresAuth && !authStore.isAuthenticated ) { next ({ name : 'home' , query : { redirect : to.fullPath } }); } else { next (); } }
在 router/index.ts 中注册:
1 2 3 4 import { authGuard } from './guards' ;const router = createRouter ({ });router.beforeEach (authGuard);
8. 全局样式:CSS 变量与基础重置 在 src/styles/variables.css 中定义设计令牌:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 :root { --color-primary : #4f46e5 ; --color-primary-hover : #4338ca ; --color-success : #10b981 ; --color-warning : #f59e0b ; --color-error : #ef4444 ; --color-bg : #f8fafc ; --color-text : #1e293b ; --color-text-secondary : #64748b ; --color-border : #e2e8f0 ; --space-1 : 4px ; --space-2 : 8px ; --space-3 : 12px ; --space-4 : 16px ; --space-6 : 24px ; --space-8 : 32px ; --radius-sm : 4px ; --radius-md : 8px ; --radius-lg : 12px ; --font-family : 'Inter' , system-ui, -apple-system, sans-serif; --font-size-sm : 0.875rem ; --font-size-base : 1rem ; --font-size-lg : 1.125rem ; --font-size-xl : 1.25rem ; --font-size-2xl : 1.5rem ; }
在 src/styles/globals.css 中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @import './variables.css' ;*, *::before , *::after { box-sizing : border-box; margin : 0 ; padding : 0 ; } body { font-family : var (--font-family); font-size : var (--font-size-base); color : var (--color-text); background-color : var (--color-bg); -webkit-font-smoothing : antialiased; } a { color : var (--color-primary); text-decoration : none; } a :hover { color : var (--color-primary-hover); }
课后练习 一、概念自测(选择题 / 填空题)
(单选) Vue 3 项目进行 TypeScript 类型检查时,应使用什么命令? A. tsc --noEmit B. vue-tsc --noEmit C. vite build D. eslint --fix
(单选) 在 Vue 3 项目中,ESLint 的主解析器应使用? A. @typescript-eslint/parser B. babel-eslint C. vue-eslint-parser D. espree
(填空) 在 Vue 3 项目中,可复用的响应式逻辑和副作用应封装为 ______ 函数,放在 composables/ 目录下。
(多选) 关于 Vue 3 + Vite 项目的配置,哪些是正确的? A. tsconfig.app.json 的 include 必须包含 .vue 文件路径。 B. lint-staged 的文件匹配模式需要包含 *.vue 文件。 C. vite.config.ts 中不需要配置 resolve.alias,仅靠 tsconfig.json 的 paths 即可。 D. build 脚本应在 vite build 之前执行 vue-tsc --noEmit。
二、AI 编程任务:编写面向 AI 的提示词 场景 :你需要从零创建一个 Vue 3 + TypeScript + Vite 的企业级项目骨架。要求如下:
使用 pnpm create vite 初始化项目,模板为 vue-ts。
配置 TypeScript 严格模式,@/* 路径别名指向 src/。
配置 ESLint(eslint:recommended + plugin:vue/vue3-recommended + @typescript-eslint/recommended + prettier),解析器使用 vue-eslint-parser。
配置 Prettier(singleQuote: true, semi: true, trailingComma: 'all', printWidth: 100)。
配置 Husky + lint-staged(匹配 *.vue, *.ts, *.tsx 等)。
配置环境变量 VITE_API_BASE_URL(开发与生产不同),并封装 HttpClient 类。
创建完整的目录结构(api/、components/ui/、components/layout/、composables/、pages/、router/、stores/、styles/、types/、utils/)。
安装 Pinia 和 Vue Router 4,创建示例 Store(认证)和路由配置(懒加载首页、用户页、404 页面)。
创建全局 CSS 变量和基础样式重置。
任务要求 :请写出一段完整的中文提示词 ,发送给 AI,使其生成符合上述要求的完整项目初始化的所有配置文件和核心代码文件。提示词中需明确指定 Vue 3 特有的配置项(vue-eslint-parser、vue-tsc、Pinia Setup Store、Vue Router 懒加载、<router-view> 等)。
三、Agent 模式下的提示词示例
你是一个资深前端开发 Agent。请创建一个 Vue 3 + TypeScript + Vite 企业级项目骨架。需要生成/修改以下文件:
使用 pnpm create vite 初始化项目(模板 vue-ts),安装额外依赖:vue-router@4、pinia、pinia-plugin-persistedstate、husky、lint-staged、eslint-plugin-vue、@typescript-eslint/parser、@typescript-eslint/eslint-plugin、eslint-config-prettier、vue-tsc。
tsconfig.app.json:严格模式,paths: { "@/*": ["src/*"] },include 包含 .vue 文件。
vite.config.ts:引入 @vitejs/plugin-vue,resolve.alias 配置 @ 指向 src。
.eslintrc.cjs:extends 包含 plugin:vue/vue3-recommended、@typescript-eslint/recommended、prettier。parser 使用 vue-eslint-parser,parserOptions.parser 为 @typescript-eslint/parser。rules 允许 console.warn/error。
.prettierrc:singleQuote: true,semi: true,trailingComma: 'all',printWidth: 100。
.husky/pre-commit:npx lint-staged。
package.json:lint-staged 配置(匹配 *.{vue,ts,tsx}),scripts 包含 build: "vue-tsc --noEmit && vite build"。
.env.development 和 .env.production:分别设置 VITE_API_BASE_URL。src/vite-env.d.ts 扩展 ImportMetaEnv。
src/api/client.ts:HttpClient 类(GET/POST/PUT/DELETE),自动注入 token。
src/api/user.api.ts:用户 API 封装。
src/stores/useAuthStore.ts:Pinia Setup Store,token/currentUser/loading 状态,login/logout 方法,持久化 token。
src/router/index.ts:Vue Router 4,懒加载首页、用户页、404 页面,afterEach 设置标题。
src/pages/Home/index.vue、src/pages/Users/index.vue、src/pages/NotFound/index.vue:简单的占位页面组件(使用 <script setup lang="ts">)。
src/App.vue:包含 <router-link> 导航和 <router-view />。
src/main.ts:注册 Pinia、Router,引入全局样式。
src/styles/variables.css 和 src/styles/globals.css:全局变量和基础样式。
创建完整目录结构说明(空文件夹:components/ui/、components/layout/、composables/、types/、utils/)。 所有文件添加 JSDoc 注释,确保可直接运行。完成后列出所有文件内容。
课后练习答案 一、概念自测答案
B
解析:Vue 3 项目使用 vue-tsc --noEmit 进行类型检查,它能正确识别 .vue 文件的类型。tsc --noEmit 无法处理 .vue 文件。
C
解析:ESLint 解析 .vue 文件时必须使用 vue-eslint-parser 作为主解析器。@typescript-eslint/parser 作为子解析器处理 <script> 标签内的 TypeScript 代码。
**Composable**(或 useXxx 函数)
解析:Vue 3 中可复用的响应式逻辑封装为 Composable 函数,命名以 use 开头。
A、B、D
解析:C 错误,tsconfig.json 的 paths 仅用于 TypeScript 类型检查,Vite 实际模块解析需要 vite.config.ts 中的 resolve.alias 配置,两者必须同步。
二、AI 编程任务参考答案(提示词示例)
示例提示词 : “请从零创建一个 Vue 3 + TypeScript + Vite 企业级项目骨架。要求:
使用 pnpm create vite 初始化 vue-ts 模板。
TypeScript 严格模式,@/ 别名。
ESLint(vue3-recommended + @typescript-eslint/recommended + prettier)+ Prettier + Husky + lint-staged。
.env 管理 VITE_API_BASE_URL,封装 HttpClient。
目录结构:api/components/composables/pages/router/stores/styles/types/utils。
Pinia Setup Store(认证)+ Vue Router 4(懒加载路由)。
全局 CSS 变量和重置样式。
输出所有配置文件、API 模块、Store、路由、页面组件和样式文件的完整内容。”