Vite 项目脚手架与工程化起步:从 create-vite 到可维护的前端工程

以 create-vite 为起点,从零搭建一个工程化完备的 Vite 项目:模板选择与目录结构、依赖管理与脚本设计、ESLint + Prettier + Husky + lint-staged 代码质量工具链、路径别名与基础配置,以及从模板到可维护工程的演进路径。

引言

新建一个前端项目的瞬间,开发者通常面临两难:手动搭脚手架要面对「配置地狱」,而全盘依赖模板又容易得到一个难以维护的黑盒。Vite 的 create-vite 提供了一条中间路径——它足够快、足够小,生成的骨架几乎无配置即可运行,同时又足够透明,让开发者可以一步步理解并改造它。

本文从 npm create vite 讲起,带你走过从脚手架到可维护工程的完整路径:模板选择、目录结构、依赖管理、代码质量工具链(ESLint / Prettier / Husky / lint-staged)、路径别名,以及团队协作规范。读完你将能独立初始化一个「拿来即用、改得明白」的 Vite 工程。

前置:Node.js 18+、npm/pnpm 基础。构建工具的底层原理可结合 https://plumephp.com/frontend-vite-deep-dive/ 一并阅读。


目录


1. 为什么选择 create-vite

1.1 对比传统脚手架

方案启动速度配置透明度生态契合
create-vite秒级极高(几乎零配置)React/Vue/Svelte/Solid 官方推荐
CRA(已退役)分钟级低(黑盒 react-scripts)仅 React
create-next-app秒级中仅 Next.js 全栈
手动搭建取决于经验极高完全可控

1.2 create-vite 的核心取舍

  • 非开箱即用全家桶:只生成最小可运行骨架,不强制 eslint/prettier(你可自行加入)。
  • 模板即源码:生成的代码是你可以逐行读懂、按需修改的普通工程。
  • 与框架深度绑定:官方模板针对各框架做了开箱优化(如 React Fast Refresh、Vue HMR)。

1.3 什么时候不用它

大型企业级多包仓库、需要复杂代码生成的项目,直接以空目录 + 手动配置或基于公司内部脚手架模板起步,往往更合适。


2. 初始化项目:模板与交互

2.1 一条命令启动

# npm
npm create vite@latest my-app -- --template react-ts

# 或交互式选择
npm create vite@latest my-app

# pnpm / yarn
pnpm create vite my-app --template vue-ts
yarn create vite my-app --template svelte-ts

2.2 官方模板一览

模板适用场景备注
vanilla原生 JS/TS 实验最小骨架
react / react-tsReact 应用Fast Refresh 开箱
vue / vue-tsVue 3 应用含 <script setup> 示例
svelte / svelte-tsSvelteSvelteKit 的轻量替代
solid / solid-tsSolidJS细粒度响应式
litWeb ComponentsLit 框架

2.3 交互式选择的内核

framework?  ──>  react | vue | svelte | solid | vanilla | lit | ...
variant?    ──>  plain | TypeScript | TS+SWC | 框架特定变体

交互式流程本质上就是在做「模板名拼接」——选择完成后,create-vite 从本地模板缓存解压对应骨架,不产生网络下载框架源码的等待。


3. 目录结构解剖

3.1 生成的默认结构(react-ts 模板)

my-app/
├── public/               # 静态资源,原样拷贝到产物根
│   └── vite.svg
├── src/
│   ├── assets/           # 需要构建处理的资源(会被 hash)
│   ├── App.css
│   ├── App.tsx
│   ├── index.css
│   ├── main.tsx          # 应用入口
│   └── vite-env.d.ts     # Vite 客户端类型声明
├── .gitignore
├── index.html            # 唯一的 HTML 入口(位于根而非 public)
├── package.json
├── tsconfig.json         # 项目引用结构
├── tsconfig.app.json
├── tsconfig.node.json    # 针对 vite.config 的 Node 环境配置
└── vite.config.ts        # Vite 配置文件

3.2 为什么 index.html 在根目录

这是 Vite 区别于 webpack 的关键设计:index.html 是应用入口,<script type="module" src="/src/main.tsx"> 声明入口模块。Vite 通过分析 HTML 中的模块引用,建立模块图(module graph),开发期按需编译、生产期以它为起点打包。

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My App</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

3.3 public 与 src/assets 的区别

存放位置处理方式适用
public/原样拷贝,URL 以 / 开头favicon、robots.txt、无法 hash 的文件
src/assets/走构建管线,自动 hash + 压缩图片、字体等被引用的资源

4. 依赖管理与脚本设计

4.1 package.json 的核心脚本

{
  "name": "my-app",
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "preview": "vite preview",
    "lint": "eslint ."
  },
  "dependencies": {
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  },
  "devDependencies": {
    "@types/react": "^19.0.0",
    "@vitejs/plugin-react": "^4.3.0",
    "typescript": "~5.6.0",
    "vite": "^6.0.0"
  }
}

4.2 三个关键脚本的作用域

脚本命令作用
devvite启动开发服务器(默认 5173 端口)
buildtsc -b && vite build类型检查 + 生产构建到 dist/
previewvite preview本地预览构建产物(模拟生产服务器)

4.3 为什么是 "type": "module"

Vite 6 及其配置都要求 ESM。"type": "module" 让 .js 文件默认按 ESM 解析,vite.config.ts 中的 import/export 语法才能正常工作,也是现代前端工程的事实标准。


5. 代码质量工具链

脚手架默认不含 lint/format,但工程化项目几乎必然要加。下面是经过验证的最小组合。

5.1 ESLint + Prettier + Husky + lint-staged

npm install -D eslint @eslint/js typescript-eslint prettier eslint-config-prettier husky lint-staged

5.2 精简 eslint.config.js

import js from '@eslint/js'
import tseslint from 'typescript-eslint'
import prettier from 'eslint-config-prettier'

export default tseslint.config(
  { ignores: ['dist', 'node_modules'] },
  js.configs.recommended,
  ...tseslint.configs.recommended,
  prettier, // 关闭与 Prettier 冲突的规则
  {
    rules: {
      '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
    },
  },
)

5.3 提交前强制检查(Husky + lint-staged)

npx husky init
# 生成 .husky/pre-commit,内容:
npx lint-staged
// package.json
{
  "lint-staged": {
    "*.{js,ts,jsx,tsx}": ["eslint --fix", "prettier --write"]
  }
}

5.4 工作流

git add . -> pre-commit 钩子 -> lint-staged 只检查暂存文件
          -> eslint --fix 修复 -> prettier --write 格式化
          -> 全部通过才允许 commit

6. 路径别名与基础配置

6.1 vite.config.ts 配置别名

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { fileURLToPath, URL } from 'node:url'

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
    },
  },
})

6.2 tsconfig 联动(避免 TS 报错)

// tsconfig.app.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

6.3 在代码中使用

// import { Button } from '../../components/Button'
// 变成
import { Button } from '@/components/Button'

别名避免了深层相对路径 ../../../ 的脆弱性,重构目录时不再需要大范围修改 import。


7. 从模板到工程:演进路径

7.1 模板只是起点

模板解决「跑起来」的问题,工程化解决「持续交付」的问题。演进通常分四步:

阶段1: 骨架可运行(模板自带)
阶段2: 代码规范落地(ESLint/Prettier/提交钩子)
阶段3: 目录分层(features / pages / components / hooks)
阶段4: 基础设施(路由、状态、请求层、CI/CD)

7.2 一个推荐的 src 分层

src/
├── api/            # 接口层:axios/fetch 封装
├── assets/         # 静态资源
├── components/     # 通用组件
├── features/       # 按业务域划分的功能模块
├── hooks/          # 自定义 hooks
├── layouts/        # 布局组件
├── pages/          # 路由页面
├── router/         # 路由配置
├── stores/         # 状态管理
├── types/          # 全局类型
├── utils/          # 工具函数
├── main.tsx
└── App.tsx

7.3 渐进式改造而非推倒重来

模板提供的 App.tsx 示例可以直接删除、替换为真实业务入口;vite.config.ts 按需增量添加插件。保持「最小改动」原则,避免一开始就堆砌大量脚手架配置。


8. 团队协作规范

8.1 版本锁定

# 锁定依赖版本,配合 lockfile
npm ci
pnpm install --frozen-lockfile

8.2 Node 版本统一

// .nvmrc
20
// package.json
{
  "engines": {
    "node": ">=20.0.0"
  }
}

8.3 CI 基本检查(示意)

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: 'npm' }
      - run: npm ci
      - run: npm run lint
      - run: npm run build

9. 总结:脚手架的取舍

9.1 核心收获

  1. create-vite 是最小可运行的透明骨架:秒级启动、零黑盒、逐行可读。
  2. index.html 在根目录是理解 Vite 模块图设计的钥匙。
  3. 工具链分层渐进落地:先跑起来,再加规范,再分层,再上 CI。
  4. 别名与类型联动解决的是长期可维护性问题。

9.2 自检清单

检查项是否掌握
能用不同模板初始化项目☐
能解释 public 与 src/assets 区别☐
能独立配置 ESLint/Prettier/Husky☐
能配置并解释路径别名☐
能设计团队提交规范☐

9.3 下一步

读 https://plumephp.com/vite-config-guide/ 深入配置项,或直接进入 https://plumephp.com/vite-plugin-development/ 编写你的第一个插件。


延伸阅读

  • https://plumephp.com/frontend-vite-deep-dive/ — Vite 预构建与 HMR 的底层实现
  • https://plumephp.com/vite-config-guide/ — defineConfig 全参数详解
  • https://plumephp.com/vite-build-optimization/ — 生产构建优化
  • create-vite 官方文档 — 完整模板与命令参考
  • Vite 中文文档

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「vite」更多文章

  1. Vite 静态资源与媒体资产处理:图片、字体、SVG 与 Worker
  2. Vite 环境变量与生产构建最佳实践:import.meta.env、构建模式与产物优化
  3. Vite 浏览器兼容与 Legacy 构建:build.target、Polyfill 与兼容插件