从零开始构建一个现代化前端项目:裸辞半年后,我重新捡起键盘的血泪经验

Git冲突患者
2025-12-16 23:11
阅读 303

去年十月,我做了一个让全家都惊掉下巴的决定——裸辞了。在某大厂干了三年多,经历了无数次“双11压测崩盘”、“凌晨三点回滚上线”和“产品经理说这个需求很简单”的洗礼后,我终于扛不住了。Gap这半年,表面是躺平看世界,实则内心焦虑得半夜爬起来刷 LeetCode,生怕被技术浪潮冲走。

上周五晚上十一点,我坐在上海租的小单间里(离前司就两公里,省下的通勤时间全拿来写代码了),盯着 VS Code 的空白窗口发呆。突然想:既然要重新找工作,不如亲手搭一个能放进简历里的现代前端项目?不为别的,就为了证明自己还没被时代淘汰。

于是,就有了这篇踩坑无数、重构三次、差点又想裸辞(二次)的实战记录。


起手式:别再用 create-react-app 了,它已经“老”了

说实话,刚开搞时我下意识敲了 npx create-react-app my-awesome-app —— 毕竟在大厂那会儿,所有内部脚手架都是基于 CRA 魔改的,闭着眼都能配。但跑起来一看,webpack 4 + Babel 7,连 Top-Level Await 都不支持,ESLint 规则还是三年前的配置。我当场裂开。

现在都 2024 年了,Vite 已经成了事实标准。速度快到离谱,HMR 冷启动不到 300ms,改一行代码秒级刷新,体验直接拉满。于是我删掉 node_modules(对,我又删了一次),重新开整:

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

选 TypeScript 是被逼的。之前在大厂维护一个 JS 项目,光类型推断就让新人 debug 两天。现在跳槽面试,不会 TS 根本进不了二面。而且说实话,写多了反而觉得爽——IDE 自动补全强到飞起,再也不用翻半天文档查 API 返回结构了。


工具链:不是越多越好,而是“刚刚好”

很多教程一上来就塞你一嘴工具:Prettier、ESLint、Husky、lint-staged、Commitizen、Changesets……听着高大上,但实际开发中,90% 的时间都在配这些玩意儿,业务代码一行没写。

我的原则很朴素:只加解决实际问题的工具

比如 ESLint,我直接用了 eslint-config-react-app + typescript-eslint,再配上 Prettier 做格式化。两者通过 eslint-config-prettier 解耦,互不打架。.eslintrc.js 长这样:

module.exports = {
  extends: [
    'react-app',
    'react-app/jest',
    '@typescript-eslint/recommended',
    'prettier'
  ],
  plugins: ['@typescript-eslint'],
  rules: {
    // 禁止 any,但允许我偷懒用一次(调试时)
    '@typescript-eslint/no-explicit-any': 'off',
    // 强制组件命名规范,避免出现 MyComponent123
    'react/function-component-definition': [
      'error',
      { namedComponents: 'function-declaration' }
    ]
  }
};

再说 Git hooks。以前在公司,每次 commit 都要跑 2 分钟 lint + test,烦死了。现在我只用 lint-staged 在 staged 文件上跑检查,速度飞快:

// package.json
{
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"]
  }
}

提交前自动 fix 可修复问题,格式乱了?不存在的。代码可读性这块,我拿捏得死死的。


代码结构:别让“utils”变成垃圾场

在大厂那会儿,我们有个 src/utils 目录,里面塞了 87 个文件,从日期处理到加密解密再到 mock 数据,啥都有。新人根本不敢动,怕删了某个“关键函数”导致线上炸掉。

这次我给自己立了规矩:按功能域组织,而不是按文件类型

src/
├── features/
│   ├── auth/          # 认证相关:登录、注册、token 管理
│   ├── dashboard/     # 仪表盘:图表、数据卡片
│   └── profile/       # 用户资料编辑
├── shared/
│   ├── ui/            # 通用组件:Button, Modal, FormItem
│   ├── lib/           # 纯工具函数,无副作用
│   └── hooks/         # 自定义 hooks
└── app/
    ├── routes.tsx     # 路由配置
    └── layout.tsx     # 全局布局

这样做的好处是:当我要改“用户头像上传”功能时,所有相关代码都在 profile 目录下,不用跨三个文件夹找逻辑。团队协作时也清晰——谁负责哪个 feature 一目了然。


React 写法:告别 class,拥抱函数式与状态管理

曾经我也写过 class 组件,setState 套 setState,回调地狱看得眼花。现在?Function Component + Hooks 是唯一真理。

但光用 useState 和 useEffect 不够。复杂状态(比如表单联动、多步骤向导)很容易写出意大利面条代码。我试过 Redux Toolkit,但感觉有点重;Zustand 上手快,但缺乏 devtools 支持。

最后选了 Jotai —— 一个原子化的状态库。用起来像 useState,但支持异步、派生状态、持久化,还自带 React DevTools 插件。

举个例子,用户登录状态:

// atoms/authAtom.ts
import { atom } from 'jotai';
import { User } from '@/types';

const userAtom = atom<User | null>(null);
const isLoggedInAtom = atom((get) => !!get(userAtom));

export { userAtom, isLoggedInAtom };

在组件里直接用:

const LoginButton = () => {
  const [user, setUser] = useAtom(userAtom);
  const isLoggedIn = useAtomValue(isLoggedInAtom);

  const handleLogin = async () => {
    const userData = await api.login();
    setUser(userData); // 自动触发 re-render
  };

  return isLoggedIn ? <Logout /> : <button onClick={handleLogin}>登录</button>;
};

没有 Provider 嵌套,没有 action type 字符串,状态流清晰得像小溪。而且因为是原子粒度,性能优化天然做好了——只 re-render 依赖该 atom 的组件。


性能与体验:别让用户等得想卸载

上周测试时,我把 build 后的包扔 Lighthouse 一跑,Performance 才 68 分。首屏加载 3.2s,JS bundle 2.1MB。我当场血压飙升——这要是放我们前司,测试组早就提 bug 单了:“页面白屏太久,用户流失率上升”。

优化三板斧:

  1. 代码分割:路由级拆包,用 React.lazy + Suspense
  2. 图片懒加载<img loading="lazy" /> 加上 decoding="async"
  3. 移除未用依赖:用 source-map-explorer 扫包,发现不小心引入了整个 Lodash,换成 lodash-es 按需导入

最骚的是,我发现一个第三方 UI 库偷偷打包了 moment.js(170KB!)。换成 date-fns 后,bundle 直接瘦了 15%。

优化项 优化前 优化后 提升
Bundle Size 2.1 MB 1.3 MB -38%
FCP (首内容绘制) 2.8s 1.1s +60%
TTI (可交互时间) 3.2s 1.4s +56%

现在 Lighthouse Performance 92 分,老板(哦不,是我自己)看了直呼内行。


开发心得:现代化 ≠ 复杂化

折腾这一周,最大的感悟是:所谓“现代化”,不是堆砌最新技术,而是用合适的工具解决真实问题

在大厂时,我们曾为了“技术先进性”强行上微前端,结果构建流程复杂到 CI 经常超时,本地调试要启五个服务。后来领导一句话点醒我:“用户只关心页面能不能点,不关心你用了 Webpack 还是 Vite。”

所以这次,我没上 Nx,没搞 Monorepo,没写 Cypress E2E(暂时)。一切以快速迭代、清晰维护为目标。代码可读性优先于 clever code,稳定交付优先于炫技。


最后:重启职业生涯的底气

今天凌晨两点,我把项目部署到 Vercel,打开手机扫码预览——丝滑的交互动画、清晰的错误提示、秒开的首屏。那一刻,Gap 半年的焦虑仿佛被清空了。

我知道,重新找工作不会一帆风顺。但至少,当我面对面试官问“你怎么理解现代前端工程化”时,我不再只能背八股文,而是能掏出这个亲手打磨的项目,指着每一行配置说:“这里,是我踩过的坑;这里,是我思考后的选择。”

如果你也在裸辞、转行、或只是想写点干净的代码——别怕从零开始。键盘还在,屏幕还亮,我们就还没输。

(PS:项目已开源,README 里写了详细搭建步骤。欢迎 star,更欢迎 issue 吐槽——毕竟,程序员的快乐,就是互相帮对方 debug 啊。)

评论 0

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