编译阶段优化
对于 Compiler 实例⽽⾔,耗时最⻓的显然是⽣成编译过程实例后的 make 阶段,在这个阶段⾥,会执⾏模块编译到优化的完整过程。
对于 Compilation 实例的⼯作流程来说,不同的项⽬和配置各有不同,但总体⽽⾔,编译模块和后续优化阶段的⽣成产物并压缩代码的过程都是⽐较耗时的。
真正影响整个构建效率的还是 Compilation 实例的处理过程,即编译模块和优化处理。
编译模块阶段所耗的时间是从单个⼊⼝点开始,编译每个模块的时间的总和。要提升这⼀阶段的构建效率,⼤致可以分为三个⽅向:
- 减少执⾏构建的模块。
- 提升单个模块构建的速度。
- 并⾏构建以提升总体效率。
减少执⾏构建的模块
-
IgnorePlugin
可在构建模块时直接剔除那些需要被排除的模块,从⽽提升构建模块的速度,并减少产物体积。
有的依赖包,除了项⽬所需的模块内容外,还会附带⼀些多余的模块。典型的例⼦是 moment 这个包,⼀般情况下在构建时会⾃动引⼊其 locale ⽬录下的多国语⾔包;但对于⼤多数情况⽽⾔,项⽬中只需要引⼊本国语⾔包即可。⽽ Webpack 提供的 IgnorePlugin 即可在构建模块时直接剔除那些需要被排除的模块,从⽽提升构建模块的速度,并减少产物体积。new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/, })
-
按需引⼊类库模块
⼀般适⽤于⼯具类库性质的依赖包的优化,典型例⼦是 lodash 依赖包。
要解决这个问题,效果最佳的⽅式是在导⼊声明时只导⼊依赖包内的特定模块,这样就可以⼤⼤减少构建时间,以及产物的体积。还可以使⽤ babel-plugin-lodash 或 babel-plugin-import 等插件达到同样的效果。
另外,Tree Shaking,这⼀特性也能减少产物包的体积,但是这⾥有两点需要注意:- Tree Shaking 需要相应导⼊的依赖包使⽤ ES6 模块化,⽽ lodash 还是基于 CommonJS,需要替换为 lodash-es 才能⽣效。
- 相应的操作是在优化阶段进⾏的,换句话说,Tree Shaking 并不能减少模块编译阶段的构建时间。
-
DllPlugin
核⼼思想是将项⽬依赖的框架等模块单独构建打包,与普通构建流程区分开。 -
Externals
Webpack 配置中的 externals 和 DllPlugin 解决的是同⼀类问题:将依赖的框架等模块从构建过程中移除。它们的区别在于:- 在 Webpack 的配置⽅⾯,externals 更简单,⽽ DllPlugin 需要独⽴的配置⽂件。的
- DllPlugin 包含了依赖包独⽴构建流程,⽽ externals 配置中不包含依赖框架的⽣成⽅式,通常使⽤已传⼊ CDN 的依赖包。
- externals 配置的依赖包需要单独指定依赖模块的加载⽅式:全局对象、CommonJS、AMD 等。
- 在引⽤依赖包的⼦模块时,DllPlugin ⽆须更改,⽽ externals 则会将⼦模块打⼊项⽬包中。
提升单个模块构建的速度
-
include/exclude
include 的⽤途是只对符合条件的模块使⽤指定 Loader 进⾏转换处理。⽽ exclude 则相反,不对特定条件的模块使⽤该 Loader。- 通过 include/exclude 排除的模块,并⾮不进⾏编译,⽽是使⽤ Webpack 默认的 js 模块编译器进⾏编译(例如推断依赖包的模块类型,加上装饰代码等)。
- 在⼀个 loader 中的 include 与 exclude 配置存在冲突的情况下,优先使⽤ exclude 的配置,⽽忽略冲突的 include 部分的配置。
-
noParse
Webpack 配置中的 module.noParse 则是在上述 include/exclude 的基础上,进⼀步省略了使⽤默认 js 模块编译器进⾏编译的时间。 -
Source Map
对于⽣产环境的代码构建⽽⾔,会根据项⽬实际情况判断是否开启 Source Map。在开启 Source Map 的情况下,优先选择与源⽂件分离的类型,例如 "source-map"。 -
TypeScript 编译优化
Webpack 中编译 TS 有两种⽅式:使⽤ ts-loader 或使⽤ babel-loader。
在使⽤ tsloader 时,由于 ts-loader 默认在编译前进⾏类型检查,因此编译时间往往⽐较慢,通过加上配置项 transpileOnly: true,可以在编译时忽略类型检查,从⽽⼤⼤提升 TS 模块的编译速度。
babel-loader 则需要单独安装 @babel/preset-typescript 来⽀持编译 TS(Babel 7 之前的版本则还是需要使⽤ ts-loader)。 -
Resolve
Webpack 中的 resolve 配置制定的是在构建时指定查找模块⽂件的规则,例如:- resolve.modules:指定查找模块的⽬录范围。
- resolve.extensions:指定查找模块的⽂件类型范围。
- resolve.mainFields:指定查找模块的 package.json 中主⽂件的属性名。
- resolve.symlinks:指定在查找模块时是否处理软连接。
并⾏构建以提升总体效率
-
HappyPack 与 thread-loader
这两种⼯具的本质作⽤相同,都作⽤于模块编译的 Loader 上,⽤于在特定 Loader 的编译过程中,以开启多进程的⽅式加速编译。HappyPack 诞⽣较早,⽽ thread-loader 参照它的效果实现了更符合 Webpack 中 Loader 的编写⽅式。 -
parallel-webpack
并发构建的第⼆种场景是针对于多配置构建。Webpack 的配置⽂件可以是⼀个包含多个⼦配置对象的数组,在执⾏这类多配置构建时,默认串⾏执⾏,⽽通过 parallel-webpack,就能实现相关配置的并⾏处理。