下方的配置代码,均为webpack.config.js文件的内容
如果需要产生打包文件的话,直接运行指令 webpack
如果需要直接运行的话,直接运行指令 webpack server
项目内容上传到了 码云 https://gitee.com/a2547944268/webpack_test上,下面的内容对照着代码的话,可能更清晰。
优化配置概括
优化主要分为两个方面的配置:开发环境和生产环境
具体可以概括如下:
# webapck性能优化
* 开发环境性能优化
* 生产环境性能优化
# 开发环境性能优化
* 优化打包构建速度
* HMR
* 优化代码调试
* source-map
# 生产环境性能优化
* 优化打包构建速度
* oneOf
* babel缓存
* 多进程打包
* external
* dll
* 优化代码运行的性能
* 缓存(hash/chunkhash/contenthash) 及三者区别
* tree shaking (es6/producton) sideEffect
* code split(单/多入口)
* 懒加载/预加载
* pwa
1.HMR
HMR:hot module replacement 热模块替换
作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块)
极大提升代码构建速度
实现:
样式文件:可以使用HMR功能,因为style-loader内部实现了
js文件:默认不能使用HMR功能,需要修改js代码,添加支持HMR功能的代码
注意:HMR功能对js的处理,只能处理非入口js文件的其他文件
html文件:默认不能使用HMR功能,同时会导致问题:html文件不能热更新了(不用做HMR功能,因为只有一个html文件)
解决:修改entry入口,将html文件引入
其实配置HMR,只需要在webpack.config.js内文件的derServer属性内添加 hot: true 便可直接开启HMR
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: ['./src/js/index.js', './src/index.html'],
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build'),
},
module: {
rules: [
// loader的配置
{
// 处理less资源
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader'],
},
// css文件是放置在js文件内的,不需要单独文件夹存放
{
// 处理css资源
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
// 处理图片资源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
// 关闭es6模块化
esModule: false,
outputPath: 'imgs',
},
},
{
// 处理html中img资源
test: /\.html$/,
loader: 'html-loader',
options: {
esModule: true,
},
},
{
// 处理其他资源
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media',
},
},
],
},
plugins: [
// plugins的配置
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
mode: 'development',
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
// 开启HMR
// 当修改了webpack配置,新配置想要生效,必须重启webpack服务
hot: true,
},
};
运行指令为 webpack server
2.source-map
source-map主要是为了解决:开发环境下如何调试代码
source-map:一种 提供源代码到构建后代码映射 技术(如果构建后代码出错了,通过映射可以追踪)
写法: devtool: 'source-map' 是最基本的配置
[inline-|hidden-|eval-][nosources-][cheap-[module-]]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加入
内联和外部的区别: 1.外部生成了文件,内联没有 2.内联构建速度更快
开发环境
需要的:速度快,调试更友好
速度快(eval>inline>cheap>...)
eval-cheap-source-map 速度会更快
eval-source-map
调试更友好
source-map
cheap-module-source-map
cheap-source-map
推荐:
--> eval-source-map / eval-cheap-module-source-map
优先选择第一种
生产环境
生产环境需要的:源代码要不要隐藏,调试要更友好
内联会让代码体积变得非常大,所以在生产不使用内联
隐藏源代码
hidden-source-map 只隐藏源代码,会提示构建后代码错误
nosources-source-map 全部隐藏
推荐
--> source-map / cheap-module-source-map
webpack.config.js配置
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: ['./src/js/index.js','./src/index.html'],
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
// 处理less资源
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
// css文件是放置在js文件内的,不需要单独文件夹存放
{
// 处理css资源
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [
// plugins的配置
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
// 开启HMR
// 当修改了webpack配置,新配置想要生效,必须重启webpack服务
hot: true
},
devtool: 'source-map'
};
3.oneOf
主要在module的rules属性内使用
主要目的:使用的文件loader只会匹配一个,主要用于提升构建速度
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 这里默认使用生产环境,所以需要配置开发环境
// 定义nodejs环境变量:决定使用browserslist的哪个环境变量
process.env.NODE_ENV = 'development'
// 复用loader
const commonCssLoader = [
// 这种写法会将css代码直接整合到js内
// 'style-loader',
// 下面的写法是将编译后的css文件提取出来
MiniCssExtractPlugin.loader, // 将css代码提取为单独css文件
'css-loader', // 编译css代码
{
// css兼容性处理
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
require('postcss-preset-enev')()
]
}
},
]
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
// 优先执行
enforce: 'pre',
loader: eslint - loader,
options: {
fix: true // 自动修复js内的报错
}
},
{
// 以下loader只会匹配一个,主要用于提升构建速度
// 注意:不能有两个配置处理同一种类型的文件
oneOf: [
{
test: /\.css$/,
use: [
...commonCssLoader
]
},
{
test: /\.less$/,
use: [
...commonCssLoader,
'less-loader' // 将less编译成css
]
},
{
// js的兼容性处理
test: /\.js$/,
exclude: /node_modules/,
loader: babel - loader,
options: {
presets: [
[
'@babel/preset-env', // 全部加载的话很大,可以按需加载
{
useBuiltins: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '50',
}
}
]
]
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs', // 输出路径
esModules: false
}
}, {
test: /\.html$/,
loader: 'html-loader'
},
{
// 处理其他文件
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.css'
}),
// 压缩css代码
new OptimizeCssAssetsWebpackPlugin(),
// 这个可以处理html里的代码,但是html内的图片无法处理
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production'
}
4.缓存
缓存主要是两点:babel、资源
1. babel缓存
cacheDirectory: true
---> 让第二次打包构建速度更快
2.文件资源缓存
需要修改文件名
2.1 hash:每次webpack构建时会生成一个唯一的hash值
问题:因为js和css同时使用一个hash值
如果重新打包,会导致所有缓存失效(如果只改动了一个文件)
2.2 chunkhash:根据chunk生成的hash值,如果打包来源于同一个chunk,那么hash值就一样
问题:js和css的hash值还是一样的
因为css是在js中被引入的,所以同属于同一个chunk
2.3 contenthash:根据文件内容生成hash值,不同文件的hash值不一样
--->让代码上线运行缓存更好使用
三者的区别:
hash在编译后都会生成新的hash值,无论值文件内容是否变化
chunkhash:js和css绑定在一起了,值是一致的
整个配置文件太多了,但是可以参考上面的代码例子:
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 这里默认使用生产环境,所以需要配置开发环境
// 定义nodejs环境变量:决定使用browserslist的哪个环境变量
process.env.NODE_ENV = 'development'
// 复用loader
const commonCssLoader = [
// 这种写法会将css代码直接整合到js内
// 'style-loader',
// 下面的写法是将编译后的css文件提取出来
MiniCssExtractPlugin.loader, // 将css代码提取为单独css文件
'css-loader', // 编译css代码
{
// css兼容性处理
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
require('postcss-preset-enev')()
]
}
},
]
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
// 优先执行
enforce: 'pre',
loader: eslint-loader,
options: {
fix: true // 自动修复js内的报错
}
},
{
// 以下loader只会匹配一个,主要用于提升构建速度
// 注意:不能有两个配置处理同一种类型的文件
oneOf: [
{
test: /\.css$/,
use: [
...commonCssLoader
]
},
{
test: /\.less$/,
use: [
...commonCssLoader,
'less-loader' // 将less编译成css
]
},
{
// js的兼容性处理
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
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 *1024,
name: '[hash:10].[ext]',
outputPath: 'imgs', // 输出路径
esModules: false
}
},{
test: /\.html$/,
loader: 'html-loader'
},
{
// 处理其他文件
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
}),
// 压缩css代码
new OptimizeCssAssetsWebpackPlugin(),
// 这个可以处理html里的代码,但是html内的图片无法处理
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production',
devtool: 'source-map'
}
可以看到实现babel缓存的属性 cacheDirectory: true 及压缩css时文件缓存
5.tree shaking
tree shaking:去除无用代码
前提:1.必须使用ES6模块 2.开启production环境
作用:减少代码体积
在package.json中配置
"sideEffects": false 所有代码都没有副作用(都可以进行tree shaking)
问题:可能会把css / @babel/polyfill(副作用)文件干掉
如果不进行tree shaking(不希望删掉css等文件),可以修改:"sideEffects": ["*.css"]
webpackconfig.js的内容与其他的类似,没发现具体差别,需要直接看gitee上的代码。