webpack4初次尝试
webpack以配置驱动,繁琐的配置也成为了webpack进一步发展的障碍,零配置的打包构建工具如雨后春笋。webpack4对配置要求降低了很多,甚至entry和output也非必配项。
-
mode属性
即默认策略配置,分为开发和生产环境(development/production),常用的配置以及配置好默认值。默认值为production。devlopment针对开发环境做了优化,production针对生产环境做了优化。
-
分包插件升级
commonChunkPlugin -> optimization.splitChunks and runtimeChunk 或者 splitChunksPlugin and runtimeChunkPlugin插件形式, 分包插件优化升级。CommonChunksPlugin 会找到多数模块中都共有的东西,并且把它提取出来,里面可能会存在一些当前模块不需要的东西。SplitChunksPlugin分包更加细腻,公用的模块会被拆分成多个独立的包,可以保证加载进来的代码一定是会被依赖到的。
// 配置案例 { optimization: { splitChunks: { cacheGroups: { commons: { chunks: "initial", minChunks: 2, maxInitialRequests: 5, minSize: 30000 }, vendor: { test: /node_modules/, chunks: "initial", name: "vendor", priority: 10, enforce: true } } } } } // webpack4 源码 if (options.optimization.splitChunks) new SplitChunksPlugin(options.optimization.splitChunks).apply(compiler);
-
webpack4根据下述条件自动进行代码块分割:
-
新代码块可以被共享引用,OR这些模块都是来自node_modules文件夹里面
-
新代码块大于30kb(min+gziped之前的体积)
-
按需加载的代码块,最大数量应该小于或者等于5
-
初始加载的代码块,最大数量应该小于或等于3
-
-
splitChunksPlugin配置项解析
-
test 限制范围,以 module 为单位控制 chunk 的抽取范围,是一种细粒度比较小的方式。
-
chunks 值为”all”, “async”(默认) 或 “initial”,分别代表了全部 chunk,按需加载的 chunk 以及初始加载的 chunk。
-
minChunks entry引用次数大于此值则分包,默认为1
-
minSize 包的大小超过此值则分包,默认为30KB,太小体积的代码块被分割,可能还会因为额外的请求,拖慢加载性能
-
name 包名称
-
maxInitialRequests 一个入口最大的并行请求数, 也就是最大初始化chunks,设置过大容易导致分包过细,http请求数量过多,触发浏览器同域名并发限制,默认为3
-
maxAsyncRequests 最大异步请求chunks,即按需加载时候最大的并行请求数,默认为5
-
cacheGroups 默认模式会将所有来自node_modules的模块分配到一个叫vendors的缓存组;所有重复引用至少两次的代码,会被分配到default的缓存组。一个模块可以被分配到多个缓存组,优化策略会将模块分配到高优先级别(priority)的缓存组,或者会分配到可以形成更大体积代码块的组里。
缓存组会继承splitChunks的配置。
// webpack4 splitChunks配置项的默认值源码 this.set("optimization.splitChunks", {}); this.set("optimization.splitChunks.chunks", "async"); this.set("optimization.splitChunks.minSize", 30000); this.set("optimization.splitChunks.minChunks", 1); this.set("optimization.splitChunks.maxAsyncRequests", 5); // 打包分隔符, 如:vendors~chunkA~chunkB.js this.set("optimization.splitChunks.automaticNameDelimiter", "~"); this.set("optimization.splitChunks.maxInitialRequests", 3); this.set("optimization.splitChunks.name", true); this.set("optimization.splitChunks.cacheGroups", {});
-
-
runtimeChunkPlugin 添加一个只包含运行时(runtime)额外代码块到每一个入口
-
-
混淆压缩升级
UglifyjsWebpackPlugin -> optimization.minimize
-
动态引入模块
Webpack 4,官方提供了sideEffects属性,通过将其设置为false,可以主动标识该类库中的文件只执行简单输出,并没有执行其他操作,可以放心shaking。除了可以减小bundle文件的体积,同时也能够提升打包速度。为了检查side effects,Webpack需要在打包的时候将所有的文件执行一遍。而在设置sideEffects之后,则可以跳过执行那些未被引用的文件。
Tree shaking一直是一个美丽而遥不可及的话题,它是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码。这个术语和概念实际上是兴起于 ES2015 模块打包工具 rollup。可以简单地理解为摇树,抖落掉枯萎无用的树叶。影响tree shaking的根本原因在于side effects(副作用),其中最广为人知的一条side effect就是动态引入依赖的问题。ES6其实也提供import()方法支持动态引入依赖,所以以下写法其实也是完全可行的。
webpack 2.0 开始原生支持 ES Module,也就是说不需要 babel 把 ES Module 转换成曾经的 commonjs 模块了,要使用 Tree Shaking,请关闭 babel 默认的模块转义。
if(Math.random() > 0.5) { import('./a.js').then(() => { ... }) } else { import('./b.js').then(() => { ... }) }
-
作用域提升
ModuleConcatenationPlugin -> optimization.concatenateModules。scope hoisting的效果同样也依赖于静态分析。带来的好处是,减少bundle体积,较少不必要的作用域。
//开启前 [ /* 0 */ function(module, exports, require) { var module_a = require(1) console.log(module_a['default']) } /* 1 */ function(module, exports, require) { exports['default'] = 'module A' } ] //开启后 [ function(module, exports, require) { var module_a_defaultExport = 'module A' console.log(module_a_defaultExport) } ]
-
多进程之HappyPack
HappyPack就能让Webpack把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程,其中子进程的个数为cpu的个数减去1,需要在loader处修改如下
// loader中修改为
use: 'happypack/loader?id=babel',
// plugin中添加
new HappyPack({
id: 'babel',
//如何处理.js文件,和rules里的配置相同
loaders: [{
loader: 'babel-loader',
query: {
presets: [
"env", "stage-0"
]
}
}]
}),