一、技术栈简介
- Vue 3:采用 Composition API 与
<script setup>语法,更灵活、逻辑复用更简单。 - Vite:极速的开发服务器与构建工具,基于 ES modules。
- Pinia:Vue 官方推荐的状态管理库,类型安全、轻量且直观。
- TypeScript:为 JavaScript 提供静态类型检查,提升代码健壮性与可维护性。
二、项目初始化
1. 使用 Vite 创建项目
# npm
npm create vite@latest my-vue-app -- --template vue-ts
# yarn
yarn create vite my-vue-app --template vue-ts
# pnpm
pnpm create vite my-vue-app --template vue-ts
进入项目目录并安装依赖:
cd my-vue-app
npm install
2. 安装 Pinia
npm install pinia
# 或
yarn add pinia
三、项目结构组织
推荐的中大型项目结构:
src/
├── assets/ # 静态资源(图片、字体等)
├── components/ # 公共组件
│ └── HelloWorld.vue
├── composables/ # 组合式函数(逻辑复用)
├── layouts/ # 布局组件
├── pages/ # 页面级组件(或 views/)
├── router/ # Vue Router 配置
│ └── index.ts
├── stores/ # Pinia 状态管理
│ ├── counter.ts
│ └── user.ts
├── styles/ # 全局样式(SCSS/CSS)
├── types/ # TypeScript 类型声明
│ └── global.d.ts
├── utils/ # 工具函数
├── App.vue
└── main.ts
四、核心配置详解
1. 注册 Pinia(main.ts)
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router' // 如果有路由
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')
2. TypeScript 配置增强(tsconfig.json)
确保 tsconfig.json 包含以下配置以获得更好的 Vue 支持:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}
3. Vite 配置别名(vite.config.ts)
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
server: {
port: 3000,
open: true,
},
})
五、Pinia 状态管理实战(TypeScript 加持)
1. 定义第一个 Store(stores/counter.ts)
使用 Composition API 风格(推荐,更符合 Vue 3 习惯):
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useCounterStore = defineStore('counter', () => {
// State
const count = ref<number>(0)
// Getters
const doubleCount = computed(() => count.value * 2)
// Actions
function increment() {
count.value++
}
function decrement() {
count.value--
}
return { count, doubleCount, increment, decrement }
})
2. 在组件中使用 Store(<script setup lang="ts">)
<template>
<div>
<p>Count: {{ counter.count }}</p>
<p>Double: {{ counter.doubleCount }}</p>
<button @click="counter.increment">+1</button>
<button @click="counter.decrement">-1</button>
</div>
</template>
<script setup lang="ts">
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
</script>
3. 类型安全的 Actions 与异步操作
Pinia 天然支持 async/await 且类型推断完好:
// stores/user.ts
import { defineStore } from 'pinia'
import { ref } from 'vue'
interface UserInfo {
id: number
name: string
email: string
}
export const useUserStore = defineStore('user', () => {
const user = ref<UserInfo | null>(null)
const loading = ref(false)
async function fetchUser(id: number) {
loading.value = true
try {
const res = await fetch(`/api/users/${id}`)
user.value = await res.json()
} catch (error) {
console.error('获取用户失败', error)
} finally {
loading.value = false
}
}
return { user, loading, fetchUser }
})
组件中使用:
<script setup lang="ts">
import { onMounted } from 'vue'
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
onMounted(() => {
userStore.fetchUser(1)
})
</script>
六、Vue 3 Composition API 与 TypeScript 实践
1. 组件 Props 类型声明
<script setup lang="ts">
interface Props {
title: string
count?: number
items: string[]
}
// 运行时声明 + 类型声明
const props = withDefaults(defineProps<Props>(), {
count: 0,
})
</script>
2. Emits 类型声明
<script setup lang="ts">
interface Emits {
(e: 'update', value: string): void
(e: 'delete', id: number): void
}
const emit = defineEmits<Emits>()
function handleChange(val: string) {
emit('update', val)
}
</script>
3. 模板引用(Template Refs)
<template>
<input ref="inputRef" type="text" />
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const inputRef = ref<HTMLInputElement | null>(null)
onMounted(() => {
inputRef.value?.focus()
})
</script>
4. 组合式函数(Composables)封装逻辑
创建 composables/useCounter.ts:
import { ref } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const increment = () => count.value++
const decrement = () => count.value--
return { count, increment, decrement }
}
七、路由集成(Vue Router + TypeScript)
安装路由:
npm install vue-router@4
配置 router/index.ts:
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'home',
component: () => import('@/pages/HomePage.vue'),
},
{
path: '/about',
name: 'about',
component: () => import('@/pages/AboutPage.vue'),
},
]
const router = createRouter({
history: createWebHistory(),
routes,
})
export default router
在 main.ts 中引入并挂载路由(见前文)。
八、环境变量与多环境配置
Vite 使用 .env 文件管理环境变量,通过 import.meta.env 访问。
创建文件:
.env(所有环境共享).env.development(开发环境).env.production(生产环境)
示例 .env.development:
VITE_API_BASE_URL=http://localhost:3000/api
在代码中使用(已具备类型提示):
const baseURL = import.meta.env.VITE_API_BASE_URL
若需增强 TypeScript 类型提示,在 src/vite-env.d.ts 中添加:
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_BASE_URL: string
// 更多环境变量...
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
九、代码规范与格式化(ESLint + Prettier)
1. 安装依赖
npm install -D eslint prettier eslint-plugin-vue @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-prettier eslint-plugin-prettier
2. 配置 .eslintrc.cjs
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
'plugin:vue/vue3-recommended',
'eslint:recommended',
'@vue/typescript/recommended',
'plugin:prettier/recommended',
],
parserOptions: {
ecmaVersion: 2021,
},
rules: {
// 自定义规则
},
}
3. 配置 .prettierrc
{
"semi": false,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "es5"
}
十、构建与部署
1. 构建生产版本
npm run build
构建产物默认输出至 dist 目录。
2. 预览构建结果
npm run preview
3. 部署到静态服务器(如 Nginx)
将 dist 文件夹内容上传至服务器,并配置 Nginx:
server {
listen 80;
server_name your-domain.com;
root /var/www/vue-app/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
4. 环境变量替换
Vite 在构建时会根据模式自动替换 import.meta.env 中的变量。
十一、常见问题与最佳实践
1. Pinia 状态持久化
可结合 pinia-plugin-persistedstate 插件实现:
npm install pinia-plugin-persistedstate
// main.ts
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
在 Store 中启用:
export const useUserStore = defineStore('user', () => {
// ...
}, {
persist: true, // 或配置对象
})
2. 按需自动导入(unplugin-auto-import)
减少手动导入 ref、computed 等:
npm install -D unplugin-auto-import
在 vite.config.ts 中配置:
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
plugins: [
AutoImport({
imports: ['vue', 'vue-router', 'pinia'],
dts: 'src/auto-imports.d.ts', // 生成类型声明文件
}),
],
})
3. 组件库按需引入(如 Element Plus)
npm install element-plus
配置自动导入:
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
plugins: [
Components({
resolvers: [ElementPlusResolver()],
}),
],
})
十二、总结
Vue 3 + Vite + Pinia + TypeScript 的组合为现代前端开发提供了极致的开发体验:
- Vite 带来秒级热更新与快速构建。
- Pinia 以简洁的 API 和完美 TypeScript 支持成为状态管理首选。
- TypeScript 为大型项目提供类型安全保障。
- Composition API 让逻辑复用与代码组织更加优雅。
遵循上述流程与规范,即可高效、稳健地搭建企业级 Vue 3 应用。
———个人观点、仅供参考———