【React ✨】从零搭建 React 项目:脚手架与工程化实战(2025 版)
目标:使用 Vite + React + TypeScript 快速脚手化,并落地ESLint/Prettier、测试、别名、Tailwind、环境变量、提交校验与 CI。附Next.js 与 CRA 对比建议。
目录
- 快速开始(Vite/TS)
- 项目结构
- 代码规范:ESLint + Prettier +EditorConfig
- 路径别名与导入优化
- CSS 方案:Tailwind CSS(可选)
- 环境变量与多环境
- 测试:Vitest + Testing Library
- Git 提交规范:Husky + lint-staged +
Commitlint - CI 示例(GitHub Actions)
- 生产构建与部署
- 常见问题与性能优化
- 附录:Next.js 与 CRA 选择建议
快速开始(Vite/TS)
推荐使用 pnpm(也可用 npm/yarn)。Node 建议 >= 18。
# 1) 新建项目
pnpm create vite@latest my-react-app --template react-ts
# or
npm create vite@latest my-react-app -- --template react-ts
# or
yarn create vite my-react-app --template react-tscd my-react-app# 2) 安装依赖
pnpm install
# 3) 启动开发
pnpm dev
打开 http://localhost:5173 验证是否启动成功,下面是打开页面:
项目结构
my-react-app/
├─ src/
│ ├─ app/ # 应用级入口/路由/状态
│ ├─ components/ # 通用组件
│ ├─ features/ # 业务特性模块(可拆包)
│ ├─ pages/ # 路由页面(如用 react-router)
│ ├─ hooks/ # 自定义 hooks
│ ├─ assets/ # 静态资源
│ ├─ styles/ # 全局样式/变量
│ ├─ lib/ # 工具库/适配层(api、storage)
│ ├─ test/ # 测试辅助
│ ├─ main.tsx # 入口
│ └─ vite-env.d.ts
├─ .editorconfig
├─ .eslintrc.cjs
├─ .prettierrc
├─ index.html
├─ package.json
├─ tsconfig.json
└─ vite.config.ts
代码规范:ESLint + Prettier + EditorConfig
pnpm add -D eslint prettier eslint-config-prettier eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint/parser @typescript-eslint/eslint-plugin @tanstack/eslint-plugin-query eslint-plugin-import
.eslintrc.cjs:
规范 JavaScript/TypeScript 代码的书写风格和质量检查
module.exports = {root: true, // 声明为根配置文件,停止向上查找其他配置env: { browser: true, es2023: true, node: true }, // 指定代码运行环境(浏览器、ES2023、Node.js),避免全局变量报错parser: "@typescript-eslint/parser", // 使用 TypeScript 解析器处理 TS 代码parserOptions: { ecmaFeatures: { jsx: true }, sourceType: "module" }, // 启用 JSX 语法支持,指定模块化代码(ES Modules)settings: { react: { version: "detect" } }, // 自动检测 React 版本,适配不同版本的 React 语法plugins: ["react", "react-hooks", "@typescript-eslint", "import", "@tanstack/query"],extends: ["eslint:recommended","plugin:react/recommended","plugin:react-hooks/recommended","plugin:@typescript-eslint/recommended","plugin:import/recommended","plugin:import/typescript","plugin:@tanstack/query/recommended","prettier"],rules: {"react/react-in-jsx-scope": "off", // 无需显式导入 React"import/order": ["warn", {"groups": ["builtin","external","internal","parent","sibling","index"],"newlines-between": "always","alphabetize": { "order": "asc", "caseInsensitive": true }}], },
};
.prettierrc
{"printWidth": 100, // 每行代码的最大字符数限制为 100,超过则自动换行,避免单行代码过长影响可读性。"singleQuote": true, // 强制使用单引号(')代替双引号(")包裹字符串,例如将 \"hello\" 格式化为 'hello'。"semi": true, // 在语句结尾添加分号(;),例如 const a = 1 会被格式化为 const a = 1;。"trailingComma": "all", // 为多行结构中的最后一个元素添加尾随逗号"arrowParens": "always" // 箭头函数的参数始终使用括号包裹,即使只有一个参数
}
.editorconfig
root = true // 声明为根配置文件,停止向上查找其他 EditorConfig 配置文件,确保当前配置优先级最高。[*] // 表示对所有文件类型生效
charset = utf-8 // 强制使用 UTF-8 字符编码,避免中文等特殊字符乱码。
indent_style = space // 使用空格
indent_size = 2 // 每级缩进使用 2 个空格
end_of_line = lf // 行尾换行符使用 Unix 风格的 LF
insert_final_newline = true // 确保文件末尾添加一个空行
trim_trailing_whitespace = true // 自动删除行尾多余的空格
在 package.json
增加脚本:
{"scripts": {"lint": "eslint . --ext .ts,.tsx --max-warnings=0","lint:fix": "pnpm lint --fix","format": "prettier --write ."}
}
路径别名与导入优化
安装 Node 类型(若未装):
pnpm add -D @types/node
# 或 npm i -D @types/node / yarn add -D @types/node
tsconfig.json
{"compilerOptions": {"baseUrl": ".","paths": {"@/*": ["src/*"]}}
}
vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';export default defineConfig({plugins: [react()],resolve: {alias: {'@': path.resolve(__dirname, 'src')}}
});
使用:import Button from '@/components/Button'
。
CSS 方案:Tailwind CSS(可选)
pnpm add -D tailwindcss postcss autoprefixer
安装的是 Tailwind v4 需要手动创建配置文件
tailwind.config.js
export default {content: ['./index.html', './src/**/*.{ts,tsx}'],theme: { extend: {} },plugins: [],
};
src/styles/index.css
@import "tailwindcss";
在 main.tsx
引入:
import '@/styles/index.css';
环境变量与多环境
Vite 约定: - .env
(通用) - .env.development
- .env.production
- 变量以 VITE_ 前缀暴露给客户端。
示例:.env.development
VITE_API_BASE=https://dev.api.example.com
使用:
const base = import.meta.env.VITE_API_BASE;
小贴士:使用 import.meta.env.MODE
判定环境,或在 CI 中注入.env
。
测试:Vitest + Testing Library
pnpm add -D vitest @vitest/coverage-v8 jsdom @testing-library/react @testing-library/user-event
vitest.config.ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';export default defineConfig({plugins: [react()],test: {environment: 'jsdom',setupFiles: './src/test/setup.ts',globals: true, coverage: { reporter: ['text', 'lcov'] }}
});
src/test/setup.ts
pnpm add -D @testing-library/jest-dom
import '@testing-library/jest-dom';
示例测试:src/components/Hello.test.tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { useState } from 'react';function Hello() {const [count, setCount] = useState(0);return (<div><span>count: {count}</span><button onClick={() => setCount((c) => c + 1)}>add</button></div>);
}test('increments', async () => {render(<Hello />);await userEvent.click(screen.getByText('add'));expect(screen.getByText(/count: 1/)).toBeInTheDocument();
});
脚本:
{"scripts": {"test": "vitest","test:coverage": "vitest --coverage"}
}
命令测试:
pnpm test
页面测试:
安装依赖:
pnpm add -D @vitest/ui
脚本:
{"scripts": {"test:ui": "vitest --ui",}
}
Git 提交规范:Husky + lint-staged + Commitlint
pnpm add -D husky lint-staged @commitlint/cli @commitlint/config-conventional
pnpm dlx husky-init && pnpm install
.husky/pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"pnpm lint-staged
package.json
{"lint-staged": {"*.{ts,tsx,js,jsx,json,css,md}": ["prettier --write","eslint --fix --max-warnings=0"]},"commitlint": { "extends": ["@commitlint/config-conventional"] }
}
.husky/commit-msg
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"pnpm commitlint --edit "$1"
CI 示例(GitHub Actions)
.github/workflows/ci.yml
name: CI
on:push:branches: [ main ]pull_request:branches: [ main ]jobs:build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- uses: actions/setup-node@v4with:node-version: '20'cache: 'pnpm'- uses: pnpm/action-setup@v4with:version: 9- run: pnpm install --frozen-lockfile- run: pnpm lint- run: pnpm test -- --run- run: pnpm build- name: Upload distuses: actions/upload-artifact@v4with:name: distpath: dist
生产构建与部署
pnpm build # 产出 dist/
-
静态托管:Vercel / Netlify / Cloudflare Pages / GitHub Pages(将
dist
作为静态资源)。 -
自建 Nginx:
server {listen 80;server_name your.domain.com;root /var/www/my-react-app/dist;location / {try_files $uri /index.html;} }
常见问题与性能优化
- 使用 React.lazy + Suspense 做路由/组件懒加载。
- 图片用现代格式(WebP/AVIF),配合资源懒加载(
loading="lazy"
)。 - 生产构建开启 splitChunks(Vite 默认基于 Rollup 分包)。
- 使用 TanStack Query 缓存请求;或 SWR、RTK Query。
- 大表格/长列表用虚拟滚动(react-virtual 等)。
- 利用
useMemo
/useCallback
避免不必要渲染(配合 ESLint hooks
规则)。
附录:Next.js 与 CRA 选择建议
-
Vite + React(本文方案):偏前端 SPA,开发体验极快,灵活、轻量。
-
Next.js(create-next-app):如果需要 SSR / SSG / ISR / Route Handlers / 中间层 API / 边缘运行,优先 Next.js。
pnpm create next-app@latest my-next --ts --eslint --app --src-dir --tailwind
-
Create React App:生态已逐渐转向 Vite/Next.js,不再优选。仅在特定内部脚手需求下考虑。
结语
以上步骤覆盖了一个现代 React 工程从 脚手化 → 规范化 → 可测试 → 可持续集成 → 可部署
的完整闭环。你可以直接复制到团队模板仓库,或基于此再封装自己的脚手架(如通过 create-*
模板或内网 CLI)。