浅谈前端工程化理解

浅谈前端工程化理解

前言

本文是个人学习实践过程中的记录及理解,如有错漏欢迎指出。

相关知识来源于哲玄前端(抖音ID:44622831736)大前端全栈实践课程

什么叫前端工程化?

一句话概括:把前端开发流程系统化、自动化、规范化,让代码像"产品"一样可以被构建、测试、部署和维护。 其中包括 规范、工具链、流程、体系

而这样的"工业流水线"为了解决这些痛点:

  • 代码无规范 → 难维护
  • 手工构建、发布 → 易出错、效率低
  • 页面越来越复杂 → 打包体积、性能成瓶颈
  • 团队协作缺乏统一 → 冲突频繁,复用差
  • 上线风险高 → 缺少测试、监控、回滚机制

工程化涉及的核心环节

  1. 开发阶段

    • 模块化 / 组件化

      • JS 模块化( ESMCommonJS
      • CSS 模块化( CSS Modules、预处理器)
      • 组件化(React/Vue/Svelte 等)
    • 语法增强

      • Babel/SWC 转译,TypeScript 静态类型
      • PostCSSLessSass
    • 代码规范

      • ESLintPrettierStylelint
      • Git hooks
      • Commit message 规范( commitlint, conventional commits
  2. 构建阶段

    • 打包构建工具WebpackViteRollup
    • 资源优化Tree ShakingCode Splitting、懒加载
    • 多环境配置dev/test/staging/prod
  3. 测试阶段

    • 单元测试JestVitestMocha
    • 集成测试CypressPlaywright
    • 端到端测试(E2E) :保证整体业务流程正确
  4. 发布 & 运维阶段

    • 持续集成 / 持续部署(CI/CD)GitHub ActionsGitLab CIJenkins
    • 自动化构建:push → 构建 → 测试 → 部署 → 通知
    • 灰度发布 / A/B 测试 / 版本回滚
    • CDN 缓存、前端监控(埋点、性能、错误上报)
  5. 协作 & 维护

    • Monorepo/ 多包管理TurborepoLerna
    • 文档体系Storybookdocusaurustypedoc
    • 脚手架 / 模板化Vue CLI 等)
    • 持续优化:性能指标、包体积分析、依赖治理

随着前端技术愈发成熟和工作团队的扩张,开发过程中我们会愈发注重模块化、组件化、类型约束、代码编程规范等,诞生出包括像 EggSalis 等奉行"约定优于配置" 的框架,以及课程中的 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。

    java 复制代码
    module.exports = {
        devServer: {
          static: './dist',
          hot: true,
        }
    }

    等多关于 webpack-dev-server 的配置详情可以查看这里

    其工作原理:

    • 监控到源文件发生改变
    • 重新构建打包到指定位置(一般为内存)
    • 通知应用程序资源发生改变,检查更新
    • 应用程序异步下载更新,并同步应用更新

    如果我们使用自定义服务器启用 HMR 会发现:

    • webpack-dev-middleware 负责监控源文件的改变,并按传入编译器重新构建。
    • webpack-hot-middleware 负责监测更新信息,并通知应用程序更新。
    • HotModuleReplacementPlugin 接收更信信息后,完成下载并应用更新。

优化

  • 分包

    项目在开发过程中,我们会复用部分代码以提升开发效率,但在打包时这部分代码会根据入口文件引用重复打包到多个入口的 chunk 中,这很明显不是我们希望的。

    这时便需要为打包工具添加分包策略,虽然像 webpack 具有默认分包策略,但默认情况下,它只会影响到按需加载的 chunks。

    我们想要获得的分包情况:

    • 体积较大、不常更改的独立第三方库及生态依赖,如 VuePinia ➡︎ Vue

    • 剩余的第三方库 ➡︎ vendor 包

    • 公共业务代码 ➡︎ common 包

    • 不符合上诉情况,根据入口配置正常打包

    如果 UI 库使用的是按需加载,建议单独分为一个包,避免因为加载的组件前后不一,第三方库的包 contenthash 等改变,导致缓存失效。

    这样分包的好处是可以使用浏览器可以并行下载的优势,并且不常改变的包可以被浏览器有效缓存起来。

    分包不是越多越好。首先服务器不支持http2.0的情况不支持多路复用,浏览器(谷歌)只能同时并发同域名的6个请求,零碎的 chunk 可能会增加 请求数(即使 HTTP/2/3 也有开销),所以请权衡利弊后再按需求制定分包策略。

  • 优化 loader 转译过程

    • 利用多线程加速耗时操作

      使用 happypackthread-loader 帮助开启线程池,将工作交给多个工作线程处理。

      thread-laoderwebpack 官方支持的,同时也支持缓存和 worker 复用,能缩短二次构建时间。

      happypack 已经停止维护,适合 webpack 旧版本使用。

      开启进程开销,小文件/轻量 loader 反而可能更慢。

      推荐仅在耗时的操作中使用,适合 CPU 密集型 loader。

      使用时也切勿开启过多工作线程将 CPU 占满,导致 I/O 操作切换频繁

    • 细分 loader 需要处理的范围,充分利用 includeexclude 等属性
  • 提取公共 css 样式并压缩体积

    • 使用 mini-css-extract-plugin 根据 CSS 文件中的样式使用情况,将公共部分提取到一起

      此插件不能与 loader 链中的 style-loader 一同使用!!!

      可按需求配合 splitChunks.cacheGroups 分包,可将提取到的 CSS 文件放到一个独立文件中。

      yaml 复制代码
      splitChunks: {
            cacheGroups: {
              styles: {
                type: "css/mini-extract", // type 用于匹配 .css 文件
                name: "styles",
                chunks: "all", 
                enforce: true, // 强制执行
              },
            },
          },
    • css-minimizer-webpack-plugin 将提取出来的 CSS 资源进行压缩

  • 压缩 js 文件体积

    Terseresbuild 皆是优秀的解析器/压缩器工具集。

    • 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 转换前的源码映射(更精确)。
  • 合理使用浏览器缓存,给产物文件添加 contenthashhashchunkHash 的设置
  • 打开构建缓存落盘,加快二次构建
  • 充分运用 tree-shaking (树摇)

以上便是此次学习的全部总结,当然这些只是构建知识的部分应用,更是前端工程化工作中的冰山一角,未来还有许多知识、理念需要了解与掌握,希望能抛砖引玉,如果有更多有意思的知识,欢迎分享。

相关推荐
艾小码5 小时前
新人必看!3天啃下大型前端项目,我是这样做到的
前端
袁煦丞5 小时前
宝塔FTP远程文件管理+安全防护:cpolar内网穿透实验室第417个成功挑战
前端·程序员·远程工作
三十_5 小时前
【NestJS】构建可复用的数据存储模块 - 动态模块
前端·后端·nestjs
干就完了15 小时前
js数组方法,其实也就这么多东西,一篇全搞懂
前端·javascript
JIE_5 小时前
【Hero动画】用一个指令实现Vue跨路由/组件动画
前端
aidingni8885 小时前
Comet浏览器不为人知的故事
前端·javascript
Cache技术分享5 小时前
182. Java 包 - 创建和使用 Java 包
前端·后端
libokaifa5 小时前
C++ 基础学习
前端·架构·github
_前端小李_5 小时前
关于this指向
前端·javascript