从零搭起一个现代化前端项目,我踩过的坑比你走的路还多

马桂英
2025-12-27 13:11
阅读 869

上周五晚上十点半,我戴着 AirPods 半躺在工位上,一边听着 Lo-fi Hip Hop 一边疯狂敲键盘。窗外是上海徐家汇熟悉的霓虹——没错,我又在公司附近的小单间里“驻扎”加班了。事情起因很简单:我们技术中台要孵化一个新工具链,前端部分完全从零开始。领导说:“你不是一直嚷嚷着想用最新技术栈吗?这次给你机会。”
我嘴上说“好啊”,心里却咯噔一下——上次这么自信地接活,还是去年双11前重构购物车组件,结果线上白屏三分钟,被产品追着问“是不是故意搞破坏”。

但话说回来,作为上市公司技术中台的一员,写可维护、可扩展、可读性高的代码,本就是基本修养。这次项目虽然小,但麻雀虽小五脏俱全:需要对接 Spring Boot 后端、支持 CI/CD、具备完善的测试和文档、还要能快速部署到 GitHub Pages 做 Demo。更关键的是——这玩意儿将来可能会放进我的求职作品集里。毕竟,谁不想跳槽时甩出一个干净利落、架构清晰的 GitHub 项目呢?


起手式:别一上来就 npm create-react-app

很多人一想到“现代化前端项目”,第一反应就是 create-react-app 或者 Vite + React。但说实话,在企业级场景下,这种脚手架生成的项目往往只是个起点。真正的挑战在于:如何组织目录、管理依赖、统一规范、集成工具链

我们的目标很明确:

  • 技术栈:TypeScript + Vite + React 18 + Tailwind CSS
  • 工程化:ESLint + Prettier + Husky + lint-staged
  • 测试:Vitest + React Testing Library
  • 部署:GitHub Actions 自动构建并发布到 GitHub Pages
  • 文档:集成 Storybook,组件即文档

听起来是不是有点重?但相信我,在中台团队,这种配置已经是“轻量级”了。我们甚至砍掉了微前端和模块联邦——毕竟不是每个项目都需要那么“高大上”。


目录结构:可读性才是第一生产力

我见过太多项目把所有 hooks 塞进 utils 文件夹,把 API 请求散落在各个 component 里。每次接手都像考古。所以这次我坚持一个原则:按功能划分,而非按技术类型划分

src/
├── features/          # 业务功能模块(如 auth, dashboard)
├── shared/            # 跨模块复用逻辑
│   ├── components/    # 公共组件(带 Storybook)
│   ├── hooks/         # 自定义 hooks
│   ├── lib/           # 工具函数、第三方封装
│   └── types/         # 全局 TS 类型
├── app/               # 应用入口、路由、全局状态
├── assets/            # 静态资源
└── main.tsx           # 启动文件

这样做的好处是:当你想改“用户登录”逻辑时,直接去 features/auth 里找,不用在十几个文件夹里来回跳转。产品经理说“登录页加个验证码”,我也能三分钟定位到对应组件,而不是翻半天 components/Auth/LoginForm.tsx


和 Spring Boot 联调:跨域不是玄学

后端同事用的是 Spring Boot,跑在本地 localhost:8080。前端 Vite 默认 localhost:5173。第一次联调,控制台直接给我甩了个经典错误:

Access to fetch at 'http://localhost:8080/api/login' from origin 'http://localhost:5173' has been blocked by CORS policy.

我差点以为自己配错了 URL。结果一问后端,人家根本没开 CORS。Spring Boot 默认是禁止跨域的,得手动加配置:

@Configuration
public class CorsConfig {
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(Arrays.asList("http://localhost:5173"));
        config.setAllowedMethods(Arrays.asList("*"));
        config.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/api/**", config);
        return source;
    }
}

当然,上线后我们会用 Nginx 统一代理,避免跨域问题。但在开发阶段,前后端分离调试是常态。所以我在 vite.config.ts 里也加了代理:

export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },
});

现在前端直接请求 /api/login,Vite 会自动转发到后端。再也不用担心 CORS 报错让我怀疑人生了。


Git 提交规范:Husky + lint-staged 救我狗命

我们团队有个不成文规定:PR 里不能有 ESLint 错误或格式混乱的代码。以前靠 Code Review 人工检查,效率低还伤感情。后来我引入了 Husky + lint-staged,提交前自动 fix:

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

配合 Husky 的 pre-commit 钩子,每次 git commit 都会自动格式化代码。虽然偶尔会因为 Prettier 把单引号改成双引号被同事吐槽,但至少 PR 里的 diff 不再是满屏红色了。


部署到 GitHub Pages:一键发布不是梦

为了方便展示和求职,我把项目部署到了 GitHub Pages。配置其实超简单,只需要两步:

  1. vite.config.ts 中设置 base

    export default defineConfig({
      base: '/my-awesome-project/', // 注意和仓库名一致
    });
    
  2. 写一个 GitHub Actions workflow:

# .github/workflows/deploy.yml
name: Deploy to GitHub Pages

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npm run build
      - uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./dist

每次推到 main 分支,Action 自动构建并发布。Demo 地址立刻生效。面试时直接甩链接:“这是我独立搭建的项目,源码在 GitHub,欢迎 Star~”


性能与兼容性:别让用户等得想卸载

虽然项目不大,但我还是做了些基础优化:

优化项 措施 效果
Bundle Size 使用 vite-bundle-visualizer 分析 移除 unused lodash,体积 ↓30%
图片懒加载 <img loading="lazy"> 首屏加载快 0.8s
浏览器兼容 browserslist 配置支持到 Chrome 80+ 避免用太新的 JS 特性
错误边界 自定义 ErrorBoundary 组件 防止白屏,提升用户体验

特别吐槽一点:有些同学为了炫技用 ProxyReflect 搞花里胡哨的状态管理,结果 IE11 用户(对,我们还有!)一打开就报 Uncaught ReferenceError: Proxy is not defined。老板问起来,你说“现在谁还用 IE”,但客户偏偏就是那 0.5% 的用户。


最后:写代码是为了让人看懂,不是让机器运行

回过头看,这个项目从零到上线只用了两周。过程中踩过 Vite 插件冲突的坑、被 TypeScript 泛型绕晕过、也因为 GitHub Actions 权限问题熬到凌晨。但最终,它成了我 GitHub 上 star 最多的项目(虽然只有 23 个……)。

更重要的是,代码结构清晰、文档齐全、测试覆盖,连实习生都能快速上手修改。这才是“现代化前端项目”的真正意义——不是堆砌最新框架,而是打造一个可持续演进的工程体系。

如果你也在准备求职,不妨从一个小而美的项目开始。别只写 TodoList 了,试试对接真实后端、写单元测试、做自动化部署。这些细节,才是面试官眼里“靠谱工程师”的分水岭。

对了,项目地址在这:github.com/yourname/my-awesome-project(名字当然是假的)。Star 不重要,但 issue 欢迎提——说不定下次团建,我就请你喝瑞幸了。

(耳机里的音乐刚好切到下一首,是 The Weeknd 的《Blinding Lights》。嗯,该回家了,明天还得和产品 battle “这个按钮能不能再大 2px”。)

评论 0

最热最新
暂无评论
马桂英Lv.1
0
影响力
0
文章
0
粉丝