前端工程化:我在实战中走过的那些路

开源搬砖工
2025-06-15 23:43
阅读 392

我是李晨,目前在一家中型互联网公司担任前端开发工程师。从业六年多来,我参与过不少项目,从最开始的简单页面重构,到如今主导中后台系统的前端架构设计和工程化建设。说实话,刚入行的时候,我对“前端工程化”这个概念并没有太多感知,觉得不就是写代码、调试样式、用个 Webpack 构建一下嘛?直到后来接手了一个复杂度颇高的中台项目,才发现自己对工程化的理解简直皮毛。

那次项目是我职业生涯中一次重要的转折点。项目本身业务逻辑庞大,模块众多,团队协作频繁,性能问题频发……当时我们团队里五六个前端,开发节奏一度非常混乱,每个人都在自己的小天地里写代码,构建流程不稳定、环境配置差异大、部署出错也找不到原因,上线后更是各种兼容性和性能问题层出不穷。

痛定思痛之后,我和团队决定彻底重构整个项目的工程体系。这篇文章,就来聊聊我在那个过程中踩过的坑、学到的经验,以及现在我们正在使用的一套相对成熟的工程化解决方案。


项目背景与挑战:一个“看似简单”的中台项目

项目背景与挑战:一个“看似简单”的中台项目

当时的项目是一个企业级 SaaS 平台,面向的是中小企业的 IT 管理人员。虽然不是特别复杂的 ToC 类产品,但涉及到权限控制、数据可视化、大量表单交互等典型中后台功能。技术栈上,我们选择了 Vue3 + TypeScript + Vite 的组合。

一开始我们搭建了个简单的项目骨架,大家就开始各自分工开发了。但没过多久,我们就发现了一些明显的问题:

  • 构建效率低下:随着组件数量增加,Vite 的热更新变慢,甚至有时候会卡住。
  • 版本控制混乱:不同人的依赖版本不一致,有人本地跑得好好的,一合并代码就报错。
  • 打包体积臃肿:最终 build 出来的文件动辄几 MB,加载速度极慢。
  • 缺乏统一规范:命名、目录结构、代码风格随意,新同事看别人的代码像读天书。
  • 自动化程度低:每次上线都需要手动打包上传,容易出错。
  • 测试覆盖率低:基本没有单元测试或 E2E 测试,上线前靠手动点击测试,漏测频频发生。

这些问题直接影响了我们的开发效率和线上稳定性。那段时间,我每天早上打开 Slack 都能收到 QA 提的各种 bug,有些甚至只是因为某个依赖版本不对导致的,真的很让人头疼。


解决方案:重新梳理前端工程链路

解决方案:重新梳理前端工程链路

既然问题这么多,那我们就得从头梳理整条工程链路了。我把这次重构划分为以下几个核心部分:

1. 初始化脚手架与项目结构标准化

我们决定不再直接 vite create,而是基于 pnpm 创建了一个内部的 monorepo 结构,并封装了自己的 CLI 工具用于初始化新项目(模仿了 @ant-design/cli 和 create-react-app 的方式)。

pnpm create my-project

这个 CLI 脚手架工具包含了统一的目录结构模板、基础组件库引入、全局样式处理和默认的配置文件,确保每个新项目开箱即用。

目录结构示例:

src/
│
├── assets/            # 静态资源
├── components/        # 公共组件
├── layout/            # 页面布局组件
├── pages/             # 页面路由组件
├── services/          # API 封装层
├── store/             # Pinia 状态管理
├── router/            # 路由配置
├── utils/             # 工具函数
├── App.vue
└── main.ts

2. 开发阶段的协作优化

使用 pnpm + Turborepo 进行依赖管理和缓存加速

我们在 monorepo 中集成了 Turborepo,这让多个子项目的依赖管理和任务执行变得高效了很多。比如我们可以并行运行多个 package 的 lint 或 test,极大提升了 CI 效率。

// turbo.json
{
  "pipeline": {
    "lint": {
      "cache": true
    },
    "test": {
      "dependsOn": ["^lint"]
    }
  }
}

统一 ESLint + Prettier + Stylelint

为了让代码风格统一,我们在项目中集成了以下规则:

  • eslint-config-airbnb-typescript
  • @typescript-eslint/eslint-plugin
  • prettier
  • stylelint-scss(针对 SCSS)

并在 VSCode 中启用保存自动格式化,强制提交前检查风格。这一步大大减少了 review 时的风格争议。


3. 性能优化与打包策略

自动分包 + 动态导入

我们利用 Vite 内置的自动分包机制,结合 import() 实现懒加载路由组件。同时对于大型三方库(如图表库 ECharts),我们也进行了动态导入,减少主包体积。

// 示例:懒加载组件
const MyLazyComponent = defineAsyncComponent(() => import('@/components/LazyComponent.vue'));

图片压缩 + SVG Sprite

静态资源方面,我们集成了 image-minimizer-webpack-plugin,在构建时自动压缩图片,并将所有图标转换为 SVG Sprites,减少请求数量。


4. 自动化流程集成

我们搭建了一套完整的自动化流程:

环节 工具 目的
开发规范 Husky + lint-staged 提交前代码检查
CI GitHub Actions / Jenkins 自动化测试、打包
CD Docker + Nginx + Ansible 容器化部署
发布通知 Dingtalk Bot 上线通知 & 日志反馈

通过这些工具,我们实现了从提交代码 → 触发 CI → 打包 → 部署 → 通知的完整闭环。


5. 监控与错误收集

我们在生产环境中集成了 Sentry,用来捕获 JS 异常和接口失败信息,并且结合 source map 上传功能,可以在报错时看到具体哪一行出了问题。

import * as Sentry from '@sentry/browser';
Sentry.init({
  dsn: 'https://xxx@sentry.io/project',
  integrations: [new Sentry.BrowserTracing()],
});

代码实践:几个关键配置片段

代码实践:几个关键配置片段

为了让大家更直观了解,我挑几个比较常用的配置贴出来。

🧰 Vite 配置示例

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import tsconfigPaths from 'vite-tsconfig-paths';

export default defineConfig({
  plugins: [vue(), tsconfigPaths()],
  optimizeDeps: {
    include: ['lodash-es', 'axios'],
  },
  build: {
    outDir: 'dist',
    rollupOptions: {
      output: {
        manualChunks(id) {
          if (id.includes('node_modules')) {
            return id.toString().split('node_modules/')[1].split('/')[0];
          }
        },
      },
    },
  },
});

🔍 ESLint 配置(简化版)

JavaScript框架对比-2

module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'prettier',
  ],
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
};

💼 GitHub Action 部署流程(简化)

name: Build and Deploy

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '18'
      - run: npm install
      - run: npm run build

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying to staging..."

踩坑经验分享:那些年我们一起掉进去的地方

❌ 热更新卡顿问题

最初我们用 Vue3 + Vite 开发时,热更新越来越慢。后来发现是某些组件引入了大量的第三方库,或者过度使用响应式变量造成的。我们做了两个优化:

  • 把大型依赖移出 watch 列表;
  • 对于不需要响应式的对象使用 markRaw 标记。

⚠️ Git Hooks 不生效

刚开始集成 Husky 时,发现提交代码并不会触发 eslint 检查。后来才发现是因为没有执行 husky install,导致 hooks 没有正确挂载。

建议大家安装完 husky 后记得运行:

npx husky install
npx husky add .husky/pre-commit "npm run lint"

🧵 多人协作下的 cache 冲突

Turborepo 默认开启了本地缓存,但在多人协同开发下会导致某些 cache 被污染。后来我们改为远程 cache 存储在 AWS S3,避免本地冲突。


实施后的效果和收益

经过两个月的努力,我们将整个项目的工程化体系建立起来,取得了明显的效果:

  • 构建速度快了 2~3 倍
  • 上线事故减少了 70% 以上
  • 新人上手时间缩短了 60%
  • 代码 Review 时间节省了 40%

更重要的是,我们团队的协作变得更加高效了,每个人都可以专注于业务逻辑而不是基建工作。


我的经验总结和建议

用户交互流程图-1

作为一名经历过工程化阵痛的开发者,我真心建议大家:

✅ 越早重视工程化越好

不要等到项目做大了才开始考虑这些问题。工程化就像盖房子的地基,前期花些力气,后期才能稳稳当当。

✅ 投资工具链=投资团队效率

一套好的脚手架、清晰的目录结构、自动化的流程,能让每个成员的工作更加聚焦,也更容易形成团队标准。

✅ 让工具帮你做重复的事

包括格式化、校验、测试、部署,尽可能自动化,减少人为操作带来的失误。

✅ 保持开放心态,持续迭代

工程化不是一锤子买卖,而是一个不断演进的过程。随着项目增长,你也需要不断地去调整构建策略、监控机制、错误上报等等。


写在最后:工程化不仅是个技术问题

其实我觉得,工程化不仅仅是写好一份 webpack.config.js,它更像是一种思维方式——如何把零散的代码、松散的流程组织成一个稳定、可持续发展的系统。

在我参与的每一次项目重构中,我都会回头去看当初自己写的那些“草稿式代码”,然后感慨:要是早点学工程化就好了!

如果你也是前端开发的一员,不妨从现在开始,着手优化你的项目结构、搭建你的 lint 流程、试一试自动化的发布机制。哪怕只迈出一小步,未来回头看的时候,你会发现这条路值得每一分努力。

愿你在编码的路上越走越远,一起写出更有质量的代码 🚀

如果这篇文字对你有帮助,欢迎在评论区交流你的工程化实践经历,我很乐意和大家一起探讨~

评论 0

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