学习elpis工程化

53 阅读3分钟

引言:

见名知意,本文主要是对工程化阶段的elpis学习总结,结合学习过程和日常开发过程,来自述一下工程化的必要性和重要性,学习内容来源于抖音“哲玄前端”《大前端全栈实践》

工程化的实现:

前端工程化通常指用工具链 + 流程 + 规范,把前端开发从“人肉写页面”变成“高效、可维护、可协作的工程,一是要模块化/组件化,解决代码复用和依赖管理,二是要规范化,可以包括代码规范,commit规范,项目结构规范,三是要利用各种工具,如webpack,vite等实现自动化构建,再是实现自动化测试,自动化部署,让前端开发变得高效、可维护、可协作、可持续交付。

webpack

本文使用webpack5,解析步骤如下:

业务文件=>解析引擎(代码分割、解析编译、模块分包、TreeShaing、压缩优化等)=>产物文件,

解析引擎部分可以是webpack,vite等,工具方面不重要,主要是思想

单页面应用(SPA)通常只有一个输入文件,大部分情况下是main.js,且一般只需要输出一个 app.js

多页面应用(MPA)有多个输入文件,此处就是一个典型的多页面应用,入口文件是pageEntries,是一个对象,用 splitChunks 最大化缓存和复用,webpack 会为每个入口分别打包一份 JS,这样每个页面都有自己独立的业务代码​编辑

​编辑

模块分包

  // 配置打包输出优化(代码分割,模块合并,缓存,treeshaking,压缩等优化策略)
  optimization: {
    /**
     * 把JS文件打包成3种类型
     * 1.vender:第三方lib库,基本不会改动,除非依赖版本升级
     * 2.common:通用模块,业务组件代码的公共部分
     * 3.entry.{page}:不同页面entry里的业务组件代码的差异部分,会经常改动
     * 目的:把改动和引用频率不一样的js区分出来,以达到更好利用浏览器缓存的效果
     */
    splitChunks: {
      chunks: "all", //对同步异步模块都进行分割
      maxAsyncRequests: 10, //每次异步加载最大并行请求数
      maxInitialRequests: 10, //入口点的最大并行请求数
      cacheGroups: {
        vendor: {
          //第三方依赖库
          test: /[\/]node_modules[\/]/, //打包node_modules下的文件
          name: "vendor", //模块名称
          priority: 20, //优先级,越大越优先打包
          enforce: true, //强制执行
          reuseExistingChunk: true, //如果该chunk已经存在,则使用已有的chunk
        },
        common: {
          //公共模块
          name: "common", //模块名称
          minChunks: 2, //被两处引用即公共模块
          minSize: 1, //最小分割文件大小(1byte)
          priority: 10, //优先级
          reuseExistingChunk: true, //如果该chunk已经存在,则使用已有的chunk
        },
      },
    },
    // 将webpack运行时生成的代码打包到runtime.js
    runtimeChunk: true,
  },

从以上代码可见,在 MPASPA里,JS 文件通常包含三类内容:

  1. 第三方库(如Vue、Axios、Lodash、Element)

    • 体积大,但几乎不怎么变动
    • 最适合 单独抽离,长期缓存
  2. 公共业务模块(多个页面都会用到的工具函数、公共组件等)

    • 体积中等,改动频率低于业务代码
    • 可以 抽成 common 包,避免重复加载
  3. 页面独有的业务代码(即 entry.{page})

    • 改动频率高,业务差异化大
    • 不需要和其他模块混在一起,保持独立 chunk

核心目的是让改动少的 JS(vendor、common)长期缓存,让改动频繁的 JS(页面代码)独立更新

热更新(HotModuleReplacementPlugin)

HMR client 注入到入口,这里遍历所有入口,然后给每个入口(除了 vendor 第三方包)追加 HMR 客户端,追加的就是webpack-hot-middleware,用来建立长连接,当代码发生变化时,通知浏览器哪个地方变化了

Object.keys(baseConfig.entry).forEach((v) => {
  // 第三方包不作为hmr入口
  if (v !== "vendor") {
    baseConfig.entry[v] = [
      // 主入口文件
      baseConfig.entry[v],
      // hmr更新入口,官方指定hmr路径
      `webpack-hot-middleware/client?path=http://${DEV_SERVER_CONFIG.HOST}:${DEV_SERVER_CONFIG.PORT}/${DEV_SERVER_CONFIG.HMR_PATH}&timeout=${DEV_SERVER_CONFIG.TIMEOUT}&reload=true`,
    ];
  }
});