从零开始构建一个现代化前端项目:一个大专生的血泪复盘

Rerank观察员
2025-12-16 20:47
阅读 706

大家好,我是小李,一个刚毕业半年的大专计算机应届生。现在在北京一家中型互联网公司做前端开发,每天通勤一小时(早高峰10号线真的能挤到灵魂出窍)。别看我学历一般,但靠着自学前端,在校期间死磕 JavaScript + Vue,还顺手搞了个 GitHub 小作品集,居然真拿到了 offer——虽然工资不高,但够我在五环外合租活下去了。

说起来有点惭愧,入职前我以为“会写页面”就是前端的全部。结果第一个月就被安排重构一个老后台系统,产品那边天天催:“这个功能双11前必须上线!”、“用户反馈加载太慢了!”、“能不能加个暗色模式?”……而我,一个连 Webpack 都没配过的人,面对满屏的 Uncaught TypeError: Cannot read property 'xxx' of undefined,一度想回老家考编。

但人嘛,总得成长。这半年来,我硬着头皮从零搭起一个现代化前端项目,踩了无数坑,也攒了些经验。今天就来技术分享一下我的完整流程——不是教科书式的“最佳实践”,而是真实世界里一个普通前端仔怎么在 deadline 和产品经理的双重夹击下,把一个项目跑起来、跑稳、还能让测试小姐姐少提几个 bug 的故事。


起因:产品经理又改需求了

事情要从去年双11说起。我们团队负责一个 B 端 SaaS 产品,原本是 jQuery + Bootstrap 写的“祖传代码”,性能差、维护难、UI 还像十年前。老板拍板重做,让我牵头搭新架构(其实是因为 senior 哥们跳槽了,锅甩给我了)。

PM 周一晨会扔来一份 PRD:“我们要 PWA、支持离线、首屏秒开、还要 SSR 提升 SEO……对了,下周 demo 给客户看。”
我当时差点一口老血喷在 Vim 上——没错,我是个 Vim 党,JetBrains?那是什么?能吃吗?

但抱怨归抱怨,活还得干。我意识到:不能再用“能跑就行”的思维了,得整一套现代化的工程体系。


第一步:选型——别被 hype 带偏了

现在前端框架多得眼花缭乱,React/Vue/Svelte/... 我司之前用 Vue 2,团队熟悉度高,所以果断选 Vue 3 + TypeScript + Vite。理由很现实:

  • 学习成本低(我只会 Vue)
  • Vite 启动快(再也不用等 Webpack 编译等到泡面凉了)
  • TS 能减少低级错误(上次我把 user.name 写成 user.nane,线上崩了半小时)

📌 安全意识 tip:别盲目追新!新工具可能有未知漏洞。比如某次我用了社区一个热门 UI 库,结果发现它依赖的某个包偷偷收集用户数据——赶紧删了,吓得我连夜扫了一遍 package-lock.json

初始化项目很简单:

npm create vue@latest my-product
# 一路回车,记得勾上 TypeScript、Pinia、Router
cd my-product
npm install

Vite 默认配置已经很现代了:ESBuild 预构建、HMR 热更新快如闪电。我甚至能在 Vim 里改一行代码,浏览器自动刷新,爽到飞起。


第二步:目录结构——别让代码变成意大利面条

很多新手(包括曾经的我)喜欢把所有文件堆在 src/components 下。结果三个月后,找一个组件比找对象还难。

参考了公司老项目的惨痛教训,我定了这套结构:

src/
├── assets/          # 静态资源
├── components/      # 公共组件(Button, Modal)
├── views/           # 页面级组件(HomePage, UserList)
├── composables/     # Vue 3 Composition API 逻辑抽离
├── stores/          # Pinia 状态管理
├── services/        # API 请求封装
├── utils/           # 工具函数(debounce, formatDate)
├── router/          # 路由配置
├── types/           # TS 类型定义
└── main.ts

关键点:按功能分,不按文件类型分。比如用户模块相关的组件、API、store 都放在 features/user/ 下(后来才加的,初期偷懒没分,后悔死了)。


第三步:API 层——别再裸奔 fetch 了

以前我直接在组件里写 fetch('/api/user'),结果:

  • 错误处理到处重复
  • token 过期了不会自动刷新
  • 测试时 mock 数据麻烦

现在我用 axios 封装了一层:

// services/api.ts
import axios from 'axios'

const api = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 10000,
})

// 请求拦截器:自动加 token
api.interceptors.request.use(config => {
  const token = localStorage.getItem('token')
  if (token) config.headers.Authorization = `Bearer ${token}`
  return config
})

// 响应拦截器:统一错误处理
api.interceptors.response.use(
  response => response.data,
  error => {
    if (error.response?.status === 401) {
      // token 过期,跳登录页
      localStorage.removeItem('token')
      window.location.href = '/login'
    }
    return Promise.reject(error)
  }
)

export default api

这样,组件里调用超干净:

// composables/useUser.ts
import api from '@/services/api'

export function fetchUser() {
  return api.get('/user')
}

💡 安全提醒:永远不要在前端存敏感信息!token 用 HttpOnly Cookie 更安全,但我们后端没配合,只能先这样。下次一定推动他们改!


第四步:状态管理——Pinia 真香

Vuex 太重了,配置一堆 mutations/actions。Pinia 直接用函数式 API,清爽:

// stores/user.ts
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', () => {
  const user = ref<User | null>(null)
  
  const login = async (credentials: Credentials) => {
    const data = await api.post('/login', credentials)
    user.value = data.user
    localStorage.setItem('token', data.token)
  }

  const logout = () => {
    user.value = null
    localStorage.removeItem('token')
  }

  return { user, login, logout }
})

在组件里直接解构使用,TypeScript 还能自动推导类型,再也不用担心拼错 state 名字了。


第五步:性能优化——用户可不管你是谁

产品最常问:“为什么加载这么慢?” 其实大部分问题出在资源加载策略上。

1. 代码分割(Code Splitting)

Vite + Vue Router 天然支持路由级懒加载:

// router/index.ts
const routes = [
  {
    path: '/dashboard',
    component: () => import('@/views/Dashboard.vue') // 自动分块
  }
]

2. 图片优化

别再直接丢原图了!我们用 vite-plugin-imagemin 压缩:

// vite.config.ts
import viteImagemin from 'vite-plugin-imagemin'

export default defineConfig({
  plugins: [
    viteImagemin({
      gifsicle: { optimizationLevel: 7 },
      optipng: { optimizationLevel: 7 },
      mozjpeg: { quality: 20 },
      pngquant: { quality: [0.65, 0.8] }
    })
  ]
})

3. 首屏加速:Critical CSS + 骨架屏

  • 把首屏用到的 CSS 内联到 HTML(Vite 插件 critters 自动搞定)
  • 列表页加骨架屏,用户不再盯着白屏发呆

性能对比(Lighthouse 评分)

指标 重构前 重构后
首屏时间 4.2s 1.1s
Lighthouse 性能分 38 89
Bundle 体积 2.1MB 680KB

看到这个数据,产品终于闭嘴了(暂时)。


第六步:安全与合规——别等出事才后悔

作为前端,很多人觉得安全是后端的事。但 XSS、CSRF、数据泄露,前端也是重灾区!

我做的几件事:

  1. XSS 防御:所有用户输入内容,用 DOMPurify 清洗
    import DOMPurify from 'dompurify'
    const clean = DOMPurify.sanitize(dirtyHTML)
    
  2. CSP 配置:在 index.html 加 Content Security Policy
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' https://trusted.cdn.com">
    
  3. 敏感操作二次确认:删除按钮必须弹窗确认,防误触
  4. 日志脱敏:错误上报时自动过滤手机号、身份证等字段

⚠️ 血泪教训:上周五晚上加班,测试突然说“用户密码明文显示在控制台”——原来是我调试时忘了删 console.log(user)。赶紧全局搜 console.log,加了个 ESLint 规则禁止提交。


第七步:自动化与协作——别当独行侠

一个人写代码爽,但团队协作必须规范。

我们团队落地的流程:

  • Git 提交规范:用 commitlint + husky,强制格式 [feat|fix|docs]: description
  • PR 模板:每次合并必须填“改动点”、“测试方案”、“影响范围”
  • GitHub Actions:自动跑单元测试 + 构建预览
    # .github/workflows/ci.yml
    name: CI
    on: [push, pull_request]
    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
          - run: npm ci
          - run: npm run test:unit
          - run: npm run build
    

最爽的是:每次 push,GitHub 自动部署一个临时链接给 PM 预览,再也不用听他说“你本地跑给我看”。


最后:Rust?哦,那是下班后的事

写这篇文章时,我已经能比较从容地应对日常开发了。最近还在业余研究 Rust——不是为了转岗,纯粹觉得它的内存安全和并发模型太酷了。说不定哪天能用 Rust 写个 WASM 模块,给前端提速?

回头看看,从那个连 git rebase 都不会的大专生,到现在能独立搭建项目架构,靠的不是天赋,而是:

  • 大量试错(删库跑路的心都有过)
  • 善用开源(GitHub 是最好的老师)
  • 保持警惕(安全不是选修课)

如果你也和我一样,学历普通、起点不高,别慌。前端世界足够大,容得下一个愿意死磕的普通人。

最后吐个槽:今天 PM 又说“加个 AI 功能吧,让用户上传图片自动生成文案”……我默默打开了 GitHub,搜索 “AI image to text”。兄弟们,救救孩子!


附:我的学习资源清单(真实用过)

共勉。

评论 0

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