本文将从零开始详解 Vue 3 + TypeScript 项目的完整构建流程,涵盖从环境准备到生产部署的全过程。
pnpm create vite@latest
选择配置:
✔ Project name: vue3-ts-demo
✔ Framework: Vue
✔ Variant: TypeScript
├── public/ # 静态资源
├── src/
│ ├── assets/ # 静态资源
│ ├── components/ # 组件
│ ├── router/ # 路由配置
│ ├── stores/ # Pinia状态管理
│ ├── views/ # 页面组件
│ ├── App.vue # 根组件
│ └── main.ts # 入口文件
├── .eslintrc.cjs # ESLint配置
├── tsconfig.json # TypeScript配置
└── vite.config.ts # Vite配置
修改 tsconfig.json
:
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"strict": true,
"moduleResolution": "node",
"types": ["vite/client"],
"paths": {
"@/*": ["./src/*"]
}
}
}
安装依赖:
pnpm add -D eslint eslint-plugin-vue @typescript-eslint/parser @typescript-eslint/eslint-plugin prettier eslint-config-prettier
.eslintrc.cjs
配置示例:
module.exports = {
root: true,
env: { browser: true, es2021: true },
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended',
'@vue/typescript/recommended',
'prettier'
],
parserOptions: {
ecmaVersion: 'latest',
parser: '@typescript-eslint/parser'
}
}
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
props: {
title: {
type: String,
required: true
}
}
})
</script>
<script setup lang="ts">
interface Props {
title: string
count?: number
}
const props = defineProps<Props>()
const emit = defineEmits<{
(e: 'update', value: number): void
}>()
</script>
interface
定义复杂类型type
定义联合类型/工具类型pnpm add pinia @pinia/nuxt
// stores/counter.ts
import { defineStore } from 'pinia'
interface CounterState {
count: number
}
export const useCounterStore = defineStore('counter', {
state: (): CounterState => ({
count: 0
}),
actions: {
increment() {
this.count++
}
}
})
pnpm add vue-router @types/vue-router
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
declare module 'vue-router' {
interface RouteMeta {
requiresAuth?: boolean
}
}
const routes = [
{
path: '/',
component: () => import('@/views/Home.vue'),
meta: { requiresAuth: true }
}
]
export const router = createRouter({
history: createWebHistory(),
routes
})
// utils/request.ts
import axios from 'axios'
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE,
timeout: 10000
})
// 请求拦截器
service.interceptors.request.use(config => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
// 响应拦截器
service.interceptors.response.use(
response => response.data,
error => Promise.reject(error)
)
export default service
pnpm build
// vite.config.ts
export default defineConfig({
base: process.env.NODE_ENV === 'production'
? '/your-sub-path/'
: '/'
})
FROM nginx:alpine
COPY dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
@types/
类型包composables/
目录组织VITE_
前缀暴露变量通过以上流程可快速搭建规范的 Vue 3 + TypeScript 项目。实际开发中建议结合具体需求添加单元测试(Vitest)、状态持久化(pinia-plugin-persistedstate)等扩展功能,持续保持项目代码的类型安全和架构清晰。