第 13 节:Vue 3 + TypeScript 项目初始化

0 阅读6分钟

第 13 节:Vue 3 + TypeScript 项目初始化

阅读时间:约 7 分钟
难度级别:实战
前置知识:Node.js、npm/yarn、Vue 基础

本节概要

通过本节学习,你将掌握:

  • 使用 Vite 快速创建 Vue 3 + TypeScript 项目
  • 配置项目结构和开发环境
  • 集成 Naive UI 组件库
  • 配置 Axios 和 HTTP 客户端
  • 实现基础的路由和布局
  • 项目的构建和部署配置

引言

从本节开始,我们将进入前端开发部分。Vue 3 配合 TypeScript 和 Vite,能够提供出色的开发体验和性能。本节我们将学习如何初始化项目并配置开发环境。

前端使用 Vue 3 + TypeScript + Vite 构建。本文将介绍如何从零搭建前端开发环境。

🎯 本章目标

完成后,你将拥有:

  • ✅ Vue 3 + TypeScript 项目
  • ✅ Vite 构建配置
  • ✅ Naive UI 组件库
  • ✅ Tailwind CSS 样式
  • ✅ Axios HTTP 客户端
  • ✅ 开发服务器运行

🚀 创建项目

Step 1: 使用 Vite 创建项目

与 AI 对话:

使用 Vite 创建一个 Vue 3 + TypeScript 项目:
- 项目名称:frontend
- 使用 TypeScript
- 使用 Vue 3
- 配置 Vite

执行命令:

# 创建项目
npm create vite@latest frontend -- --template vue-ts

# 进入项目目录
cd frontend

# 安装依赖
npm install

Step 2: 安装必要依赖

# UI 组件库
npm install naive-ui

# HTTP 客户端
npm install axios

# Markdown 渲染
npm install marked

# 代码高亮
npm install highlight.js

# 样式框架
npm install -D tailwindcss @tailwindcss/vite

# TypeScript 类型
npm install -D @types/node

最终的 package.json:

{
  "name": "frontend",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc -b && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@tailwindcss/vite": "^4.1.18",
    "axios": "^1.13.2",
    "highlight.js": "^11.11.1",
    "marked": "^17.0.1",
    "tailwindcss": "^4.1.18",
    "vue": "^3.5.24"
  },
  "devDependencies": {
    "@types/node": "^24.10.1",
    "@vitejs/plugin-vue": "^6.0.1",
    "@vue/tsconfig": "^0.8.1",
    "naive-ui": "^2.43.2",
    "typescript": "~5.9.3",
    "vite": "^7.2.4",
    "vue-tsc": "^3.1.4"
  }
}

⚙️ 配置 Vite

vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwindcss from '@tailwindcss/vite'

// Vite 配置文档: https://vite.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    tailwindcss()
  ],
  server: {
    port: 5173,
    proxy: {
      '/api': {
        target: 'http://localhost:8000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
})

配置说明:

  • plugins: 使用 Vue 和 Tailwind CSS 插件
  • server.port: 开发服务器端口
  • server.proxy: API 代理配置,将 /api 请求转发到后端

📝 配置 TypeScript

tsconfig.json

{
  "files": [],
  "references": [
    { "path": "./tsconfig.app.json" },
    { "path": "./tsconfig.node.json" }
  ]
}

tsconfig.app.json

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetectionKind": "force",
    "noEmit": true,
    "jsx": "preserve",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true
  },
  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}

🎨 配置 Naive UI

src/main.ts

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'

// Naive UI 组件库
import {
  create,
  NButton,
  NCard,
  NInput,
  NSpace,
  NLayout,
  NLayoutHeader,
  NLayoutContent,
  NScrollbar,
  NSpin,
  NAvatar,
  NIcon,
  NEmpty,
  NMessageProvider,
} from 'naive-ui'

const naive = create({
  components: [
    NButton,
    NCard,
    NInput,
    NSpace,
    NLayout,
    NLayoutHeader,
    NLayoutContent,
    NScrollbar,
    NSpin,
    NAvatar,
    NIcon,
    NEmpty,
    NMessageProvider,
  ]
})

const app = createApp(App)
app.use(naive)
app.mount('#app')

按需引入的优势:

  • 减小打包体积
  • 提高加载速度
  • 只引入需要的组件

🌐 配置 Axios

src/api/request/axios.ts

import axios from 'axios'

const request = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000',
  timeout: 60000,
})

// 请求拦截器
request.interceptors.request.use(
  (config) => {
    // 可以在这里添加 token
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

// 响应拦截器
request.interceptors.response.use(
  (response) => {
    return response
  },
  (error) => {
    // 统一错误处理
    console.error('API Error:', error)
    return Promise.reject(error)
  }
)

export default request

src/api/request/index.ts

import type { AxiosProgressEvent, AxiosResponse, GenericAbortSignal } from 'axios'
import request from './axios'

export interface HttpOption {
  url: string
  data?: any
  method?: string
  headers?: any
  onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void
  signal?: GenericAbortSignal
  responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'
}

export interface Response<T = any> {
  data: T
  message: string | null
  status: string
}

function http<T = any>(
  { url, data, method, headers, onDownloadProgress, signal, responseType }: HttpOption,
) {
  const successHandler = (res: AxiosResponse<Response<T>>) => {
    if (res.status === 200)
      return res.data
    return Promise.reject(res.data)
  }

  const failHandler = (error: Response<Error> | any) => {
    return Promise.reject(error)
  }

  method = method || 'GET'
  const params = Object.assign(typeof data === 'function' ? data() : data ?? {}, {})

  if (method === 'GET')
    return request.get(url, { params, signal, onDownloadProgress, responseType }).then(successHandler, failHandler)
  else if (method === 'POST')
    return request.post(url, params, { headers, signal, onDownloadProgress, responseType }).then(successHandler, failHandler)
  else
    throw new Error('不支持的请求方式')
}

export function post<T = any>(options: HttpOption): Promise<Response<T>> {
  return http<T>({ ...options, method: 'POST' })
}

export function get<T = any>(options: HttpOption): Promise<Response<T>> {
  return http<T>({ ...options, method: 'GET' })
}

export default post

🎨 配置样式

src/style.css

@import 'tailwindcss';

:root {
  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
  line-height: 1.5;
  font-weight: 400;

  color-scheme: light dark;
  color: rgba(255, 255, 255, 0.87);
  background-color: #242424;

  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  margin: 0;
  display: flex;
  place-items: center;
  min-width: 320px;
  min-height: 100vh;
}

#app {
  width: 100%;
  height: 100vh;
}

src/styles/markdown.css

/* Markdown 内容样式 */
.markdown-content {
  line-height: 1.6;
}

.markdown-content h1,
.markdown-content h2,
.markdown-content h3 {
  margin-top: 1.5em;
  margin-bottom: 0.5em;
  font-weight: 600;
}

.markdown-content p {
  margin: 0.8em 0;
}

.markdown-content code {
  background-color: #f4f4f4;
  padding: 0.2em 0.4em;
  border-radius: 3px;
  font-family: 'Courier New', monospace;
  font-size: 0.9em;
}

.markdown-content pre {
  background-color: #282c34;
  padding: 1em;
  border-radius: 5px;
  overflow-x: auto;
  margin: 1em 0;
}

.markdown-content pre code {
  background-color: transparent;
  padding: 0;
  color: #abb2bf;
}

.markdown-content table {
  border-collapse: collapse;
  width: 100%;
  margin: 1em 0;
}

.markdown-content th,
.markdown-content td {
  border: 1px solid #ddd;
  padding: 8px 12px;
  text-align: left;
}

.markdown-content th {
  background-color: #f8f9fa;
  font-weight: 600;
}

🏃 运行项目

启动开发服务器

npm run dev

预期输出:

  VITE v7.2.4  ready in 500 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: http://192.168.1.100:5173/

构建生产版本

npm run build

预览生产版本

npm run preview

📁 项目结构

frontend/
├── public/              # 静态资源
│   └── vite.svg
├── src/
│   ├── api/            # API 接口
│   │   ├── request/    # Axios 封装
│   │   ├── chat.ts     # 聊天 API
│   │   └── workflow.ts # Workflow API
│   ├── components/     # Vue 组件
│   │   ├── Layout.vue
│   │   ├── ChatPage.vue
│   │   └── WorkflowPage.vue
│   ├── styles/         # 样式文件
│   │   └── markdown.css
│   ├── App.vue         # 根组件
│   ├── main.ts         # 入口文件
│   └── style.css       # 全局样式
├── index.html          # HTML 模板
├── package.json        # 依赖配置
├── tsconfig.json       # TS 配置
├── vite.config.ts      # Vite 配置
└── .env                # 环境变量

🔧 环境变量

.env

# API 基础 URL
VITE_API_BASE_URL=http://localhost:8000

# 应用标题
VITE_APP_TITLE=Ask SQL

使用环境变量

// 在代码中使用
const apiUrl = import.meta.env.VITE_API_BASE_URL
const appTitle = import.meta.env.VITE_APP_TITLE

💡 Vibe Coding 要点

1. 使用脚手架

与 AI 对话:
"使用 Vite 创建 Vue 3 + TypeScript 项目,
并配置 Naive UI、Axios、Tailwind CSS"

2. 按需配置

第1步:创建基础项目
第2步:安装必要依赖
第3步:配置 Vite
第4步:配置 TypeScript
第5步:配置组件库
第6步:配置 HTTP 客户端

3. 验证配置

# 每完成一步配置,立即验证
npm run dev

# 检查是否有错误
# 访问 http://localhost:5173

本节小结

本节我们完成了前端项目的初始化:

  1. 项目创建:使用 Vite 创建了 Vue 3 + TypeScript 项目
  2. UI 组件库:集成了 Naive UI,提供丰富的组件
  3. HTTP 客户端:封装了 Axios,统一处理请求和响应
  4. 路由配置:使用 Vue Router 实现页面导航
  5. 布局组件:创建了基础的 Layout 组件
  6. 样式配置:配置了 Tailwind CSS 和全局样式
  7. 开发环境:配置了 Vite 和 TypeScript

现在我们有了完整的前端开发环境,可以开始实现具体功能。

思考与练习

思考题

  1. 为什么选择 Vite 而不是 Webpack?各有什么优劣?
  2. TypeScript 在 Vue 3 项目中的价值是什么?
  3. 如何在组件库和自定义组件之间做选择?
  4. 前端项目的目录结构应该如何组织?

实践练习

  1. 扩展项目结构

    • 添加 composables/ 目录用于组合式函数
    • 添加 stores/ 目录用于状态管理
    • 添加 types/ 目录用于类型定义
  2. 优化 HTTP 客户端

    • 添加请求拦截器
    • 添加响应拦截器
    • 实现请求重试机制
  3. 主题配置

    • 配置 Naive UI 的主题
    • 支持深色模式切换
    • 自定义主题颜色
  4. 开发工具

    • 配置 ESLint 和 Prettier
    • 配置 Git Hooks
    • 配置 VS Code 插件

上一节第 12 节:后端测试与调试
下一节第 14 节:构建聊天交互界面