dll

DllPlugin 是另一类减少构建模块的方式,它的核心思想是将项目依赖的框架等模块单独构建打包,与普通构建流程区分开。例如,原先一个依赖 React 与 react-dom 的文件,在构建时,会如下图般处理:
image.png
而在通过 DllPlugin 和 DllReferencePlugin 分别配置后的构建时间就变成如下图所示,由于构建时减少了最耗时的模块,构建效率瞬间提升十倍。
image.png
webpack内置了DLLPlugin,主要包含两个插件:

DllPlugin:打包出dll文件,先进行一遍预打包,生成dll文件
DLLReferencePlugin:在开发环境使用dll文件
一般需单独定义一个dll.config.js

  1. output: {
  2. path: path.join(__dirname, '../build'), // 放在项目的/build目录下面
  3. filename: '[name].dll.js', // 打包文件的名字
  4. library: '[name]_library' // 可选 暴露出的全局变量名
  5. // vendor.dll.js中暴露出的全局变量名。
  6. // 主要是给DllPlugin中的name使用,
  7. // 故这里需要和webpack.DllPlugin中的`name: '[name]_library',`保持一致。
  8. },
  9. plugin
  10. new webpack.DllPlugin({
  11. path: path.join(__dirname, '../build', '[name]_manifest.json'), // 生成上文说到清单文件,放在当前build文件下面,这个看你自己想放哪里了。
  12. name: '[name]_library',
  13. context: __dirname,
  14. }),


定义dll命令,进行dll打包
最后输出dll和manifest文件。dll文件就是所有打包的文件内容。manifest作用为索引,负责引导实际对于dll里模块的引用。
实际应用中,需要在dev的html中进行script引用,可用DLLReferencePlugin插件引用manifest文件,AddAssetHTMLPlugin引用dll文件即可。

tree-shaking

Tree Shaking(摇树)是指在构建打包过程中,移除那些引入但未被使用的无效代码(Dead-code elimination)。这种优化手段最早应用于在 Rollup 工具中,而在 Webpack 2 之后的版本中, Webpack 开始内置这一功能。下面我们先来看一下 Tree Shaking 的例子,如下面的表格所示:
image.png
可以看到,引入不同的依赖包(lodash vs lodash-es)、不同的引入方式,以及是否使用 babel 等,都会对 Tree Shaking 的效果产生影响。下面我们就来分析具体原因。

  1. ES6 模块: 首先,只有 ES6 类型的模块才能进行Tree Shaking。因为 ES6 模块的依赖关系是确定的,因此可以进行不依赖运行时的静态分析,而 CommonJS 类型的模块则不能。因此,CommonJS 类型的模块 lodash,在无论哪种引入方式下都不能实现 Tree Shaking,而需要依赖第三方提供的插件(例如 babel-plugin-lodash 等)才能实现动态删除无效代码。而 ES6 风格的模块 lodash-es,则可以进行 Tree Shaking 优化。
  2. 引入方式:以 default 方式引入的模块,无法被 Tree Shaking;而引入单个导出对象的方式,无论是使用 import * as xxx 的语法,还是 import {xxx} 的语法,都可以进行 Tree Shaking。
  3. sideEffects:在 Webpack 4 中,会根据依赖模块 package.json 中的 sideEffects 属性来确认对应的依赖包代码是否会产生副作用。只有 sideEffects 为 false 的依赖包(或不在 sideEffects 对应数组中的文件),才可以实现安全移除未使用代码的功能。在上面的例子中,如果我们查看 lodash-es 的 package.json 文件,可以看到其中包含了 “sideEffects”:false 的描述。此外,在 Webpack 配置的加载器规则和优化配置项中,分别有 rule.sideEffects(默认为 false)和 optimization.sideEffects(默认为 true)选项,前者指代在要处理的模块中是否有副作用,后者指代在优化过程中是否遵循依赖模块的副作用描述。尤其前者,常用于对 CSS 文件模块开启副作用模式,以防止被移除。
  4. Babel:在 Babel 7 之前的babel-preset-env中,modules 的默认选项为 ‘commonjs‘,因此在使用 babel 处理模块时,即使模块本身是 ES6 风格的,也会在转换过程中,因为被转换而导致无法在后续优化阶段应用 Tree Shaking。而在 Babel 7 之后的 @babel/preset-env 中,modules 选项默认为 ‘auto’,它的含义是对 ES6 风格的模块不做转换(等同于 modules: false),而将其他类型的模块默认转换为 CommonJS 风格。因此我们会看到,后者即使经过 babel 处理,也能应用 Tree Shaking。

    前端工程化精

    scope-hosting

    该插件只适用于webpack直接处理es6模块。
    针对NPM中第三方模块优先采用jsnext:main中指向es6模块化语法的文件
    大型工程中模块引用层级一般较深,产生较长引用链,Scope Hosting可将纵深的引用链拍平,使得模块本身和其引用的其他模块作用域处同级,可去掉一部分webpack附加代码减小资源体积。
    作用:代码体积更小,创建函数作用域更少,代码可读性更好。
    使用方式:
    引入webpack内部插件 ModuleConcatenationPlugin插件(默认在生产模式下已启用,若要在其他模式下启用concatenation,可手动添ModuleConcatenationPlugin或用optimization.concatenateModules选项) ```javascript module.exports = { resolve: {

    1. mainFields: ['jsnext:main', 'browser', 'main'] // 针对npm中的第三方模块优先采用jsnext:main中指向的ES6模块化语法的文件

    }, plugins: [

    1. new webpack.optimize.ModuleConcatenationPlugin() // 开启Scope Hoisting

    ] }

```