Day1 从 0 搭建 VueDemo Web Admin 项目环境:技术栈、插件链与自动化脚本全解析

1. 引言:为什么要从基础环境讲起

这篇系列的目标是记录我如何从 0 构建起 vueweb-demo-admin 项目,并细致拆解每一个模块、每一个关键配置。第一天先从最容易忽略但决定项目质量的"环境搭建"入手,帮助同学掌握从 Node 到质量校验的完整流程。

我的目标是:

  1. 梳理项目选型决策,让前端小白知道为什么选 Vue 3 + Vite + Pinia。
  2. 告诉你我如何组合 Vite 插件链,把组件、图标、路由、样式都管起来。
  3. 展示自动化脚本与钩子,确保团队开发时无脑执行即可达成统一规范。

这系列会持续更新,从目录/布局、组件库、权限、测试、部署,到自动化脚本、性能优化。今天的篇章是"基础准备",你只需耐心读完,环境就可以跑起来。
注:系列还会覆盖「接口封装与范型设计、请求/响应拦截、vue-request 最佳实践、API 自动化脚本与持续集成、性能与体验优化」等主题;本文聚焦把环境"一次性跑通",为后续章节打牢地基。


2. 技术栈拉通(表格说明)

维度 内容 说明
Node 版本 `^20.19.0
包管理器 pnpm(v9+) 安装快速、软链接能力好,适合有多个项目的开发者。此外 pnpmnode-linker=hoisted 提升 IDE 兼容性。
核心框架 Vue 3 + Pinia + Vue Router + TypeScript 全面选用 Composition + TS,开箱即用的类型支持。
UI、请求、状态 Element Plus、axios/vue-request、pinia-plugin-persistedstate 组件库 + 请求封装 + 状态持久化组合,满足中后台快开发需求。
工具链 Vite + Vitest + Playwright + ESLint + Prettier + Oxlint + TailwindCSS 从构建到测试再到格式校验,构成"开发→CI"的闭环。

2.1 0-1 安装步骤(命令+路径)

  1. Node 版本 & 工具 :使用 nvm install 20.19 && nvm use 20.19(或 volta install node@20.19) 并执行 node -v 验证。
  2. 克隆项目 + 安装依赖 :如果你还没仓库,git clone <repo>,进入根目录后运行 pnpm install。依赖会写入 package.json,pnpm-lock.json 和 node_modules 会自动生成。
  3. 配置全局工具(可选) :安装 Husky pnpm dlx husky-init && pnpm install(仓库已有 prepare 脚本会自动生效),确保 .husky/ 目录含 pre-commit 触发 lint-staged。这里说明一下为什么使用Husky,因为Husky是 Git 钩子管理工具,用于在 Git 操作时自动执行脚本 。最常用的是 pre-commit 钩子,在提交代码前自动执行代码检查(lint、format 等),确保提交的代码符合规范

husky 作用 Git 钩子管理工具,在 Git 操作时自动执行脚本。本项目中用于在提交代码前自动执行 lint-staged(prettier + eslint + oxlint),确保提交的代码符合规范。

.husky 文件位置 项目根目录下的 .husky/ 文件夹,当前包含:

  • pre-commit:提交前钩子,执行 npx lint-staged
  • _/:Husky 配置目录

这个过程的目录影响:

复制代码
你的项目根目录
├── package.json    # scripts + deps
├── pnpm-lock.yaml  # 中台依赖锁
├── .husky/         # hook 配置
└── node_modules/   # pnpm 安装的依赖(gitignore)

2.2 为什么要按这个顺序

  • Node 版本:中后台项目依赖较多,较新版本能保证 vite+esbuild 兼容,通过 .nvmrc/.node-version 明确版本。
  • pnpm:npm/yarn 在依赖冲突时容易"吃"空间,pnpm 通过 symlink 保留一致性,尤其配合 CI 速度明显。
  • Husky + lint-staged:让格式化/静态检查在提交阶段发生,避免"别人没看见 lint 报错"的低效回滚。

3. Vue 3 项目从 0 到 1 初始化

vueweb-demo-admin 是一个 Vue 3 + Vite + TypeScript 的中后台模板,下面是严格一步到位的初始化流程,确保你克隆后可以直接运行:

  1. 全局准备 :确认 Node 版本正确(>=20.19),执行 nvm install 20.19 && nvm use 20.19,然后 node -v / pnpm -v

  2. 脚手架创建 (仅当你还没项目):

    bash 复制代码
    pnpm create vite@latest vueweb-demo-admin -- --template vue-ts
    cd vueweb-demo-admin

    该命令会自动生成 package.jsonvite.config.tstsconfig.jsonsrc/main.ts 等基础文件;如果你已经克隆项目略过该步。

  3. 安装依赖 (克隆后或者刚创建):

    bash 复制代码
    pnpm install
    pnpm dlx husky install  # 确保 husky hooks 正常
    pnpm run prepare        # 触发 package.json 中的 husky 安装(pre-commit)
  4. 确认源码入口

    • src/main.ts:挂载 Pinia、路由、Element Plus、全局样式。
    • src/App.vue:放置 <router-view />,需要引入 src/layouts/MainLayout.vue
    • src/components/:存放通用控件;配合 unplugin-vue-components 实现自动注册。
  5. 配置 tsconfig + alias :初始 tsconfig.app.json 中已经指定 @/*,并在 vite.config.ts 里用 fileURLToPath(new URL('./src', import.meta.url)) 映射,写法示例在后文。

  6. 添加常用目录 (若脚手架没有):

    bash 复制代码
    mkdir -p src/assets/styles src/layouts src/common/hooks
    touch src/assets/styles/element/variables.scss

    这些目录搭配 vite.config.ts 里的 scss.additionalData 可以注入全局变量。

根目录可视化结构图

  • .husky/:Git 钩子,当前启用 pre-commit 触发 lint-staged,提交前自动执行 prettier/eslint/oxlint。
  • .trae/:文档与规则存放(如项目规则、实现文档),用于沉淀过程与规范。
  • .windsurf/:工作流与文章草稿等辅助资料(本文档所在目录)。
  • dist/ :构建产物目录,pnpm run build 后生成,用于部署。
  • e2e/:端到端测试目录(Playwright),覆盖关键用户路径与回归场景。
  • node_modules/:依赖安装目录(由 pnpm 管理,已被 .gitignore 忽略)。
  • plugins/ :Vite 自定义插件或项目插件放置区,如 vite-plugin-router-named-map.ts
  • public/:静态资源根目录,构建时原样拷贝(如 favicon、静态脚本/样式)。
  • scripts/ :自动化脚本目录,如 build.sh(部署脚本)、generator-api.js(根据 OpenAPI 生成类型)。
  • src/:业务源码目录(组件、路由、状态、样式、页面等),开发的主要战场。
  • auto-imports.d.ts / components.d.ts:由 AutoImport/Components 插件生成的类型声明,支持自动导入与按需注册。
  • eslint.config.ts / .prettierrc.json / .oxlintrc.json:代码质量与风格校验配置,保证团队规范统一。
  • playwright.config.ts / vitest.config.ts:E2E 与单元测试配置文件。
  • tsconfig.json *:TypeScript 编译配置(含 app/node/vitest 等子配置),paths 与 Vite alias 对齐。
  • vite.config.ts:Vite 核心配置(插件链、别名、构建选项等)。
  • package.json / pnpm-lock.yaml:脚本与依赖清单;锁定依赖版本,确保多人环境一致。

3.1 为什么按这个节点顺序

  • pnpm create vite 生成基础项目,后续都围绕 src/main.ts、插件组合进行扩展。
  • pnpm install + husky install 让依赖与 git hook 立刻就位,避免后续开发时 lint-staged 失效。
  • 手动创建 assets/stylescommon/hooks 等目录是为了配合后续的组件/样式体系,从根目录开始把结构整理好,避免后续代码把文件散落。

配置图示

复制代码
Node 20+  
   ↓  
pnpm install + husky 安装  
   ↓  
┌────────────┬──────────────┬────────────────┐
│ Vite (插件) │ TypeScript  │ ESLint/Prettier │
│ (vue/jsx,   │ strict +    │ lint-staged     │
│ auto import,│ paths,      │ + oxlint        │
│ svg icons)  │ alias)      │                 │
└────────────┴──────────────┴────────────────┘
   ↓
Scripts:dev / build / test / lint / format / deploy

3. Vite 插件链拆解 vite.config.ts

ts 复制代码
plugins: [
  vue(),
  vueJsx(),
  vueDevTools(),
  tailwindcss(),
  AutoImport({ resolver: ElementPlusResolver({ importStyle: 'sass' }) }),
  Components({ resolver: ElementPlusResolver({ importStyle: 'sass' }) }),
  GenerateComponentName(...),
  routerNamedMapPlugin(),
  createSvgIconsPlugin({ iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')] }),
]
  • AutoImport + Components:按需/自动注册 Element Plus+常用方法,提高组件开发效率。
  • GenerateComponentName + routerNamedMapPlugin:多布局全局统一命名,方便调试和定位目录。
  • svg-icons:集中管理所有 svg,避免运行时动态请求。
  • tailwindcss + SCSS additionalData:支持设计系统变量、暗夜主题、动画样式、和 Element 基础样式同步。

源码 .vue/.ts/.tsx
vue
vueJsx
vueDevTools
tailwindcss
AutoImport

ElementPlusResolver
Components

ElementPlusResolver
GenerateComponentName
routerNamedMapPlugin
createSvgIconsPlugin
构建输出

插件说明

  • vue / vueJsx:处理 .vue 单文件组件与 JSX 语法
  • vueDevTools:开发时提供 Vue DevTools 调试支持
  • tailwindcss:编译 TailwindCSS 类名,支持设计系统与暗夜主题
  • AutoImport:自动导入 Element Plus 组件与常用 API(ref、computed 等)
  • Components:按需注册 Element Plus 组件,减少手动 import
  • GenerateComponentName:多布局全局统一命名,方便调试
  • routerNamedMapPlugin:路由命名映射,提升路由可维护性
  • createSvgIconsPlugin:集中管理 SVG 图标,打包为 Sprite

4. TypeScript 配置说明 tsconfig.app.json

json 复制代码
{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "compilerOptions": {
    "strict": true,
    "skipLibCheck": true,
    "noImplicitAny": false,
    "strictNullChecks": false,
    "paths": { "@/*": ["./src/*"] }
  }
}
  • 继承 Vue 官方配置,默认包含 DOM typings。
  • strict: true 强制检查,但为了兼容第三方库把 noImplicitAny/strictNullChecks 适当关闭(实际运行时用 Pinia + API typing 补足)。
  • paths + Vite alias 统一 @ 访问 src

TS 配置与 Vite Alias 关系图

tsconfig.app.json

paths: @/* → ./src/*
TypeScript

编译时解析
vite.config.ts

resolve.alias: @ → /src
Vite

构建时解析
代码中

import '@/store'
实际路径

./src/store

配置对应关系

  • tsconfig.app.jsonpaths: { "@/*": ["./src/*"] } - TypeScript 编译时识别 @ 别名
  • vite.config.tsresolve.alias: { '@': '/src' } - Vite 构建时解析 @ 别名
  • 代码中使用import '@/store' - 统一使用 @ 访问 src 目录下的文件


5. 自动化脚本 & 代码质量屏障 package.json

  • dev:启动 Vite 开发服务器。

  • build:调用 type-checkbuild-only,确保构建前类型通过。

  • test:unit/test:e2e:Vitest + Playwright 保证单元与端到端覆盖。

  • lint/format:统一 ESLint、Prettier、oxlint。但我们还在 lint-staged + husky 里继续发力:

    lint-staged:
    *.{vue,ts,js,tsx,jsx}:
    1. prettier --write
    2. eslint --fix --cache
    3. oxlint --fix

这意味着每次 git commit 都会先执行上面三步,CI 环境只需跑一次 pnpm run lint 即可。

发布图/流程建议

图 1:Git 提交流程与代码质量检查

git add
git commit
husky pre-commit 钩子触发
lint-staged 执行
prettier --write
eslint --fix --cache
oxlint --fix
提交成功

说明 :每次 git commit 都会自动触发 husky pre-commit 钩子,执行 lint-staged 进行 prettier、eslint、oxlint 三步检查,确保代码质量。

图 2:开发到部署脚本流程

UAT 环境
生产环境
开发阶段

pnpm run dev
构建阶段

pnpm run build
部署环境
pnpm run deploy:uat

scripts/build.sh
pnpm run deploy:prod

VERSION=prod scripts/build.sh
构建产物
部署上线

说明

  • pnpm run dev:启动开发服务器
  • pnpm run build:构建生产版本(包含类型检查)
  • pnpm run deploy:uat:使用 scripts/build.sh 部署到 UAT 环境
  • pnpm run deploy:prod:设置 VERSION=prod 后使用 scripts/build.sh 部署到生产环境

5.1 自动化脚本配置路径

  • scripts 位于 package.json 根目录,自动可见;build.sh 位于 scripts/build.sh(用来区分 UAT/PROD)。
  • lint-stagedpackage.json 里的字段,配合 husky 目录里 pre-commit 统一激活。可以打开 .husky/pre-commit 查看 pnpm run lint-staged 的命令链。
  • TypeScript 类型检查依赖 tsconfig.app.json(位于项目根),vue-tscvite build 会引用这份配置。

这些文件位置意味:

复制代码
root/
├── package.json        # 脚本入口 + lint-staged
├── scripts/build.sh    # 发布脚本(prod/uat)
├── .husky/pre-commit    # 启动 lint-staged
├── tsconfig.app.json   # Vue + TS 约束
└── vite.config.ts      # 插件 + alias 配置

5.2 作用说明

  • build.sh:打包前先加载 VERSION/NODE_ENV,再调用 pnpm run build:prod,兼容多环境部署。
  • lint-stagedprettier + eslint + oxlint:三个工具顺序由轻到重,prettier 先格式,eslint 再审,最后 oxlint 为代码规范(例如空格/格式)。
  • tsconfig + type-check:提前通过 vue-tsc,避免构建时报错,尤其面向 Pinia 状态、接口类型。

5.3 API 请求层实践:封装范型 + 拦截器

中后台系统的"数据层韧性"很重要,建议将 axios 封装成统一的请求实例,配合 TypeScript 范型定义响应体,集中处理鉴权、错误与日志。

ts 复制代码
// api/http.ts(示例)
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'

// 统一后端响应结构(可根据你的后端调整)
export interface ApiResp<T = unknown> {
  code: number
  message: string
  data: T
}

const http = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 15000,
})

// 请求拦截:注入 Token、时区(使用北京时间)、traceId 等
http.interceptors.request.use((config) => {
  const token = localStorage.getItem('token')
  if (token) config.headers.Authorization = `Bearer ${token}`
  config.headers['X-Timezone'] = 'Asia/Shanghai'
  return config
})

// 响应拦截:统一 code 处理、错误提示、数据解包
http.interceptors.response.use(
  (resp: AxiosResponse<ApiResp>) => {
    const { code, data, message } = resp.data ?? {}
    if (code === 0) return data as any
    // 可以在此处统一上报/弹窗
    return Promise.reject(new Error(message || '请求失败'))
  },
  (error) => {
    // 这里可增加网络错误、超时、重试等策略
    return Promise.reject(error)
  }
)

// 具备范型的请求函数:返回严格类型
export function request<T = unknown>(config: AxiosRequestConfig) {
  return http.request<any, T>(config)
}

// 业务 API 示例
export function getUserDetail(id: string) {
  return request<{ id: string; name: string }>({ url: `/user/${id}`, method: 'get' })
}

要点:

  • 范型解包request<any, T> 让调用方拿到"已解包"的 T,无需在业务层再访问 resp.data
  • 拦截器单一职责:请求阶段处理"上下文信息"(token、时区)、响应阶段处理"协议一致性"(code、message、data)。
  • 错误策略可插拔:例如在响应拦截统一注入"未登录跳转"、"权限不足提示"、"网络重试"等。

5.4 vue-request 使用指南(配合范型 + 缓存/并行/轮询)

vue-request 提供请求状态管理与自动重试、轮询、缓存等能力,配合上面的 request<T> 更丝滑:

ts 复制代码
// views/User.vue(示例)
import { useRequest } from 'vue-request'
import { getUserDetail } from '@/api/http'

const { data, loading, error, refresh } = useRequest(() => getUserDetail('10001'), {
  manual: false,           // 进入页面自动请求
  cacheKey: 'user#10001',  // 简易缓存提升二次进入性能
  staleTime: 5 * 60 * 1000,
  retryCount: 2,           // 弱网自动重试
})

// data.value 将是 { id: string; name: string }

常用技巧:

  • 依赖变更自动刷新 :将 () => getUserDetail(userId.value) 作为 service,结合 watch/computed 动态刷新。
  • 并行与依赖请求 :用多个 useRequest,或在 onSuccess 链式触发下一个。
  • 表单提交useRequest(service, { manual: true }) + run(params) 配合按钮提交,具备 loading 与错误态。

5.5 scripts 目录导览:自动化更新 API 与发布

项目根目录下的 scripts/ 用于承载"能让团队复用的自动化动作"。

  • scripts/generator-api.js :根据 OpenAPI/Swagger 生成 TypeScript 类型映射(ApiType)与接口声明(interface),输出到 src/types/api.d.ts,避免手写类型与路径出错。

    • 适用场景:后端频繁变更接口;希望前端类型自动对齐,减少回归成本。

    • 基本用法:

      bash 复制代码
      pnpm run gen:api   # package.json 中配置的命令(示例),执行后会在约定目录生成/更新 API 文件
    • 推荐接入方式:

      • 在 CI 或本地 pre-commit 前运行一次,保障分支内类型正确。
      • 生成位置与命名规范清晰,配合 @/api/* 的 barrel 导出,减少业务 import 路径复杂度。
  • scripts/build.sh:统一 UAT/PROD 打包逻辑,注入环境变量与版本号,保证构建产物一致性并可追溯。

最佳实践:

  • 所有脚本在 package.jsonscripts 中提供"易记名",并配上简短注释;
  • 输出日志中包含开始/结束/关键产物路径,方便排障;
  • 失败时返回非 0 状态码,让 CI 能够感知并中断。

6. 今日总结 & 明日预告

  1. 今天掌握了 Node + pnpm + Vite + TypeScript + ESLint + Prettier 三位一体的开发基础环境;
  2. 了解了插件流程、自动注册、svg 管理与全局样式方案;
  3. 配置了自动化脚本与 git 钩子,让开发流程可重复可复用。

明日预告:下篇继续拆解项目目录与路由结构,讲如何做多布局与权限路由守卫;欢迎评论「你最想要的下一期模块」并留下你的点赞/收藏!


相关推荐
JAVA面经实录9172 小时前
Java核心底层原理全集(终版无遗漏·生产级PDF)
java·开发语言·学习
wordbaby2 小时前
React 自定义 Hook 实践:如何优雅管理复杂列表的筛选状态?
前端
xuankuxiaoyao2 小时前
Vue.js 插槽、作用域插槽、商品、阶段案例
android·vue.js·flutter
EF@蛐蛐堂2 小时前
TanStack NPM攻击 揭秘及应对方案
前端·vue.js·npm·安全威胁分析
GISer_Jing2 小时前
GIS论述-6大核心技术方向全解II
学习·考研·arcgis
恋猫de小郭2 小时前
终于,Flutter 修复 Android 中文字体异常,但是很草台,不知怎么吐槽
android·前端·flutter
DataBuildWorld2 小时前
Claude Code 从入门到精通
学习
nashane2 小时前
HarmonyOS 6学习:超大分辨率图片压缩与长截图生成优化实践
学习·华为·harmonyos
Cobyte2 小时前
11.响应式系统演进:深入剖析 computed 实现原理与性能优化实践(Vue3.3)
前端·javascript·vue.js