浅谈前端工程化理解
前言
本文是个人学习实践过程中的记录及理解,如有错漏欢迎指出。
相关知识来源于
哲玄前端(抖音ID:44622831736)大前端全栈实践课程
什么叫前端工程化?
一句话概括:把前端开发流程系统化、自动化、规范化,让代码像"产品"一样可以被构建、测试、部署和维护。 其中包括 规范、工具链、流程、体系。
而这样的"工业流水线"为了解决这些痛点:
- 代码无规范 → 难维护
- 手工构建、发布 → 易出错、效率低
- 页面越来越复杂 → 打包体积、性能成瓶颈
- 团队协作缺乏统一 → 冲突频繁,复用差
- 上线风险高 → 缺少测试、监控、回滚机制
工程化涉及的核心环节
-
开发阶段
-
模块化 / 组件化:
- JS 模块化(
ESM、CommonJS) - CSS 模块化(
CSS Modules、预处理器) - 组件化(
React/Vue/Svelte等)
- JS 模块化(
-
语法增强:
Babel/SWC转译,TypeScript静态类型PostCSS、Less、Sass等
-
代码规范:
ESLint、Prettier、StylelintGit hooksCommit message规范(commitlint,conventional commits)
-
-
构建阶段
- 打包构建工具 :
Webpack、Vite、Rollup - 资源优化 :
Tree Shaking、Code Splitting、懒加载 - 多环境配置 :
dev/test/staging/prod
- 打包构建工具 :
-
测试阶段
- 单元测试 :
Jest、Vitest、Mocha - 集成测试 :
Cypress、Playwright - 端到端测试(E2E) :保证整体业务流程正确
- 单元测试 :
-
发布 & 运维阶段
- 持续集成 / 持续部署(CI/CD) :
GitHub Actions、GitLab CI、Jenkins - 自动化构建:push → 构建 → 测试 → 部署 → 通知
- 灰度发布 / A/B 测试 / 版本回滚
- CDN 缓存、前端监控(埋点、性能、错误上报)
- 持续集成 / 持续部署(CI/CD) :
-
协作 & 维护
Monorepo/ 多包管理 (Turborepo、Lerna)- 文档体系 (
Storybook、docusaurus、typedoc) - 脚手架 / 模板化 (
Vue CLI等) - 持续优化:性能指标、包体积分析、依赖治理
随着前端技术愈发成熟和工作团队的扩张,开发过程中我们会愈发注重模块化、组件化、类型约束、代码编程规范等,诞生出包括像 Egg、Salis 等奉行"约定优于配置" 的框架,以及课程中的 eplis-core ,这些工具能够帮助团队按照 一套统一的约定 开发应用,帮助开发团队和开发人员降低开发和维护成本。
这些涉及开发阶段的工具和操作应该是工作中经常遇到,是我们所熟悉的。这时应该意识到,不是仅仅"用 webpack 等打包工具就是工程化" ,其实我们一直参与到某个 理念 + 实践体系 中,其目标是 用工程化方法论去管理和优化前端开发的整个生命周期。
我们接触最多的除开发阶段外,便是构建阶段,该产出与我们系统性能息息相关。
工程化构建
开发一个系统通常会涉及到大量的代码,为了提升开发效率,也为了方便团队管理维护,开发者会像上述按照一定的约定或规范进行开发。
而浏览器并不能完全直接识别这些文件,所以我们需要将其转换成浏览器(或者某个应用)能够识别、执行的文件,然后在浏览器中完成页面展示。
这时,借助打包工具,我们可以大大缩短人力成本,仅通过一条命令,便可让工具按照预设的配置一步到位输出预想产物。这将极大地提高打包效率。
那么这些工具做了什么呢?
它会按照我们提供的入口文件,读取与之相关的模块及依赖,按照我们提供的规则,规定何种类型文件使用何种 解析器 (某些解析器需借助额外的插件,如 vue-loader)解析编译,转译完成后打包输出,我们可以将其注入到某个页面中,便可获得浏览器能够识别、执行的页面。
不过这仅仅是冰山一角,现打包工具拥有成熟的插件机制,具备很高的可扩展性,可根据自己的业务场景定制配置,从而极大降低了应用的开发成本。
本次学习中使用的工具是
webpack,所以用webpack举例。但请注意,什么工具不重要,只要能实现你想要的效果。
比如:
-
混用 SPA + MPA
通常 单页面应用 (SPA) 通过插件按照指定模板生成一个 HTML 文件,将 chunk 全部注入该页面,打包出一个入口(通常是
index.html)。而页面内容的变化,通过 前端路由 + JS 动态渲染 来完成,用户点击链接时,不会重新请求整个页面,而是局部更新。✅ 优点:
- 前后端分离,前端控制路由与渲染,交互流畅。
- 体验接近原生 App,切换页面不卡顿。
- 资源可缓存,后续访问快。
❌ 缺点:
- 首屏加载慢(要加载完整的 JS 框架、路由、业务逻辑)。-
- SEO 不友好(因为页面内容由 JS 渲染)。
- 复杂应用里,打包体积大,可能影响性能。
而多页面应用 (MPA) 则是每个页面对应一个 独立的 HTML 文件 ,请求新页面时,浏览器会重新加载 HTML、CSS、JS,页面之间 没有前端路由的强绑定,切换页面会整页刷新。
✅ 优点:
- 首屏快(直接返回服务端渲染好的 HTML)。
- SEO 友好(内容直接在 HTML 中,搜索引擎容易抓取)。
- 适合业务隔离(不同页面可以独立构建、独立部署)。
❌ 缺点:
- 页面切换慢,每次都要重新加载资源。
- 前后端耦合度高,不便于前后端分离。
- 公共资源(JS/CSS)可能重复加载。
为了 平衡体验、性能、维护成本,我们可以适当结合两者,通过多入口打包,但每个入口内部又是一个 SPA。
以
webpack为例,我们提供多个打包入口配置,借助HtmlWebpackPlugin插件根据入口配置生成相应的 HTML 文件,其会将每个打包入口配置中文件所引用的资源分别注入到各自的 HTML 文件中,从而生成多个 系统入口。这时每个 SPA 内部用 前端路由(Vue Router、React Router) 管理页面切换,而系统入口通过 服务端路由 控制访问。
-
热更新
模块热替换(hot module replacement 简称 HMR) 是
webpack提供的功能之一。webpack提供了 HMR 功能,需做的仅需更新webpack-dev-server的配置,便使用webpack内置的 HMR 插件。如果你在技术选型中使用了
webpack-dev-middleware而没有使用webpack-dev-server,请使用webpack-hot-middleware依赖包,以在你的自定义服务器或应用程序上启用 HMR。javamodule.exports = { devServer: { static: './dist', hot: true, } }等多关于
webpack-dev-server的配置详情可以查看这里。其工作原理:
- 监控到源文件发生改变
- 重新构建打包到指定位置(一般为内存)
- 通知应用程序资源发生改变,检查更新
- 应用程序异步下载更新,并同步应用更新
如果我们使用自定义服务器启用 HMR 会发现:
webpack-dev-middleware负责监控源文件的改变,并按传入编译器重新构建。webpack-hot-middleware负责监测更新信息,并通知应用程序更新。HotModuleReplacementPlugin接收更信信息后,完成下载并应用更新。
优化
-
分包
项目在开发过程中,我们会复用部分代码以提升开发效率,但在打包时这部分代码会根据入口文件引用重复打包到多个入口的
chunk中,这很明显不是我们希望的。这时便需要为打包工具添加分包策略,虽然像
webpack具有默认分包策略,但默认情况下,它只会影响到按需加载的 chunks。我们想要获得的分包情况:
-
体积较大、不常更改的独立第三方库及生态依赖,如
Vue、Pinia➡︎Vue包 -
剩余的第三方库 ➡︎ vendor 包
-
公共业务代码 ➡︎ common 包
-
不符合上诉情况,根据入口配置正常打包
如果
UI库使用的是按需加载,建议单独分为一个包,避免因为加载的组件前后不一,第三方库的包contenthash等改变,导致缓存失效。这样分包的好处是可以使用浏览器可以并行下载的优势,并且不常改变的包可以被浏览器有效缓存起来。
分包不是越多越好。首先服务器不支持http2.0的情况不支持多路复用,浏览器(谷歌)只能同时并发同域名的6个请求,零碎的 chunk 可能会增加 请求数(即使 HTTP/2/3 也有开销),所以请权衡利弊后再按需求制定分包策略。
-
-
优化
loader转译过程-
利用多线程加速耗时操作
使用
happypack、thread-loader帮助开启线程池,将工作交给多个工作线程处理。✅
thread-laoder是webpack官方支持的,同时也支持缓存和 worker 复用,能缩短二次构建时间。❌
happypack已经停止维护,适合webpack旧版本使用。有 开启进程开销,小文件/轻量 loader 反而可能更慢。
推荐仅在耗时的操作中使用,适合 CPU 密集型 loader。
使用时也切勿开启过多工作线程将 CPU 占满,导致 I/O 操作切换频繁。
- 细分
loader需要处理的范围,充分利用include、exclude等属性
-
-
提取公共
css样式并压缩体积-
使用 mini-css-extract-plugin 根据 CSS 文件中的样式使用情况,将公共部分提取到一起
此插件不能与 loader 链中的
style-loader一同使用!!!可按需求配合
splitChunks.cacheGroups分包,可将提取到的 CSS 文件放到一个独立文件中。yamlsplitChunks: { cacheGroups: { styles: { type: "css/mini-extract", // type 用于匹配 .css 文件 name: "styles", chunks: "all", enforce: true, // 强制执行 }, }, }, -
css-minimizer-webpack-plugin 将提取出来的 CSS 资源进行压缩
-
-
压缩
js文件体积Terser与esbuild皆是优秀的解析器/压缩器工具集。EsbuildPlugin拥有极致的性能,但压缩产物体积稍大一些。TerserWebpackPlugin拥有海量配置,兼容性强,可以进行非常激进的代码压缩和转换,往往能得到最小的产物体积。
这是一场"时间换空间"的经典权衡。
EsbuildPlugin用微不足道的空间(体积略增)换取了巨大的时间节省(构建速度飞跃),而TerserWebpackPlugin则愿意花费更多时间来打磨出体积最小的代码。 对于大多数现代项目而言,esbuild带来的开发体验提升往往比那一点点的体积优化更有价值。
-
source-map映射源根据不同环境选择不同策略选择一种 source map 风格来增强调试过程。不同的值会明显影响到构建(build)和重新构建(rebuild)的速度。
arduino// webpack 通过配置项 devtool 切换 devtool: "[inline-|hidden-|eval-][cheap-[module-]]source-map"eval-→ 用eval()包裹模块,构建快。inline-→ source map 直接内联到 JS 中。hidden-→ 生成 map 文件,但不在 JS 里声明引用。cheap-→ 只映射到行,不包含列,不包含 loader 前的源码。module-→ 包含 loader 转换前的源码映射(更精确)。
- 合理使用浏览器缓存,给产物文件添加
contenthash、hash、chunkHash的设置
- 打开构建缓存落盘,加快二次构建
- 充分运用
tree-shaking(树摇)
以上便是此次学习的全部总结,当然这些只是构建知识的部分应用,更是前端工程化工作中的冰山一角,未来还有许多知识、理念需要了解与掌握,希望能抛砖引玉,如果有更多有意思的知识,欢迎分享。