Skip to content
This repository has been archived by the owner on Feb 9, 2021. It is now read-only.

webpack optimization option #19

Open
lbwa opened this issue Jun 24, 2018 · 1 comment
Open

webpack optimization option #19

lbwa opened this issue Jun 24, 2018 · 1 comment
Labels
various means anything else

Comments

@lbwa
Copy link
Owner

lbwa commented Jun 24, 2018

webpack chunk optimization

Chunk loading

Chunk 优化原理

如果两个 chunk 包含相同的 modules,那么这些相同的 modules 将会合并为一个。这种情况下可能导致 chunks 有多个 parents

如果一个 chunk 的所有 parents 都有一个相同的 modules,那么该 modules 将被从该 chunk 中移除。

如果一个 chunk 包含所有其他 chunk 的所有模块,那么该 chunk 将被存储,因为该 chunk 能适用于多个 chunk

Chunk types

  • Entry chunk

包含一串 runtime (即运行时)的 modules,如果 chunk 包含 module 0 那么 runtime 会立即执行该 chunk。如果不是,那么等待包含 module 0chunk 执行完成之后再执行该 chunk(每次打包都会生成一个包含 module 0chunk )。

  • Normal chunk

一个正常不包含 runtimechunk。该 chunk 的结构依赖于 chunk 的加载算法。

  • Initial chunk (non-entry)

一个初始 chunk 也是一个 normal chunk。不同之处在于初始 chunk 的优化是非常重要的,因为他被计算在初始加载时间内(如,入口 chunk

  • webpack 默认启用优化情形
  • 应该分离 modules 的情形可查看官方示例

optimization.runtimeChunk

official site

即分离仅包含 runtime 的代码块,形成单独的一个 chunk,命名为 runtime chunk,它与应用源代码是引用关系。那么可利用该特点进行浏览器常缓存。

在应用源代码发生改变时,其 contentHash 发生变化,但是此时的 runtime chunk 因与源代码非包含关系,那么 runtime chunk 内容没有发生变化,也就不会影响 runtime chunk 的浏览器常缓存。

一般 runtime chunk 其中是 webpack 对其各个 chunk 的引用机制,它用于处理不同的 chunk 的执行关系,即它是直接与 webpack 相关的代码,而与业务源代码无关的代码。

module.exports = {
  // ...
  optimization: {
    runtimeChunk: {
      name: 'runtime'
    }
  }
}

optimization.runtimeChunk 默认为 false。那么每一个 entry chunk 都将包含 runtime

optimization.splitChunks

webpack 默认优化配置如下:

以下值均为默认值

module.exports = {
  //...
  optimization: {
    splitChunks: {
      /**
       * 指定需要优化的 chunk。 string | Function
       * 
       * 1. 'all' 即指明为所有 chunk,即可理解为表示所有可在异步和非异步 chunk 之间
       *    共享的模块。
       * 2. 'async' 异步的 chunk,即分离所有异步 chunk,与 import ('./a') 语法配合
       *    使用。
       * https://webpack.js.org/plugins/split-chunks-plugin/#defaults-example-1
       * 3. 'initial' 同步的 chunk
       * 4. 可被 `splitChunks.cacheGroups` 中的同名选项覆盖
       * 5. 可结合 HtmlWebpackPlugin 的配置来注入所有生成的 vendor chunks。
       */
      // 即默认地,webpack 将异步 chunk 单独分离出来。
      chunks: 'async',

      // 最小 chunk 体积。 number
      minSize: 30000,

      // 分离前必须共享的最小 chunks 数。 number
      minChunks: 1,
      
      // 按需加载时并行请求的最大数。number
      maxAsyncRequests: 5,

      // 入口处的最大并行请求数 number
      maxInitialRequests: 3,

      // 默认情况下,webpack 以来源和 chunk 名来命名生成的 chunk
      // 例如 vendors~main.js
      // 该选项允许你指定生成名字的连字符
      automaticNameDelimiter: '~',

      // 分离生成的 chunk 的名字 boolean: true | Function | string
      // 默认基于 chunk 的键名和 cacheGroups 的键名生成
      // 可提供一个 string 或 Function 自定义名字
      // 可被 `splitChunks.cacheGroups` 中的同名选项覆盖
      name: true,

      /**
       * 缓存组,即应该被浏览器常缓存的第三方库。 object
       * 
       * 1. 其中的选项可继承或覆盖外部任意 `splitChunks.*` 选项,除了 `test`, 
       *    `priority`, `reuseExistingChunk` 只能在该选项内配置
       * 2. splitChunks.cacheGroups.default: false 即可关闭
       */
      cacheGroups: {
        // 一个缓存组,在其内部未指明 name 的情况下,使用该键名命名生成的 chunk
        vendors: {
          /**
           * 指定哪些 modules 应该被该缓存组缓存。 RegExp | string
           * 
           * 1. 未指定时,将选择所有 modules。
           * 2. 可选择一个绝对路径的资源或 chunk 名,当一个 chunk 被选定时,其中所有
           *    的module 同样将被选定。
           * 3. 在搭配形如 chunk: 'all' 选项可选择在被选中的 modules 中哪些
           *    modules 应该被缓存
           */
          test: /[\\/]node_modules[\\/]/,

          // 一个 module 可属于多个缓存组,但 optimization 会将 module 优先缓存于高
          // 优先级的缓存组 number
          priority: -10
        },
        // 默认的缓存组
        default: {
          // 分离前必须共享的最小 chunk 数,可覆盖外部同名选项。number
          minChunks: 2,

          // 如前文所述,遇到可加入多个缓存组的 module 时,优先级将低于 vendor 缓存组
          priority: -20,

          // 若符合默认条件组的 module 已经被最近从主 bundle 分离出的 chunk 包含,那
          // 么重用这个 module,而不是生成新的 chunk。这会影响最终生成的 chunk 的文件名。
          reuseExistingChunk: true
        }
      }
    }
  }
}
/**
 * 应该分离 modules 的情形
 * https://webpack.js.org/plugins/split-chunks-plugin/#defaults-example-1
 * 
 * 1. chunk 包含了来自 node_modules 的 modules
 * 2. 1 的 modules 大小超过 30 kb,若 chunk 将其包含在内将影响首轮加载
 * 3. 不影响初始页面加载的 modules
 * 4. 不经常修改的代码,即应该被浏览器常缓存的代码,如 1 中的第三方库。
 * 
 * https://webpack.js.org/plugins/split-chunks-plugin/#defaults-example-2
 * 
 * 5. 可被不同页面共享的 chunk
 */

// 创建一个 `commons` chunk,它包含所有入口共享的所有代码
// 此举将增加初始 bundles 的体积,只在需要动态引入时推荐使用
module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        // 一个缓存组,仅当内部未指定 name 选项时,名字以键名指定
        commons: {
          name: 'commons',

          // 缓存所有初始的 modules,即排除所有异步 modules,将动态导入的文件和非动态导入的文件
          // 分别打包
          chunks: 'initial',
          minChunks: 2
        }
      }
    }
  }
}

// 创建一个 `vendors` chunk,它包含所有应用中需要的第三方库
module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        commons: {
          // 指明为 node_modules 被依赖的 modules
          test: /[\\/]node_modules[\\/]/,

          // 名为 vendors 的缓存组,键名 commons 仅在未指明 name 时生效。
          name: 'vendors',

          // 将所有符合 test 选项的 modules 缓存
          chunks: 'all'
        }
      }
    }
  }
}
@lbwa lbwa added the various means anything else label Jun 24, 2018
@lbwa
Copy link
Owner Author

lbwa commented Jun 24, 2018

webpackrollup 打包组件的差异:

  • webpack 所构建的结果包含 runtime(亦可称为 manifest,即用于协调各个 chunk 之间运行的代码),即包含引导 chunk 加载的代码。webpack 侧重于综合性(多资源,不仅限于 JS)打包,即应用打包,他构建了一系列应用的 chunk 之间的加载最优解。

  • rollup 仅包含入口的源代码及其相关依赖模块,他与 webpack 所打包的侧重点是不同的,rollup 侧重整体功能模块的打包,即类库打包。那么 rollup 就没有类似 webpackruntime 来引导 chunk ,因为他将所有的源代码模块整合压缩于一个包内,包内也仅仅包含入口源代码及其相关依赖模块。rollup 的侧重点就是整合压缩源代码,他并不做代码分割等相关事情。rollup 正因为不包含 runtime 的引导 chunk 的额外代码,这对于类库打包来说也是极好的事情,因为正好可以极限地压缩类库代码。

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
various means anything else
Projects
None yet
Development

No branches or pull requests

1 participant