当前位置: 首页 > ai >正文

【React ✨】从零搭建 React 项目:脚手架与工程化实战(2025 版)

目标:使用 Vite + React + TypeScript 快速脚手化,并落地ESLint/Prettier、测试、别名、Tailwind、环境变量、提交校验与 CI。附Next.js 与 CRA 对比建议。


目录

  1. 快速开始(Vite/TS)
  2. 项目结构
  3. 代码规范:ESLint + Prettier +EditorConfig
  4. 路径别名与导入优化
  5. CSS 方案:Tailwind CSS(可选)
  6. 环境变量与多环境
  7. 测试:Vitest + Testing Library
  8. Git 提交规范:Husky + lint-staged +
    Commitlint
  9. CI 示例(GitHub Actions)
  10. 生产构建与部署
  11. 常见问题与性能优化
  12. 附录: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)。

http://www.xdnf.cn/news/18460.html

相关文章:

  • 文字学的多维透视:从符号系统到文化实践
  • 2025年09月计算机二级MySQL选择题每日一练——第五期
  • Go语言实战案例-Redis连接与字符串操作
  • 井云智能体封装小程序:独立部署多开版 | 自定义LOGO/域名,打造专属AI智能体平台
  • IDEA控制台乱码(Tomcat)解决方法
  • IDEA相关的设置和技巧
  • 机器人 - 无人机基础(5) - 飞控中的传感器(ing)
  • CTFshow Pwn入门 - pwn 19
  • 《天龙八部》角色安全攻防全解析:从渗透测试视角看江湖成败
  • 【Golang】有关任务窃取调度器和抢占式调度器的笔记
  • STM32F1 USART介绍及应用
  • 开发指南134-路由传递参数
  • 支持蓝牙标签打印的固定资产管理系统源码(JAVA)
  • linux编程----网络通信(TCP)
  • LLM实践系列:利用LLM重构数据科学流程04 - 智能特征工程
  • 博士招生 | 英国谢菲尔德大学 招收计算机博士
  • 项目中优惠券计算逻辑全解析(处理高并发)
  • Unreal Engine UStaticMeshComponent
  • JUC之CompletionService
  • DFS序与树链剖分入门
  • 开发避坑指南(35):mybaits if标签test条件判断等号=解析异常解决方案
  • 文件系统层面的可用块数量可用空间和比例
  • AI重塑职业教育:个性化学习计划提效率、VR实操模拟强技能,对接就业新路径
  • 拿到手一个前端项目,应该如何启动
  • 开发避坑指南(34):mysql深度分页查询优化方案
  • Ubuntu解决makefile交叉编译的问题
  • Android Jetpack | Hilt
  • 机器人爆发、汽车换代,速腾聚创开始讲新故事
  • WindowsAPI|每天了解几个winAPI接口之网络配置相关文档Iphlpapi.h详细分析八
  • 【数据结构】选择排序:直接选择与堆排序详解