1. 用户感知优化
-
友好错误提示
friendly-errors-webpack-plugin -
进度条
progress-bar-webpack-plugin -
编译完成弹出通知
webpack-build-notifier -
设置窗口标题
set-iterm2-badge -
直观显示webpack构建
webpack-dashboard/plugin
2. 构建速度优化
2.1 缩小命名范围
通过 test、include、exclude 三个配置项来命中 Loader 要应用规则的文件。为了尽可能少地让文件被 Loader 处理。
- 通过
include去命中只有哪些文件需要被处理 - resolve.modules
resolve.modules 的默认值是
node_modules,含义是先去当前目录的node_modules目录下去找我们想找的模块,如果没找到就去上一级目录../node_modules中找,再没有就去../../node_modules中找,以此类推。
可以指明存放第三方模块的绝对路径,以减少寻找
resolve : {
// 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
// 其中, dirname 表示当前工作目录,也就是项目根目录
modules: [path.resolve(__dirname,'node_modules')]
}
-
resolve.mainFields 配置第三方模块使用哪个入口文件,为了减少搜索步骤,在明确第 方模块的入口文件描述字段时,我们可以将它设置得尽量少
-
resolve.alia
-
resolve.extensions
有些 JavaScript 运行环境可能内置了一些全局变量或者模块,例如在script标签里通过以下代码引入 jQuery:
<script src=”path/to/jquery.js"></script>
这时,全局变量 jQuery 就会被注入网页的 JavaScript 运行环境里。
如果想在使用模块化的源代码里导入和使用 jQuery ,则可能需要这样:
import $ from 'jquery';
$('.my-element');
构建后我们会发现输出的 Chunk 里包含的 jQuery 库的内容,这导致 jQuery 库出现 了两次,浪费加载流量,最好是 Chunk 里不会包含 jQuery 库的内容
externals 可以告诉我们 webpack 在 javascript 运行环境中已经配置里哪些全局变量,不用将这些全局变量打包到代码中二十直接使用它们。
module.exports = {
externals: {
// 将导入语句里的 Jquery 替换成运行环境里的全局变量Jquery
Jquery: 'Jquery'
}
}
- module.noParse 忽略对部分没采用模块化的文件的递归解析处理,提高构建性能。
- 提高构建速度
- 直接通知webpack忽略较大的库
- 被忽略的库不能有import, require, define的引入方式
- parser
因为 Webpack 是以模块化的 JavaScript 文件为入口的,所以内置了对模块化 JavaScript的解析功能,支持 AMO, CornmonJS SystemJS ES6 parser 属性可以更细粒度地配置哪些模块语法被解析、哪些不被解析。同 noParse 配置项的区别在于,
parser可以精确到语法层面,而noParse只能控制哪些文件不被解析。parser的使用方法如下:
module:{
rules:[{
test∶/\.js$/,
use:['babel-loader'],
parser:{
amd∶false,//禁用AMD
commonjs∶ false,//禁用CommonJS
system∶ false,// 禁用SystemJS
harmony∶false,//禁用 ES6 import/export
requireInclude∶false,//禁用require.include
requireEnsure∶false,//禁用require.ensure
requireContext∶false,//禁用require.context
browserify∶false,// 禁用browserify
requireJs∶false,//禁用 requirejs
}
}]
}
2.2 分析每个loader和plugin执行时长
speed-measure-webpack-plugin
-
happyPack多核编译 Happy Pack ( github.com/amireh/happ… )将任务分解给多个子进程去并发执行,子进程处理完后再将结果发送给主进程。
-
缓存
cache-loader -
dllplugin
- 将网页依赖的基础模块抽离出来,打包到一个个单独的动态链接库中。在一个动态链接库中可以包含多个模块。
- 需要导入的模块存在于某个动态链接库中时,这个模块不能被再次打包,而是去动态链接库中获取。
- 页面依赖的所有动态链接库都需要被加载。
接入webpack
- DllPlugin 插件: 用于打包出一个个单独的动态链接库文件
- DllReferencePlugin 插件:用于在主要的配置文件中引入 DllPlugin 插件打包好的动态链接库文件。
-
少用loader/plugin
-
source-map
- 开发环境下,cheap-module-eval-source-map
- 生产环境:hidden-source-map
- 优化文件监听,忽略掉不需要监听的文件
在开启监听模式时,默认情况下会监听配置的 Entry 文件和所有 Entry 递归依赖的文件在这些文件中会有很多存在于 node_modules 下,因为如今的 Web 项目会依赖大量的第三方模块, 所以在大多数情况下我们都不可能去编辑 node_modules 下的文件,而是编辑自己建立的源码文件,而一个很大的优化点就是忽略 node_modules 下的文件,不监昕它们。
相关配置如下:
module.export = {
watchOptions : {
// 不监听的 node_modules 目录下的文件
ignored: /node_modules/,
}
3. 打包输出质量
- 区分环境 通过环境变量的值去判断执行哪个分支
if (true) {
console.log('你正在使用线上环境');
} else {
console.log('你正在使用开发环境');
}
使用Uglifyjs可以压缩为
console.log('你正在使用线上环境');
另外很多包对生产环境与开发环境有优化
- 压缩JS
- UglifyJsPlugin :通过封装 UglifyJS 实现压缩
- ParallelUglifyPlugin: 多进程并行处理压缩
webpack-parallel-uglify-plugin
压缩ES6: uglifyjs-webpack-plugin@beta
uglifyjs-webpack-plugin
- 新版, 支持ES6 terser-webpack-plugin
- 减小JS文件体积
作用域提升(合并作用域)
- 代码体积减小
- 提高执行效率
- 同样注意Babel的modules配置(只支持import)
- Babel7优化配置
- 在需要的地方引|入polyfill (@babel/polyfill)
- 辅助函数的按需引入
presets: [
[
'@babel/preset-env',
{
"useBuiltIns": "usage", // polyfill按需引入
}
],
],
- @babel/plugin-transform-runtime 复用polyfill,而不是每次都生成一个polyfill函数
-
压缩css
mini-css-extract-pluginoptimize-css-assets-webpack-plugin -
cdn加速
module.exports = {
// 省略 entry 配置 ...
output: {
// 为输出的 JavaScript 文件名加上 Hash
filename: '[name][chunkhash:8].js',
path: path.resolve(_dirname, '.dist'),
指定存放 JavaScript 文件的 CDN 目录 URL
publicPath: '//js.cdn.com/id/',
}
}
- tree shaking
- 基于ES6 import export
- package.json中配置sideEffects
// 排除掉不需要tree-shaking的文件
"sideEffects": [
"*.css"
]
- 注意Babel默认配置的影响
presets: [
[
'@babel/preset-env',
{
modules: false, // 不需要把import转为其它语法,因为tree-shaking只支持import
}
],
'@babel/preset-react'
],
mainFields 配置采用哪个字段作为模块的入口描述,我们需要使用第三方包的es6版本
module.exports = {
resolve: {
// 针对Npm中的第三方模块优先采用jsnext∶main中指向的 ES6模块化语法的文件
mainFields:['jsnext:main','browser','main']
}
}
以上配置的含义是优先使用jsnext∶main作为入口,如果不存在,jsnext∶main就会采用 browser 或者 main 并将其作为入口。虽然并不是每个 npm 中的第三方模块都会提供ES6模块化语法的代码,但对于已提供了的代码要尽量优化。
-
提取公共代码
-
分割按需加载(异步组件,异步路由)
-
prepack 优化代码运行效率(不成熟,不要用语线上)
prepack-webpack-plugin -
scope hoisting 分析模块依赖关系,将可能将被打散的模块合到一个函数中
-
持久化缓存
- 每个打包的资源文件有唯一的hash值
- 修改后只有受影响的文件hash变化
- 充分利用浏览器缓存
- 基于webpack的应用大小监测与分析
- Stats分析与可视化图
- webpack- bundle-analyzer 进行体积分析
- speed-measure-webpack-plugin 速度分析