一、量化工具
1. speed-measure-webpack-plugin
测量webpack构建速度
下载量:(100w/weeks)
使用方式:
//webpack.config.js
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
const config = { //...webpack配置 }
module.exports = smp.wrap(config);
效果:
2. webpack-bundle-analyzer
创建所有捆绑包内容的交互式树形图可视化
下载量:(500w/weeks)
使用方式:
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const config = {
plugins: [
//...
new BundleAnalyzerPlugin(),
]
}
效果:
二、速度优化
1. exclude/include
我们可以通过 exclude
、include
配置来确保转译尽可能少的文件。顾名思义,exclude
指定要排除的文件,include
指定要包含的文件。
exclude: /node_modules/, // 不检查node_modules里的代码 黑名单
include: [path.resolve(__dirname, 'src')], // 只检查src里面的代码 白名单
2. cache: boolean|object
(在构建及打包过程中都生效,但如果文件有修改则无法使用缓存)
缓存生成的 webpack 模块和 chunk,来改善构建速度。cache
会在开发
模式被设置成 type: 'memory'
而且在 生产
模式 中被禁用。 cache: true
与 cache: { type: 'memory' }
配置作用一致。 传入 false
会禁用缓存
memory 内存中缓存,不允许额外配置;
filesystem文件系统中缓存,可以额外配置;
cache: {
type: 'filesystem', //开放更多的可配置项
cacheDirectory: path.resolve(__dirname, '.temp_cache'), //缓存位置
},
其他缓存相关优化:cache-loader ;给 babel-loader
增加选项 cacheDirectory;require('hard-source-webpack-plugin')(52w/weeks)[注意:不能和speed-measure-webpack-plugin插件公用]
3. thread-loader
使用时,需将此 loader 放置在其他 loader 之前。放置在此 loader 之后的 loader 会在一个独立的 worker 池中运行。
在 worker 池中运行的 loader 是受到限制的。例如:
- 这些 loader 不能生成新的文件。
- 这些 loader 不能使用自定义的 loader API(也就是说,不能通过插件来自定义)。
- 这些 loader 无法获取 webpack 的配置。
每个 worker 都是一个独立的 node.js 进程,其开销大约为 600ms 左右。同时会限制跨进程的数据交换。
请仅在耗时的操作中使用此 loader!
4.module.noParse
防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中 不应该含有 import
, require
, define
的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能。
module.exports = {
//...
module: {
noParse:/jquery|lodash/,
},
};
5.resolve.alias
alias通过创建import或者require的别名,把原来导入模块的路径映射成一个新的导入路径,这样的好处就是webpack直接会去对应别名的目录查找模块,减少了搜索时间。
module.exports = {
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
};
6.resolve.extensions
extensions字段用来在导入模块时,自动带入后缀尝试去匹配对应的文件
extensions
数组越长,或者正确后缀的文件越靠后,匹配的次数越多也就越耗时
module.exports = {
resolve: {
extensions: ['.js', '.json']
}
}
7. 模块懒加载
如果不进行模块懒加载
的话,最后整个项目代码都会被打包到一个js文件里,单个js文件体积非常大,那么当用户网页请求的时候,首屏加载时间会比较长,使用模块懒加载
之后,大js文件会分成多个小js文件,网页加载时会按需加载,大大提升首屏加载速度
const routes = [
{
path: '/login',
name: 'login',
component: login
},
{
path: '/home',
name: 'home', // 懒加载
component: () => import('../views/home/home.vue'),
},
]
8. hash
hash 计算与整个项目的构建相关;
chunkhash 计算与同一 chunk 内容相关; 根据不同的入口文件(Entry)进行依赖文件解析、构建对应的 chunk,生成对应的哈希值。
contenthash 计算与文件内容本身相关。 将根据资源内容创建出唯一 hash,也就是说文件内容不变,hash 就不变。
我们要保证,改过的文件需要更新hash值,而没改过的文件依然保持原本的hash值,这样才能保证在上线后,浏览器访问时没有改变的文件会命中缓存,从而达到性能优化的目的
output: {
path: path.resolve(__dirname, '../dist'), // 给js文件加上 contenthash
filename: 'js/chunk-[contenthash].js',
clean: true,
},
三、大小优化
1. terser-webpack-plugin
该插件使用 terser 来压缩 JavaScript。
参数: parallel: boolean | number;
使用多进程并行运行来提高构建速度,默认并发运行数:os.cpus().length - 1。
并行化可以显着加快构建速度,因此强烈推荐
module.exports = {
optimization: {
minimize: true, //开发环境不压缩,能显著提高编译速度
minimizer: [
new TerserPlugin({
parallel: 4,
}),
],
},
};
2. IgnorePlugin
webpack
的内置插件,作用是忽略第三方包指定目录。
例如: moment
(2.24.0版本) 会将所有本地化内容和核心功能一起打包,我们就可以使用 IgnorePlugin
在打包时忽略本地化内容。
module.exports = {
//忽略 moment 下的 ./locale 目录
new webpack.IgnorePlugin({
resourceRegExp: /^./locale$/,
contextRegExp: /moment$/,
}),
}
3. externals及html-webpack-externals-plugin
我们希望在使用时,仍然可以通过 import
的方式去引用(如 import $ from 'jquery'
),并且希望 webpack
不会对其进行打包,此时就可以配置 externals
。
module.exports = {
//...
externals: {
//jquery通过script引入之后,全局中即有了 jQuery 变量
'jquery': 'jQuery'
}
}
webpack 中公共模块,基础库, 多次使用的公共方法单独抽离,以减少包体积和打包时间
new HtmlWebpackExternalsPlugin({
externals: [
{
module: 'lodash',
entry: 'https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.20/lodash.js', global: '_',
},
],
}),
4. optimization.runtimeChunk
设置为 true
或 'multiple'
,会为每个入口添加一个只含有 runtime 的额外 chunk。
设置为 object
,对象中可以设置只有 name
属性,其中属性值可以是名称或者返回名称的函数,用于为 runtime chunks 命名。
module.exports = {
//...
optimization: {
runtimeChunk: {
name: 'runtime',
},
},
};
5. optimization.splitChunks
抽离公共代码是对于多页应用来说的,如果多个页面引入了一些公共模块,那么可以把这些公共的模块抽离出来,单独打包。公共代码只需要下载一次就缓存起来了,避免了重复下载。
抽离公共代码对于单页应用和多页应该在配置上没有什么区别,都是配置在 optimization.splitChunks
中。
optimization: {
runtimeChunk: true,
// 分割代码块
splitChunks: {
chunks: 'all',
/**
* initial 入口chunk,对于异步导入的文件不处理
* 针对直接引入的代码
async 异步chunk,只对异步导入的文件处理
all 全部chunk 一般用这个
*/
// 缓存分组
cacheGroups: {
// 第三方模块
vendor: {
name: 'vendor', // chunk 名称 即打包后所有第三方库都叫vendor
// 拆分的时候 第三方和功能代码有可能冲突,比如第三方库也作为公共代码在多个地方引用
// 此时用priority 先按第三方模块进行抽离,未命中在按公共模块抽离
// priority越大 优先级越大
priority: 1, // 权限更高,优先抽离,重要!!!
// 通过test 来检测是否命中 通过检测路径
test: /node_modules/,
// 最小分组尺寸 小于此值不抽离 如果有些文件比较小 没有必要抽离
minSize: 0, // 大小限制
// 只要复用超过1次 就抽离
minChunks: 1, // 最少复用过几次
},
// 公共的模块
common: {
name: 'common', // chunk 名称
priority: 0, // 优先级
minSize: 0, // 公共模块的大小限制
// 只要复用超过2次 就抽离
minChunks: 2, // 公共模块最少复用过几次
},
},
},
},
6. mini-css-extract-plugin
本插件会将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
不可与speed-measure-webpack-plugin 共用,参考"You forgot to add 'mini-css-extract-plugin' plugin"
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
``````
module:{
rules:[
{
test: /.less$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'], }
]
},
plugins: [
new MiniCssExtractPlugin(),
]
}
7. compression-webpack-plugin
nginx配置gzip压缩
对于静态资源,有两种开启压缩的方式,一种是compress in time,另一种是precompression。
对于第二种,因为静态资源已经提前进行了压缩处理,当HTTP请求到达之后,可以直接响应已经压缩过的文件,所以可以节约服务器的CPU。
所以就算不配置compression-webpack-plugin插件也会使用gzip压缩,只是配置插件及nginx后可以节约cpu。
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
plugins: [
new CompressionPlugin(),
]
}
8.url-loader
url-loader 可以识别图片的大小,然后把图片转换成base64,从而减少代码的体积 (url-loader内置了file-loader)
{
test: /.(jpg|png|gif|bmp)$/,
use: [
{
loader: 'url-loader',
options: {
name: '[hash:10].[ext]',
esModule: false,
limit: 8 * 1024, // 如果文件的体积小于limit,则转为base64内置到html },
},
],
},
四、webpack5下的过时优化
-
除cache外的其他缓存优化,
包括cache-loader ;
给 babel-loader 增加选项 cacheDirectory;
require('hard-source-webpack-plugin');
[webpack5貌似内置了hard-source-webpack-plugin的技术]
-
happypack 用来设置多线程,但是在 webpack5 就不要再使用 happypack 了,官方也已经不再维护了,推荐使用 thread-loader。
-
webpack-parallel-uglify-plugin 或者是 uglifyjs-webpack-plugin 配置 parallel来进行多进程压缩的优化,Webpack 默认使用的是 TerserWebpackPlugin,默认就开启了多进程和缓存。
-
dll 动态链接库(事先把常用但又构建时间长的代码提前打包好(例如 react、react-dom),取个名字叫 dll。后面再打包的时候就跳过原来的未打包代码,直接用 dll。这样一来,构建时间就会缩短,提高 webpack 打包速度。
[其实就是缓存]
)