三、Webpack优化配置
性能优化
性能优化包含开发环境优化和生产环境优化。
- 开发环境
- 优化打包构建速度
- 优化代码调试
- 生产环境
- 优化打包构建速度
- 优化代码运行的性能
开发环境
HMR
即热更新:一个模块发生变化,只会重新打包这一个模块。
在devServer中开启
{
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
// 开启HMR功能
// 当修改了webpack配置,新配置要想生效,必须重新webpack服务
hot: true
}
}样式文件
样式文件可以使用热更新,因为
style-loader内部实现了js文件
默认不使用HMR功能,需要手动修改支持HMR。且只能处理非入口文件。
if (module.hot) { // 一旦 module.hot 为true,说明开启了HMR功能。 --> 让HMR功能代码生效 module.hot.accept('./print.js', function() { // 方法会监听 print.js 文件的变化,一旦发生变化,其他模块不会重新打包构建。 // 会执行后面的回调函数 print(); }); }HTML文件
默认不支持,需要修改webpack中entry入口
module.exports = { entry: ['./src/js/index.js', './src/index.html'] }
source-map
source-map是一种提供源代码到构建后代码映射技术。开启source-map只需要在devServer中开启devtool即可。
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
hot: true
},
devtool: 'source-map'
};关于devtool的选项
| 选项 | 位置 | 特点 | 错误原因及位置 |
|---|---|---|---|
source-map | 外部 | 错误代码准确信息 源代码的错误位置 | |
inline-source-map | 内联 | 只生成一个内联source-map | 错误代码准确信息 源代码的错误位置 |
hidden-source-map | 外部 | 错误代码错误原因,但是没有错误位置 | 不能追踪源代码错误,只能提示到构建后代码的错误位置 |
eval-source-map | 内联 | 每一个文件都生成对应的source-map,都在eval | 错误代码准确信息 源代码的错误位置 |
nosources-source-map | 外部 | 错误代码准确信息, 但是没有任何源代码信息 | |
cheap-source-map | 外部 | 只能精确的行 | 错误代码准确信息 源代码的错误位置 |
cheap-module-source-map | 外部 | module会将loader的source map加入 | 错误代码准确信息 源代码的错误位置 |
内联和外部的区别:外部生成了文件,内联没有;内联速度比外部快
开发环境与生产环境下source-map的选择:
开发环境:速度快,调试更友好
- 速度快
eval-cheap-souce-mapeval-source-map
- 调试友好
souce-mapcheap-module-souce-mapcheap-souce-map
因此开发环境下可以选择:
eval-source-map或者eval-cheap-module-souce-map- 速度快
生产环境
不隐藏源代码(便于调试)
source-mapcheap-module-souce-map
因此源代码
nosources-source-map全部隐藏
hidden-source-map只隐藏源代码,会提示构建后代码错误信息
oneOf
module: {
rules: [
{
// 其他loader
},
{
oneOf:[
// loader配置
]
}
]
}只需要将loader放入到oneOf数组中即可,使用oneOf后不能有两个loader处理同一类型的文件,因此需要将相同的loader提取到外边
缓存
babel缓存
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', { useBuiltIns: 'usage', corejs: { version: 3 }, targets: { chrome: '60', firefox: '50' } } ] ], // 开启babel缓存 // 第二次构建时,会读取之前的缓存 cacheDirectory: true } }文件资源缓存
hash和整个项⽬目的构建相关,只要项⽬目⽂文件有修改,整个项⽬目构建的 hash 值就会更更改
chunkhash和 webpack 打包的 chunk 有关,不不同的 entry 会⽣生成不不同的 chunkhash 值
contenthash根据⽂文件内容来定义 hash ,⽂文件内容不不变,则 contenthash 不不变
一般情况下js文件使用
chunkhash,css文件和图片使用contenthash,图片文件使用hash
生产环境
去除无用代码
可以按需加载需要使用的代码,减少代码体积。
- 使用ES6模块化
- 开启
production环境
此方法可能会将css资源忽略掉,因此可以在package.json中进行配置。
"sideEffects": [
"*.css",
"*.less"
]代码分割
即按需加载,生成多个js文件。
根据入口文件进行分割
module.exports = { // 单入口 // entry: './src/js/index.js', entry: { // 多入口:有一个入口,最终输出就有一个bundle index: './src/js/index.js', test: './src/js/test.js' } }分割node_moudle模块
module.exports = { /* 1. 可以将node_modules中代码单独打包一个chunk最终输出 2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk */ optimization: { splitChunks: { chunks: 'all' } } }通过JS代码使某个文件被单独打包
此时webpack的入口可以设置单入口。
/* 通过js代码,让某个文件被单独打包成一个chunk import动态导入语法:能将某个文件单独打包 */ import(/* webpackChunkName: 'test' */'./test') .then(({ mul, count }) => { // 文件加载成功~ // eslint-disable-next-line console.log(mul(2, 5)); }) .catch(() => { // eslint-disable-next-line console.log('文件加载失败~'); });
懒加载和预加载
只需要在触发某个条件时才引入外部文件。
document.getElementById('btn').onclick = function() {
// 懒加载~:当文件需要使用时才加载~
// 预加载 prefetch:会在使用之前,提前加载js文件
// 正常加载可以认为是并行加载(同一时间加载多个文件)
// 预加载 prefetch:等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) => {
console.log(mul(4, 5));
});
};PWA
渐进式网络开发应用程序(离线可访问)
在webpack中使用pwa需要安装插件workbox-webpack-plugin
yarn add workbox-webpack-plugin -D修改webpack配置
plugins: [
new WorkboxWebpackPlugin.GenerateSW({
/*
1. 帮助serviceworker快速启动
2. 删除旧的 serviceworker
生成一个 serviceworker 配置文件~
*/
clientsClaim: true,
skipWaiting: true
})
],在入口文件配置serviceworker
// code
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/service-worker.js')
.then(() => {
console.log('sw注册成功了~');
})
.catch(() => {
console.log('sw注册失败了~');
});
});
}如果发生eslint错误,则可以在package.json中进行修改。
{ "eslintConfig": { "extends": "airbnb-base", "env": { "browser": true } } }
多进程打包
安装插件
yarn add thread-loader -D一般多进程对babel-loader进行。只需要将thread-loader放在其他loader前即可。
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'thread-loader',
options: {
// 进程为2
workers: 2
}
},
{
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '50'
}
}
]
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true
}
}
]
}多进程不一定会使打包时间变短,需合理使用。因为进程启动也需要消耗时间。
使用CDN
在webpack中配置字段externals即可。
externals: {
// 忽略的库名 -- npm 包名
jquery: 'JQuery'
}忽略后需在html手动引入CDN链接。
dll
安装插件
yarn add add-asset-html-webpack-plugin -D在webpack.config.js同目录建立一个webpack-dll.js文件。写入如下内容:
/**
* @description:
* @author: 小康
* @url: https://xiaokang.me
* @Date: 2021-01-02 15:30:59
* @LastEditTime: 2021-01-02 15:31:00
* @LastEditors: 小康
*/
// 使用dll技术,对某些第三方库进行单独打包
const { resolve } = require('path')
const webpack = require('webpack')
module.exports = {
entry: {
// 最终要打包生成的文件名:[要打包的库]
jquery: ['jquery']
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'dll'),
// 打包的库向外暴露出去的内容的名字
library: '[name]_[hash]'
},
plugins: [
new webpack.DllPlugin({
// 打包生成manifest.json提供映射关系
name: '[name]_[hash]',
path: resolve(__dirname, 'dll/manifest.json')
})
],
mode: 'production'
}在webpack.config.js中使用
const webpack = require('webpack')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
{
plugins: [
// 告诉webpack哪些库不参与打包,同时使用时引入的昵称也需要改
new webpack.DllReferencePlugin({
manifest: resolve(__dirname, 'dll/manifest.json')
}),
// 将某个文件打包输出 并在HTML中自动引入
new AddAssetHtmlWebpackPlugin({
filepath: resolve(__dirname, 'dll/jquery.js')
})
]
}








