第 2 章:快速开始 — 使用 Vite + TypeScript 初始化项目
在上一章中,我们明确了项目目标、技术栈与未来的总体架构路线。本章将正式开始动手,从零初始化一个 基于 React 19 + TypeScript + Vite 的开发环境。
本章你将完成:
- 创建项目目录
- 初始化 Vite 项目(React + TS 模板)
- 安装所有必要依赖
- 配置基础开发环境(ESLint / Prettier / Tailwind 前置)
- 解析 package.json 结构,理解项目运行机制
完成本章后,你将拥有一个可以运行、可开发的项目基础结构,为后续多语言、主题、路由、权限等模块打下坚实基础。
2.1 创建项目目录
https://vite.dev/guide/#scaffolding-your-first-vite-project
在任意目录执行:
pnpm create vite@latest
修改 Project name,改为 web-app,回车:

选择框架,这里我们选择 React

选择 variant,这里我们选择 TypeScript


或者直接使用以下命令,指定使用 react-ts:
pnpm create vite@latest web-app --template react-ts

rolldown-vite 是将 Rolldown(一款兼容 Rollup 的 Rust 编写打包工具)集成到 Vite 的实验性方案,目标是用性能更优的 Rust 实现替代 Vite 默认的 Rollup 打包器。
这里选择 No

Install with pnpm and start now?
这里选择 Yes 时,将会自动执行以下命令:
cd web-app pnpm install pnpm dev
选择 No,需要手动执行以下命令:

接着:
cd web-app pnpm install

完成后文件结构如下:

这是最基础的 React + TypeScript + Vite 项目。
2.2 运行项目,确认环境无误
执行:
pnpm dev
你将看到:

打开浏览器确认项目运行无误。

2.3 安装项目所需的全部依赖
我们项目使用了丰富但结构清晰的技术栈。下面按照模块安装必要依赖。
2.3.1 安装 UI & 样式相关依赖
安装配置参考:
https://ui.shadcn.com/docs/installation/vite
https://v3.tailwindcss.com/docs/guides/vite
安装 Tailwind CSS v3
pnpm add -D tailwindcss@3 postcss autoprefixer

本教程 刻意选择 Tailwind CSS v3,原因如下:
- shadcn/ui 官方稳定支持 v3
- eslint / prettier / tailwind 插件生态成熟
- 社区资料最完整,适合长期维护型项目
- 避免 Tailwind v4 当前的实验性不稳定因素
初始化 Tailwind CSS
npx tailwindcss init -p
会生成 tailwind.config.js 和 postcss.config.js 两个文件。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
content: [],
theme: {
extend: {},
},
plugins: [],
}
postcss.config.js
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
将 tailwind.config.js 修改为:
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
darkMode: "class",
theme: {
extend: {},
},
plugins: [],
}
| 字段 | 作用 |
|---|---|
| content | Tailwind 扫描范围 |
| darkMode | 使用 class 切换,兼容 next-themes |
| extend | 注册 Token(颜色、圆角、字体等) |
将 Tailwind 指令添加到 CSS 中
清空 ./src/index.css 中的内容,将 Tailwind 的每个 layer 的 @tailwind 指令添加到 ./src/index.css 文件中:
@tailwind base;
@tailwind components;
@tailwind utilities;
启动项目
pnpm run dev
修改 App.jsx,添加:
<h1 className="text-3xl font-bold underline"> Hello world! </h1>

查看效果

配置 TypeScript 路径别名
编辑 tsconfig.json 文件
当前版本的 Vite 将 TypeScript 配置拆分成三个文件,其中有两个需要修改。
你需要在 tsconfig.json 和 tsconfig.app.json 的 compilerOptions 中添加 baseUrl 和 paths 属性:
修改前:
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
修改后:
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
编辑 tsconfig.app.json 文件
在 tsconfig.app.json 文件中加入以下代码,以便 IDE 能正确解析路径:
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2022",
"useDefineForClassFields": true,
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"types": ["vite/client"],
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
},
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
}
更新 vite.config.ts
安装 @types/node
@types/node 是 Node.js 的 TypeScript 类型定义文件,只要你使用 Node.js API,就必须安装。
例如:
process.env__dirname,__filenamepath,fs,crypto等 Node 内置模块- ESM 中使用
import.meta - Vite 配置文件(vite.config.ts)
- Tailwind 配置文件(tailwind.config.ts)
- tsconfig 路径解析
- node 相关脚本
如果没有安装,你会看到 TypeScript 报错:
Cannot find name 'process'
Cannot find module 'path'
Cannot find name '__dirname'
安装它的目的就是:
让你的 TypeScript 项目在写 Node 相关代码时,获得完整的类型提示、智能补全、类型检查支持。
执行以下命令:
pnpm add -D @types/node
执行结果

在 vite.config.ts 文件中加入以下代码,使你的应用能够正确解析路径,避免报错:
修改前:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
})
修改后:
import path from "path"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
})
shadcn/ui 工具
运行 CLI
执行 shadcn init 命令来初始化你的项目配置:
在初始化时,CLI 会询问你一些问题,用于生成 components.json。
我们稍后会使用它生成高质量 UI 组件:
pnpm dlx shadcn@latest init

具体的 color 的效果,请参考 https://ui.shadcn.com/colors,我们这里默认选择 Neutral,回车。

执行成功,我们看到添加了一个 components.json 文件:
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/index.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {}
}
一个 src/lib/utils.ts 文件:
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
更新了 src/index.css:
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--card: 0 0% 100%;
--card-foreground: 0 0% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%;
--primary: 0 0% 9%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 9%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 45.1%;
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--ring: 0 0% 3.9%;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
--radius: 0.5rem;
}
.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--card: 0 0% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 0 0% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 0 0% 9%;
--secondary: 0 0% 14.9%;
--secondary-foreground: 0 0% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--accent: 0 0% 14.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--ring: 0 0% 83.1%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
添加组件
你现在可以开始往项目中添加组件了。
pnpm dlx shadcn@latest add button
上面的命令会把 Button(按钮)组件 添加到你的项目中。


你可以像下面这样引入它:
import { Button } from "@/components/ui/button"
function App() {
return (
<div className="flex min-h-svh flex-col items-center justify-center">
<Button>Click me</Button>
</div>
)
}
export default App

安装 lucide-react(图标库)
lucide-react 是 shadcn/ui 官方推荐的 SVG 图标库,具有以下特点:
- Tree-shaking 友好,按需引入
- TypeScript 原生支持
- 与 Tailwind / shadcn/ui 完美配合
- 无额外运行时依赖
1️⃣ 安装依赖
pnpm add lucide-react

2️⃣ 基本使用示例
在任意组件中直接按需引入图标即可:
import { Search, User, Settings } from "lucide-react"
function IconDemo() {
return (
<div className="flex items-center gap-4">
<Search className="h-5 w-5 text-muted-foreground" />
<User className="h-5 w-5 text-blue-500" />
<Settings className="h-5 w-5 text-green-500" />
</div>
)
}

本质说明:
- 每一个图标都是一个 React 组件
className直接控制大小与颜色h-* w-*来自 Tailwind
3️⃣ 在 shadcn/ui 组件中使用(推荐)
例如在 Button 中使用图标:
import { Plus } from "lucide-react"
import { Button } from "@/components/ui/button"
function CreateButton() {
return (
<Button>
<Plus className="mr-2 h-4 w-4" /> 新建
</Button>
)
}

这是 shadcn 官方示例风格,非常推荐在你的教程中强调。
4️⃣ 图标大小与颜色规范(最佳实践)
| 用途 | 推荐尺寸 |
|---|---|
| 按钮内图标 | h-4 w-4 |
| 普通功能图标 | h-5 w-5 |
| 列表 / 菜单 | h-4 w-4 |
| 图标按钮 | h-5 w-5 或 h-6 w-6 |
颜色统一通过 Tailwind 控制:
<Icon className="text-muted-foreground" />
<Icon className="text-primary" />
5️⃣ 为什么选择 lucide-react
本项目选择 lucide-react 作为唯一图标库,原因是:shadcn/ui 默认使用 lucide,API 简单,学习成本极低,图标风格统一,适合中后台 / 管理系统,不依赖 SVG loader 或额外构建配置。
6️⃣ 与 shadcn 初始化配置的关系
在你前面 components.json 中已经有:
"iconLibrary": "lucide"
这表示:
- shadcn 生成的组件 默认假设你使用 lucide-react
- 安装 lucide-react 是必须步骤
- 不需要额外配置 Vite / SVG 插件
2.3.2 安装国际化 i18n
pnpm add react-i18next i18next i18next-browser-languagedetector

2.3.3 安装主题切换
pnpm add next-themes

2.3.4 安装数据请求层(ky)
pnpm add ky

2.3.5 安装状态管理(Zustand)
pnpm add zustand

2.3.6 安装后端数据管理(TanStack Query)
pnpm add @tanstack/react-query

2.3.7 安装路由(React Router v7)
pnpm add react-router-dom

2.3.8 安装表单(react-hook-form + zod)
pnpm add react-hook-form zod pnpm add @hookform/resolvers

2.3.9 安装 Toast(sonner)
pnpm add sonner

2.3.10 安装 mock(mockjs)
pnpm add mockjs

2.3.11 安装 Recharts 图表组件
pnpm add recharts

2.3.13 SVG 处理插件(可选)
如果你想像 shadcn 那样使用 svg 组件:
pnpm add -D vite-plugin-svgr

我们会在 vite.config.ts 中配置它。
至此,所有核心依赖已经安装完毕。
接下来,我们需要理解 package.json 的结构。
2.4 理解 package.json(本项目的依赖结构解析)
下面是当前项目核心依赖的结构化说明:
✔ React & Vite
"react": "^19.2.0",
"react-dom": "^19.2.0",
"vite": "^7.2.4",
"@vitejs/plugin-react": "^5.1.1",
用途:基础框架 + 构建工具
✔ TypeScript
"typescript": "~5.9.3"
用途:整个项目的类型安全与工程能力基座
✔ UI & 样式系统
"tailwindcss": "^3.4.19",
"tailwind-merge": "^3.4.0",
"tailwindcss-animate": "^1.0.7",
"postcss": "^8.5.6",
"autoprefixer": "^10.4.23",
"lucide-react": "^0.561.0",
shadcn + CVA + Tailwind = 通用组件体系的三角组合。
✔ 状态与数据请求
"zustand": "^5.0.9",
"ky": "^1.14.1",
"@tanstack/react-query": "^5.90.12",
✔ 国际化
"i18next": "^25.7.2",
"i18next-browser-languagedetector": "^8.2.0",
"react-i18next": "^16.4.1",
✔ 路由
"react-router-dom": "^7.10.1",
支持最新的 Data APIs、Suspense、Lazy routes
✔ 表单 + 校验
"react-hook-form": "^7.68.0",
"zod": "^4.1.13",
"@hookform/resolvers": "^5.2.2",
✔ Mock
"mockjs": "^1.1.0"
✔ 通知组件(Toast)
"sonner": "^2.0.7",
✔ 图表
"recharts": "^3.5.1",
整体结构非常清晰:
- 依赖结构有明确边界
- 业务逻辑与 UI 逻辑分离
- 每个模块都有清晰职责
2.5 配置 Vite(基础版本)
vite.config.ts:
import path from "path"
import tailwindcss from "@tailwindcss/vite"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"
// https://vite.dev/config/
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
})
更新为:
import path from "path"
import react from "@vitejs/plugin-react"
import svgr from 'vite-plugin-svgr'; // 如果你使用 SVG 组件
import { defineConfig } from "vite"
// https://vite.dev/config/
export default defineConfig({
plugins: [react(), svgr()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
server: {
port: 5173,
},
})
2.6 清理默认模板
默认 App.tsx 内容过于简单,我们先清空:
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
function App() {
const [count, setCount] = useState(0)
return (
<>
<div>
<a href="https://vite.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">Click on the Vite and React logos to learn more</p>
</>
)
}
export default App
修改 src/App.tsx:
import { Button } from "@/components/ui/button"
import { Search, User, Settings, Plus } from "lucide-react"
function App() {
return (
<div className="flex min-h-screen flex-col items-center justify-center p-4 space-x-3 gap-4">
<div>App Initialized</div>
<Button>默认按钮</Button>
<Button size="sm">小</Button>
<Button size="lg">大</Button>
<Button variant="outline">描边按钮</Button>
<IconDemo />
<CreateButton />
</div>
)
}
function IconDemo() {
return (
<div className="flex items-center gap-4">
<Search className="h-5 w-5 text-muted-foreground" />
<User className="h-5 w-5 text-blue-500" />
<Settings className="h-5 w-5 text-green-500" />
</div>
)
}
function CreateButton() {
return (
<Button>
<Plus className="mr-2 h-4 w-4" /> 新建
</Button>
)
}
export default App

下一章会替换为真实结构。
2.7 本章小结
本章完成了:
✔ 初始化 Vite + React + TypeScript 项目
✔ 安装所有框架核心依赖
✔ 解析 package.json
✔ 配置基础 Vite 环境
✔ 清理默认模板



