从零开始构建一个现代化前端项目:一个曾经抵触 AI 写代码的“老顽固”的真香之路

AI码农
2025-12-18 17:58
阅读 465

“这玩意儿写出来能跑吗?不会上线就炸了吧?”
——2023年7月,我第一次看到同事用 Copilot 生成 React 组件时的内心OS

大家好,我是那个曾经在团队群里公开表示“AI 写代码就是玩具,正经项目谁敢用”的倔脾气前端。去年双11期间,我们组被产品经理连环催更三个需求,我熬了两个通宵手敲完表单验证逻辑,结果第二天发现隔壁组用 Claude 自动生成了带 i18n 和无障碍支持的完整组件——跑得比我写的还稳。

那一刻,我默默打开了 ChatGPT 的 Plus 订阅页面。

如今,我已经成了重度依赖 AI 辅助开发的“真香党”。最近一边准备跳槽刷 LeetCode,一边在公司用 React 搞新项目,深刻体会到:现代化前端开发,早已不是“手搓轮子”的时代。今天这篇文章,就想和大家聊聊,如何从零搭建一个真正“现代化”的前端项目——不是那种网上抄来的模板堆砌,而是能扛住真实业务、面试官追问、甚至线上流量洪峰的工程。


为啥要重新造这个“轮子”?

起因其实很现实:上个月我们接了个新需求,要做一个内部数据分析平台。技术栈要求 React + TypeScript,还得支持微前端接入(别问,问就是架构组拍的板)。项目经理拍着我肩膀说:“你经验丰富,搭个底座吧,下周演示。”

我心想:不就是 create-react-app 起个脚手架,装几个库的事?结果第一天就翻车了。

  • 用 CRA 初始化后,想加 ESLint + Prettier 自动格式化,配置冲突到怀疑人生
  • 引入 Ant Design 后,打包体积直接飙到 3MB+
  • 想加个单元测试,Jest 配置文档看了三遍还是报错
  • 最致命的是:线上预览环境加载首屏花了 8 秒,产品经理当场黑脸

那一刻我真的想砸电脑——不是因为难,而是因为“明明有更优解,我却还在用五年前的方式硬扛”。

于是周末两天,我拉着 Claude 当“副驾驶”,从零重构整个项目结构。目标很明确:开箱即用、性能拉满、面试能吹、跳槽简历加分


现代化 ≠ 堆砌工具链,而是解决真实痛点

很多人一说“现代化前端”,张口就是 Vite、pnpm、Monorepo、微前端……但我觉得,真正的现代化,是让开发者少加班、让用户少等待、让代码少出 Bug

所以我定下几个核心原则:

  1. 开发体验优先:改一行代码,热更新 200ms 内生效
  2. 极致性能:首屏加载 < 1.5s(Lighthouse 评分 > 90)
  3. 可维护性:新人接手三天内能贡献代码
  4. 面试友好:技术选型能经得起深挖(毕竟我在刷题准备跳槽)

下面说说我怎么一步步实现的。


第一步:别再用 create-react-app 了,Vite 是底线

我知道很多人(包括半年前的我)觉得 CRA 够用。但当你面对以下场景:

  • npm start 要等 15 秒
  • 改个 CSS 触发全量 JS 重编译
  • 想用最新 JSX Transform 还得 eject

真的会疯。

现在我的标准初始化命令:

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

Vite 的优势不用多说:基于原生 ES Modules,冷启动快如闪电,HMR 精准到组件级。上周五晚上我改了一个 hook 逻辑,保存后浏览器瞬间更新——那一刻我差点感动哭,再也不用边改代码边刷控制台看是否 reload 了。

而且 Vite 对 React 18 的 Suspense、Server Components(实验性)支持也更前瞻。虽然我们项目暂时用不到,但技术债要少欠,视野要提前铺——毕竟面试官可能下一秒就问:“你们为什么不用 React Server Components?”


第二步:包管理,pnpm 真香警告

以前我一直觉得 npm / yarn 够用,直到项目依赖膨胀到 200+,node_modules 占了 1.2GB,CI 构建经常超时。

换成 pnpm 后:

  • 硬链接 + 符号链接,磁盘占用减少 60%
  • 安装速度提升 3 倍(实测从 45s → 14s)
  • 严格的依赖隔离,杜绝“在我机器上能跑”问题

配置也简单,.npmrc 加一行:

shamefully-hoist=true

(别杠,有些老库需要 hoist 才能正常工作,务实点)

现在团队所有人都转 pnpm 了,连最保守的后端大哥都说:“你这前端,终于不拖 CI 后腿了。”


第三步:TypeScript + ESLint + Prettier,三位一体才叫规范

很多人把这三个分开配,结果:

  • 保存时 Prettier 格式化,ESLint 报错
  • VSCode 提示类型错误,但构建不报错
  • 团队有人用 tab 有人用 space,PR 里全是无关 diff

我的解决方案:用官方推荐组合,一键集成

npm install -D typescript @typescript-eslint/eslint-plugin eslint-config-prettier prettier

关键配置文件:

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["DOM", "DOM.Iterable", "ES2020"],
    "module": "ESNext",
    "jsx": "react-jsx",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

.eslintrc.cjs

module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'prettier'
  ],
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  rules: {
    '@typescript-eslint/no-explicit-any': 'warn',
    '@typescript-eslint/explicit-function-return-type': 'off'
  }
}

.prettierrc

{
  "semi": false,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5"
}

然后在 package.json 加个 script:

{
  "scripts": {
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "format": "prettier --write ."
  }
}

现在,保存自动格式化,提交前自动 lint,代码风格统一到像一个人写的。测试同学再也不吐槽 PR 里混着空格和 tab 了。


第四步:UI 库按需加载 + 自定义主题

前面提到 Ant Design 打包太大?那是因为你全量引入了!

正确姿势:用 unplugin-vue-components(别被名字骗,它支持 React)自动按需引入。

// vite.config.ts
import react from '@vitejs/plugin-react'
import Components from 'unplugin-vue-components/vite'
import { AntDesignReactResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    react(),
    Components({
      resolvers: [AntDesignReactResolver()],
      dts: true,
    }),
  ],
})

现在写:

import { Button } from 'antd'

实际只打包 Button 相关代码,体积直降 70%。

另外,别直接用默认主题!设计师给了新色板?用 CSS Variables 覆盖:

:root {
  --ant-primary-color: #6366f1; /* indigo-500 */
}

这样既保持 UI 一致性,又避免魔改 node_modules。


第五步:性能优化,从“能跑”到“飞起”

很多前端止步于“功能实现”,但现代化项目必须考虑性能。我做了几件事:

1. 路由级代码分割

const Dashboard = lazy(() => import('@/pages/Dashboard'))

配合 Suspense loading,首屏只加载必要代码。

2. 图片懒加载 + WebP

loading="lazy" + CDN 自动转 WebP。实测图片体积减少 50%,LCP 提升 400ms。

3. API 请求封装 + SWR 缓存

别再裸写 fetch 了!封装一个 useApi hook,集成错误重试、loading 状态、缓存策略:

const { data, error } = useSWR('/api/user', fetcher)

用户切回来 tab 时数据秒出,体验直接拉满。

4. 性能监控埋点

集成 Sentry + Lighthouse CI,每次 PR 自动跑性能报告。上周发现某个组件 rerender 过度,靠 React DevTools Profiler 三分钟定位到是 useEffect 依赖数组漏了变量。


面试题预警:这些设计决策,面试官必问!

既然我在准备跳槽,就得考虑“技术选型能否经得起拷问”。比如:

  • 为什么选 Vite 不选 Webpack?

    答:开发体验(HMR 速度)、未来兼容性(原生 ESM 是趋势)、构建性能(Rollup 插件生态成熟)。但补充一句:“如果项目强依赖 Webpack 特有 loader,也会评估迁移成本。”

  • pnpm 如何解决 phantom dependencies?

    答:通过 symlink + store 结构,严格限制模块只能访问声明的依赖,避免隐式依赖导致的 CI/CD 不一致。

  • React.memo 用得多吗?什么场景下无效?

    (这时候就可以秀肌肉了)答:我们用 useMemo 缓存 props 对象,避免父组件 rerender 导致子组件无意义更新。但注意:如果 props 是函数,必须配合 useCallback,否则引用变化依然触发重渲染。

这些细节,才是区分“调库侠”和“工程师”的关键。


成果与反思:从抗拒到拥抱

重构后的项目:

指标 重构前 重构后 提升
首屏加载 8.2s 1.1s ↓ 86%
Bundle 体积 3.1MB 0.9MB ↓ 71%
CI 构建时间 2m15s 48s ↓ 63%
新人上手时间 1周 2天 ↓ 71%

上周演示时,产品经理居然说了句:“这次加载好快啊!”——这是我今年听到最动听的话。

更重要的是,我不再恐惧新技术。以前觉得“稳定压倒一切”,现在明白:真正的稳定,是用现代化工具减少人为错误。AI 生成的代码不一定完美,但它帮我快速搭建骨架、写出合规的测试用例、甚至生成 commit message——让我专注在业务逻辑和用户体验上。

当然,我也踩过坑:

  • 曾经让 Claude 生成一个自定义 Hook,结果它用了过时的 useContext 用法,导致内存泄漏
  • Vite 插件和旧版 Webpack loader 冲突,调试到凌晨三点
  • pnpm 在 Windows WSL 下偶尔 symlink 失败

但这些都不是拒绝进步的理由。就像我常跟实习生说的:“工具不会取代你,但会用工具的人会。


最后:给正在“造轮子”的你几点建议

  1. 别追求一步到位:先保证能跑,再逐步优化。我第一天只搞定了 Vite + TS,其他都是后续迭代加的。
  2. 文档比代码重要:在项目根目录写 ARCHITECTURE.md,说明每个技术选型的原因。面试时直接甩链接,比口头解释强十倍。
  3. 留个“后悔药”:用 Git 分支管理实验性功能,比如 feat/react-server-components,不行就删,不影响主干。
  4. 善用 AI,但保持警惕:让它写 boilerplate,但核心逻辑自己 review。毕竟,AI 是副驾驶,你是机长

现在,当我看到新同事还在手敲 webpack 配置时,我会笑着递上一杯咖啡:“兄弟,试试 Vite 吧,我请你。” —— 这大概就是成长吧。

P.S. 如果你在准备前端面试,不妨试着从零搭一个这样的项目。当面试官问“你做过最复杂的前端工程化实践是什么”,你就知道该怎么回答了。

P.P.S. 别忘了 star 我的 GitHub 模板仓库(开玩笑的,其实还没开源,等我跳槽成功再说 😏)

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝