大家都知道,webpack是现在主流的模块化打包工具,随着项目中打包出来的js体积越来越大,构建速度越来越慢,对其进行性能优化也是我们必做的事情。本篇文章会从各个性能方面进行讲解,希望对学习webpack的小伙伴们有所帮助。
HMR 全称 Hot Module Replacement,翻译为模块热更新。当一个模块发生变化时,只会对该模块重新进行打包,而不会打包所有模块,这个特性对于开发环境来说非常重要,我们所需要做的就是更新我们的webpack-dev-server配置。
webpack5已经自动实现HRM热更新替换功能,所以我们在devServer中不需要添加任何代码,但html文件无法实现热更新,所以我们需要在主文件入口中将html文件引入
entry: ['./src/js/index.js', './src/index.html'],
另外新的模块替换老的模块后,业务层代码并不知道代码已经发生了变化,所以我们需要在业务层代码中添加处理模块更新函数,即在index.js中添加如下:
// index.js
if(module.hot) {
module.hot.accept('./other.js', function() {
hello()
})
}
sourcemap 本质上是一个信息文件,里面储存着打包前后代码的映射为位置关系及信息,可方便开发者快速定位错误。
以上表格可能看不清,具体配置项详情可以参考官网:https://webpack.js.org/configuration/devtool/#root
devtool: 'eval-source-map'
在开发环境
想要实现开发速度快,调试更友好,可采用eval-cheap–module-souce-map
eval-source-map
在生产环境
若需要隐藏代码,可采用nosources-source-map / hidden-source-map,若想速度快,可source-map / cheap-module-souce-map
注意:生产环境考虑到文件体积的原因,一般将映射文件生成到外部。 具体配置结合项目情况
一般情况下,所有文件在执行的时候,都会将loader的rules过一遍,如果符合,就被相应的loader处理,不符合就直接过,这样非常浪费性能。oneOf是一个规则数组,当规则匹配时,只使用其中的第一个规则。
若一个文件要被多个loader处理,那可以将将其放在oneOf外面
在这里会介绍两种缓存优化,即babel 缓存 和 文件资源缓存
默认未设置缓存。当设置时,给定的目录将用于缓存加载器的结果。未来的webpack构建将尝试从缓存中读取,以避免在每次运行时都需要运行可能昂贵的Babel重新编译过程。cacheDirectory: true中将该值设置为true,加载器将使用node_modules/中的默认缓存目录。如果在任何根目录中都没有node_modules文件夹,则缓存/babel-loader或回退到默认的OS临时文件目录。
{
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
}
},
当请求的资源或者文件名称未出现变化时,浏览器会拿取缓存里面的资源,不会重新从服务器请求资源。
文件资源缓存有三种实现方案
简单创建一个node服务器:
const express = require('express');
const app = express();
//需要将dist文件作为静态资源缓存
app.use(express.static('dist', { maxAge: 2000 * 3600 }));
app.listen(9000);
启动服务器后在需要缓存的文件后面加上contenthash即可
实现效果
最终整体代码:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); //通过 npm 安装
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// 设置nodejs环境变量
process.env.NODE_ENV = 'development';
const config = {
entry:'./src/js/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/dist[contenthash:10].js'
},
module: {
rules: [
{
oneOf: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
"postcss-preset-env",
{}
],
],
},
}
}
],
},
{
//打包图片资源 处理 css 文件的 img背景 图片
test:/\.(jpg|png|gif)$/,
type: 'asset/resource',
generator:{
filename:'img/[hash:10][ext]',
},
},
{
// 处理 html 文件的 img 图片
test:/\.html$/,
loader:'html-loader',
},
{
//打包图标字体资源
test: /\.(ttf|eof|woff2)$/,
type: 'asset/resource',
generator:{
filename:'font/[hash:10][ext]',
},
},
{
//打包图标字体资源
exclude: /\.(ttf|eof|woff2|css|html|js|png|gif|jpg)$/,
type: 'asset/resource',
generator:{
filename:'other/[hash:10][ext]',
}
},
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: 'usage',
// 指定core-js版本
corejs: {
version: 3
},
// 指定兼容性做到哪个版本浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true
}
}
}
]
}
]
},
plugins:[
new HtmlWebpackPlugin({
template : './src/index.html',
// 压缩html代码
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true
}
}),
// 使用单独生成css文件的插件,打包时会将css文件独立出去
new MiniCssExtractPlugin({
// 指定文件的输出路径和文件名
filename: 'css/index[contenthash:10].css'
}),
],
optimization: {
//这将使CSS优化只在生产模式。
// 如果你想在开发中运行它,设置优化。最小化选项为true:
minimizer: [
new CssMinimizerPlugin(),
],
minimize: true,
},
mode:'development',
devServer: {
//热加载 npx webpack server
static: {
directory: path.join(__dirname, 'build'),
},
compress: true,
port: 9000,
open: true,
/* hot: true*/
},
};
module.exports = config;
各位小伙伴们,由于webpack性能优化考虑的地方较多,所以先介绍到这里,后面会更新webpack性能二。创作不易,若你觉得对你有所帮助的话麻烦点赞关注一下哟。若有什么不足的地方,也麻烦各位大佬指点出来。