上一篇的loader其主要功能还是配置webpack如何加载文件,而webpack的plugins可以做很多事情,比如定义全局变量、压缩文件、打包的优化等等。
压缩bundle文件
更小的 JS
文件可以使用户加载网页更快,所以压缩操作是很有必要的。
可以看看上一章结束时我们打包的 bundle.js
的大小,目前是 20kb
, 我们使用 TerserPlugin
来对 bundle
进行压缩。
const TerserPlugin = require('terser-webpack-plugin');
...
plugins: [
new TerserPlugin()
]
(plugins
属性在配置文件中是和module
mode
等属性平级的)
配置好之后直接打包,观察新的bundle.js
仅仅有8kb
, 这说明压缩配置生效了(terser-webpack-plugin
是webpack
内置的,所以不用另外去下载)
拆分CSS文件
上一篇我们暂时使用loader
处理css
和sass
文件,会把样式直接打包进bundle.js
中。但假设是较大的工程,这样会使最后打包的bundle
非常大,影响浏览器加载的速度。要充分利用浏览器可以并行加载网络资源的特点,正常情况下,是要把样式文件单独拆包出去,这里使用的plugin
是mini-css-extract-plugin
。
注意mini-css-extract-plugin
并非是webpack5
内置的,所以需要下载npm
包
npm install mini-css-extract-plugin --save-dev
配置文件需要加载,并在plugins
中初始化
...
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
...
plugins: [
new TerserPlugin(),
new MiniCssExtractPlugin({
filename: 'styles.css',
})
]
其次仍要指明loader
的, 将styles-loader
改写成MiniCssExtractPlugin.loader
(styles-loader
可以将样式写入JS-bundle
中)
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, 'css-loader'
]
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'
]
},
此时打包会发现dist
目录中出现了css
文件,别忘了在模版html
中引入才能生效
<link rel="stylesheet" href="./dist/styles.css" />
浏览器缓存
缓存策略可以使浏览器已经加载过的文件不再重复加载,这里不展开。但也带来一个问题,如果同名文件内容更改了,浏览器却命中了缓存这会使用户无法看到新上线的内容。一般情况下采用文件生成md5 hash
的方式来区别是否有内容更新。webpack
内置了这个功能,只需在文件名加入关键字[contenthash]
output: {
filename: 'bundle.[contenthash].js',
path: path.resolve(__dirname, './dist') ,
publicPath: 'dist/'
},
...
plugins: [
new TerserPlugin(),
new MiniCssExtractPlugin({
filename: 'styles.[contenthash].css',
})
]
打包后的结果如下
webpack
帮我们生成了文件的md5 hash
, 在文件内容不更新的情况下,这个值不会发生变化。
自动清理dist文件
上面的一节虽然生成了带有hash
的文件,但是每当新文件生成,老文件还在,webapck
是否能帮我们维护dist
文件夹的整洁呢?官网文档表明可以在 output 属性中配置 clean: true
,来清理dist
文件夹。当然这是OK的,也可以使用 clean-webpack-plugin
来做这件事儿,先加载这个Npm
包
npm install clean-webpack-plugin --save-dev
再来修改配置文件:
...
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
...
plugins: [
new TerserPlugin(),
new MiniCssExtractPlugin({
filename: 'styles.[contenthash].css',
}),
new CleanWebpackPlugin(),
]
配置完成后再打包,会发现之前旧的文件都不见了。
为什么官方已经有内置的方法来清理文件,还有费事引入其他的工具?因为 CleanWebpackPlugin
支持对打包后的其他内容进行删除,甚至是dist
文件夹的上层文件夹的内容,正常情况下用官方的clean
属性就够了,如果有一些特殊的需求,可以使用 CleanWebpackPlugin
.
自动生成HTML
如果用hash
的方式打包,还会有一个问题就是我们的html
模版文件引入js
css
资源的时候失败了,毕竟我们的模板调用资源的路径没有文件的hash
信息,这时候可以用 HtmlWebpackPlugin
,可以在打包时候生成一个html
文件,里面的资源引用路径也是有hash
值的文件名。这个 plugin
也不是内置的,需要手动加载
npm install html-webpack-plugin --save-dev
配置文件初始化plugin
...
const HtmlWebpackPlugin = require('html-webpack-plugin');
...
plugins: [
new TerserPlugin(),
new MiniCssExtractPlugin({
filename: 'styles.[contenthash].css',
}),
new CleanWebpackPlugin(),
new HtmlWebpackPlugin(),
]
值得注意的是需要改一下PublicPath
,因为生成的html
文件和其它bundle
现在是同级目录下
使用Html模版
HtmlWebpackPlugin
是可以通过配置拓展的
new HtmlWebpackPlugin({
title: 'Hello world',
filename: 'subfolder/custom_filename.html',
meta: {
description: 'Some description'
}
})
filename
还可以代路径来指定目录层级,以及通过meta
属性指定一些html
的meta
属性等等,更多的配置可以看HtmlWebpackPlugin
的 github上面的介绍
模版引擎可以使用handlebars
npm install --save handlebars
npm install --save-dev handlebars-loader
修改htmlwebpackplugin
的配置
new HtmlWebpackPlugin({
title: 'Hello world',
filename: 'index.html',
template: 'src/index.hbs',
description: 'Some description',
}),
因为需要引入.hbs
的文件,所以要增加相应的loader
{
test: /\.hbs$/,
use: [
'handlebars-loader'
]
}
src/index.hbs
的内容
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{htmlWebpackPlugin.options.title}}</title>
<meta name="description" content="{{htmlWebpackPlugin.options.description}}">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
</body>
</html>
注意里面有
{{}}
的语法,可以将配置文件中的一些属性打包进生成的html
文件的指定位置
配置完成后打包即可得到预期的html文件内容。