从零开始构建一个现代化前端项目:一个被简历逼疯的研二狗的自救指南

乐观锁玩家
2025-12-13 00:18
阅读 630

上周五晚上十一点半,实验室只剩我一个人。窗外下着小雨,键盘上泛着幽幽蓝光,耳机里放着《The Final Countdown》——不是因为多燃,纯粹是因为每次快跑路的时候都听这歌,算是某种玄学仪式了。

我盯着屏幕上刚收到的 HR 邮件:“感谢投递,但您的项目经历与岗位要求存在一定差距……”
淦!又挂了。这次是一家做低代码平台的 startup,职位描述写得天花乱坠:“熟悉现代前端工程化体系、有完整项目落地经验者优先”。我点开自己的 GitHub,除了课程作业和一个仿知乎的 React 小练习,几乎一片空白。

“简历上连个像样的项目都没有,怎么跟人竞争?”
那一刻,我突然明白了什么叫“代码人生”的残酷真相——不是你写了多少行代码,而是有没有能拿得出手的完整闭环

于是,我决定:从零开始,亲手搭一个现代化前端项目,不靠脚手架糊弄,每一步都要搞懂原理。


为啥不用 Create React App?因为它太“黑盒”了!

说实话,我之前也用 CRA(Create React App)快速起过项目。一键生成,热更新、ESLint、Babel 全配好了,美滋滋。但问题来了——一旦遇到配置冲突、性能瓶颈,或者想加个 Web Worker、自定义 Webpack 插件,你就得 eject,然后面对上千行的配置文件瑟瑟发抖。

在公司里,这种“魔法”是不被允许的。

我入职这家做 SaaS 工具的新公司已经两个月了。团队虽然小(就 5 个前端),但对工程规范极其严格。Leader 是个 Rust 转前端的老哥,天天念叨:“不要把工具当黑箱,否则线上炸了你只能祈祷。

果然,上个月双11大促前,我们一个页面加载慢到用户投诉。查了半天,发现是 CRA 默认没开代码分割(code splitting),首页 bundle 快 3MB!临时 hack 了一堆 dynamic import 才救回来。那天凌晨三点,我在 Slack 里发了个“我恨黑盒”,被运维老哥回了个“+1,我也恨”。

所以这次,我铁了心要手搓一套现代化前端架构,目标明确:

  • ✅ 使用 React 18 + TypeScript
  • ✅ 支持 Vite(快!真的快!)
  • ✅ 完整的 Linting & Formatting(告别团队 PR 里互相改格式)
  • 自动化测试(至少单元测试不能少)
  • 部署 CI/CD(虽然只是 GitHub Pages,但流程得走通)

第一步:初始化项目结构 —— 别再用 npm init 了!

以前我都是 npm init -y 走起,现在直接上 pnpm。为啥?速度快、磁盘省、依赖扁平化清晰。公司内部早统一用 pnpm 了,连测试同学都夸“装包终于不用等十分钟了”。

pnpm create vite my-resume-site -- --template react-ts
cd my-resume-site
pnpm install

📌 小贴士:Vite 的模板其实很干净,比 CRA 少了 80% 的冗余配置。而且默认支持 TS、JSX、CSS Modules,开箱即用。

但别急着跑 pnpm dev!先看看目录结构:

my-resume-site/
├── public/          # 静态资源(favicon、robots.txt)
├── src/
│   ├── assets/      # 图片、字体等
│   ├── components/  # 组件
│   ├── App.tsx
│   └── main.tsx
├── index.html       # 唯一 HTML 入口
├── tsconfig.json
└── vite.config.ts   # 核心配置文件

清爽!没有 node_modules 炸弹,没有隐藏的 .env.local 陷阱。


第二步:工程化基建 —— 让代码“长得好看”

在公司,PR(Pull Request)第一关就是 ESLint + Prettier。要是格式不对,CI 直接红掉,连 review 的机会都没有。所以我立马加上:

pnpm add -D eslint prettier typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin

然后一顿配置:

// .eslintrc.json
{
  "root": true,
  "parser": "@typescript-eslint/parser",
  "plugins": ["@typescript-eslint"],
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier"  // 必须放在最后,覆盖其他规则
  ],
  "rules": {
    "@typescript-eslint/no-explicit-any": "off", // 现实点,any 有时候真香
    "react/react-in-jsx-scope": "off" // React 17+ 不需要显式 import
  }
}
// .prettierrc
{
  "semi": false,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5"
}

再加个 Git Hook,提交前自动 fix:

pnpm add -D husky lint-staged
npx husky install
npx husky add .husky/pre-commit "npx lint-staged"
// package.json
{
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"]
  }
}

搞定!从此再也不用担心同事吐槽“你这缩进是 tab 还是空格?”


第三步:组件设计 —— 把简历变成可交互的艺术品

既然是做简历项目,那 UI 得有点意思。我参考了几个 Dribbble 上的设计,决定做成单页滚动 + 暗色主题 + 微交互动效

关键组件拆分:

  • <Header />:带滚动变色的导航栏
  • <Hero />:自我介绍 + 动态打字效果
  • <Projects />:卡片式项目展示(带 GitHub Star 数)
  • <Timeline />:教育/工作经历时间轴
  • <Contact />:表单 + 邮箱验证

滚动监听?别自己造轮子!

以前我傻乎乎地用 window.addEventListener('scroll', ...),结果性能差到掉帧。后来被 Leader 骂了一顿:“Intersection Observer 都出来多少年了?

现在直接上 react-intersection-observer

import { useInView } from 'react-intersection-observer'

const ProjectCard = ({ project }) => {
  const { ref, inView } = useInView({
    triggerOnce: true,
    threshold: 0.1,
  })

  return (
    <div
      ref={ref}
      className={`project-card ${inView ? 'animate-fade-in' : ''}`}
    >
      {/* 内容 */}
    </div>
  )
}

配合 CSS 动画,丝滑进场,毫无压力。


第四步:性能优化 —— 别让用户等成化石

公司最近搞 Lighthouse 评分竞赛,低于 90 分的请喝奶茶。我可不想破费,所以提前优化:

1. 图片懒加载 + WebP

简历里的项目截图全转 WebP,体积减少 60%。用 loading="lazy" 原生支持:

<img
  src="/projects/chat-app.webp"
  alt="Chat App"
  loading="lazy"
  width="400"
  height="240"
/>

2. 代码分割(Code Splitting)

首页只加载必要组件,其他路由动态导入:

const Projects = lazy(() => import('./components/Projects'))
const Timeline = lazy(() => import('./components/Timeline'))

function App() {
  return (
    <Suspense fallback={<Spinner />}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/projects" element={<Projects />} />
      </Routes>
    </Suspense>
  )
}

3. 预加载关键资源

index.html 里预加载字体和首屏 CSS:

<link rel="preload" href="/fonts/Inter.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/styles/main.css" as="style">

跑了个 Lighthouse,Performance 96,Accessibility 100 —— 可以去茶水间炫耀了。


第五步:测试 —— 别让 Bug 上线背锅

在公司,测试覆盖率低于 70% 的 PR 直接被打回。虽然我只是做个个人项目,但习惯不能丢。

Vitest + React Testing Library

pnpm add -D vitest @testing-library/react @testing-library/jest-dom jsdom

写个简单的 Header 测试:

// __tests__/Header.test.tsx
import { render, screen } from '@testing-library/react'
import Header from '../src/components/Header'

test('renders navigation links', () => {
  render(<Header />)
  expect(screen.getByText('Projects')).toBeInTheDocument()
  expect(screen.getByText('Contact')).toBeInTheDocument()
})

跑一下:

pnpm test
# PASS  __tests__/Header.test.tsx
# ✓ renders navigation links (12ms)

虽然只有 30% 覆盖率(别笑,总比没有强),但至少核心逻辑有保障。上线前心里踏实多了。


第六步:部署 —— 一键发布到全世界

最后一步,部署。公司用的是 AWS Amplify,但我个人项目图省事,直接上 GitHub Pages

Vite 官方提供了 vite-plugin-pagesgh-pages 集成方案:

pnpm add -D gh-pages
// package.json
{
  "scripts": {
    "deploy": "vite build && gh-pages -d dist"
  },
  "homepage": "https://yourname.github.io/my-resume-site"
}

注意:Vite 默认输出路径是 /,但 GitHub Pages 是子路径,所以得在 vite.config.ts 里加:

export default defineConfig({
  base: '/my-resume-site/', // 必须和 repo 名一致
})

然后:

pnpm run deploy

5 秒后,我的简历网站 live 了!
链接发到朋友圈,收获一堆“666”和“求源码”。


成果对比:手搓 vs 脚手架

项目 CRA 默认 手搓 Vite + TS
首次启动时间 8s 1.2s
生产包大小 (gzip) 1.8MB 420KB
Lighthouse Performance 72 96
自定义能力 低(需 eject)
学习成本 中(但值得)

吐槽与感悟:这届前端,卷不动也得卷

说实话,整个过程踩了不少坑:

  • 忘记在 vite.config.ts 里配 base,导致 GitHub Pages 白屏,折腾半小时
  • Intersection Observer 在 Safari 旧版本不兼容,得加 polyfill
  • 动态导入的 Suspense fallback 忘了写,网络慢时页面空白,差点被自己吓死

但每解决一个问题,对“现代化前端”的理解就深一层。不再是“会用 React 就行”,而是知道为什么这么配、怎么调优、如何保障质量

更重要的是——我的简历终于有了一个能点开看的项目!

上周我又投了一家公司,这次在简历里加了这个项目的链接和 GitHub 地址。HR 回复很快:“项目体验很好,技术栈也很新,约个面试吧?”

那一刻,我觉得熬夜写代码值了。


最后的小建议(给同样挣扎的你)

  1. 别怕从零开始:CRA/Vite CLI 虽好,但理解底层才能应对复杂场景
  2. 工程化不是炫技:它是为了解决协作、维护、性能这些真实痛点
  3. 简历项目 ≠ 完美项目:但一定要体现你的思考和解决问题的能力
  4. Rust 虽香,前端也得精进:毕竟我现在主业还是写 React(虽然晚上偷偷看《Rust 权威指南》)

对了,如果你也正在找工作,不妨花一周时间,亲手搭一个属于自己的现代化前端项目。不用多复杂,但一定要完整——从 init 到 deploy,每一步都留下你的思考痕迹。

毕竟,在这个“代码即简历”的时代,你的 GitHub,就是你最好的作品集。


作者碎碎念:我是某 211 软件工程研二狗,白天在实验室调模型,晚上在公司写 React,凌晨研究 Rust。
本文项目已开源:github.com/yourname/modern-resume(别点,假链接,但你可以自己建一个!)
如果觉得有用,欢迎点赞、转发、或者请我喝杯瑞幸(穷学生在线乞讨)。
下期预告:《用 Rust 写前端?WASM 实践踩坑实录》—— 敬请期待!

评论 0

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