Vue 3 + Vite + Pinia + TypeScript 开发流程全指南

7 阅读3分钟

一、技术栈简介

  • 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)

减少手动导入 refcomputed 等:

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 应用。

———个人观点、仅供参考———