前言
大家好,我是东东吖
,一名前端工程师。前面我们学习了webpack五大概念的loader加载器,今天我们将来学习webpack五大核心概念的插件机制
Webpack插件机制介绍
- loader 专注实现资源模块加载
- Plugin 解决其他自动化工作
e.g.
- 清除dist目录,清除上一次的打包结果
- 拷贝静态文件至输出目录
- 压缩输出代码
Webpack自动清除输出目录插件
webpack打包会覆盖上一次的打包结果,但是只能覆盖同名文件,对于其他已经移除的文件,就会积累在里面,非常不合理。
那么我们应该怎么做呢?接下来我们将来介绍webpack的一款插件clean-webpack-plugin,该插件可以自动清除输出目录。
//安装clean-webpack-plugin 插件
yarn add clean-webpack-plugin --dev
复制代码
在webpack中配置插件:
//webpack.config.js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
mode: "development", //使用开发模式打包
entry: "./src/main.js", //打包前入口
// publicPath:'dist/' , //注意dist后面的/不能省略
output: {
//打包后出口
filename: "bundle.js", //打包后文件名
path: path.join(__dirname, "dist"), //打包后路径
},
module: {
// 匹配不同的资源loader加载器
rules: [
{
test: /.js$/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
},
},
},
{
test: /.css$/,
use: [
"style-loader",
"css-loader", //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
],
},
{
test: /.(png|jpg)$/,
use: {
loader: "url-loader",
options: {
limit: 30 * 1024, //30KB,因为这里的单位是字节,所有需要*1024
},
},
},
{
test: /.html$/,
use: {
loader: "html-loader",
},
},
{
test: /.md$/,
use: "./markdown-loader",
},
],
},
plugins:[
new CleanWebpackPlugin()
]
};
复制代码
执行打包命令,就可以发现dist目录被清空了,执行的是本次的打包结果。
Webpack在dist下自动生成index.html
除了自动清除输出目录,还有一个常见的需求就是自动生成使用bundle.js的HTML
。
现状:写死路径,手动硬编码,配置改变,得手动改变引入路径。
安装html-webpack-plugin 插件
yarn add html-webpack-plugin --dev
复制代码
执行打包命令,确实在dist目录生成了html文件,但是也报错了。
原因在于:html-webpack-plugin有一个.ejs文件,需要更换babel-loader的正则方法,/.js/ 换成 /\.js/即可解决。
查看打包结果:
我们删除src同级目录的index.html,在生产环境直接访问dist下面的index.html
在webpack配置index.html标题
查看打包结果
打开浏览器直接访问dist目录下的index.html。
当然,我们还可以在src下面使用模板文件,然后在配置文件中指定模板文件路径。
在再次打包,访问dist下面的index,就会访问src下面的index.html的模板文件
Webpack生成多个页面文件
//webpack.config.js 关键代码
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const htmlWebpackPlugin = require('html-webpack-plugin')
plugins:[
// 用于清空dist目录
new CleanWebpackPlugin(),
// 用于生成index.html
new htmlWebpackPlugin({
title:"东东吖",
meta:{
viewport:"width=device-width"
},
template:'./src/index.html'
}),
// 用于生成about.html
new htmlWebpackPlugin({
filename:'about.html'
})
]
复制代码
copy不参与构建的静态文件
在我们的项目中,还有一些不需要参与构建的静态文件,他们最终需要发布到线上
, 例如网站的favicon.icn。我们该怎么去copy不参与构建的静态文件呢?
至于静态文件资源大家可以去阿里巴巴矢量图 网站自行下载自己喜欢的图标。
我下载的是一个小老虎,把他放在src/public下面
我们需要把此类文件直接copy,不参与打包。
安装copy-webpack-plugin
yarn add copy-webpack-plugin --dev
复制代码
配置插件,执行打包命令
//webpack.config.js 关键代码
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const htmlWebpackPlugin = require('html-webpack-plugin')
const copyWebpackPlugin = require('copy-webpack-plugin')
plugins:[
// 用于清空dist目录
new CleanWebpackPlugin(),
// 用于生成index.html
new htmlWebpackPlugin({
title:"东东吖",
meta:{
viewport:"width=device-width"
},
template:'./src/index.html'
}),
// 用于生成about.html
new htmlWebpackPlugin({
filename:'about.html'
}),
new copyWebpackPlugin({
patterns :[
{ from:'src/public',to:'public'}
]
})
]
复制代码
自己开发一个插件
相比于loader,Plugin拥有更宽泛的能力范围,Plugin是通过软件开发中的钩子机制实现。
接下来,我们自己开发一个插件,需求就是:用于清除在none模式下打包后js多余的注释。
如下图所示:
通过webpack的api
我们来定义一个MyPlugin,并且把它应用起来。
//webpack.config.js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const htmlWebpackPlugin = require('html-webpack-plugin')
const copyWebpackPlugin = require('copy-webpack-plugin');
class MyPlugin{
apply(compiler){
console.log("MyPlugin 启动");
compiler.hooks.emit.tap("MyPlugin",compilation=>{
// compilation => 可以理解为此次打包的上下文
for(const name in compilation.assets){
console.log("每个文件的名称:",name);
}
})
}
}
module.exports = {
mode: "none", //打包的模式
entry: "./src/main.js", //打包前入口
// publicPath:'dist/' , //注意dist后面的/不能省略
output: {
//打包后出口
filename: "bundle.js", //打包后文件名
path: path.join(__dirname, "dist"), //打包后路径
},
module: {
// 匹配不同的资源loader加载器
rules: [
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
},
},
},
{
test: /\.css$/,
use: [
"style-loader",
"css-loader", //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
],
},
{
test: /\.(png|jpg)$/,
use: {
loader: "url-loader",
options: {
limit: 30 * 1024, //30KB,因为这里的单位是字节,所有需要*1024
},
},
},
{
test: /\.html$/,
use: {
loader: "html-loader",
},
},
{
test: /\.md$/,
use: "./markdown-loader",
},
],
},
plugins:[
// 用于清空dist目录
new CleanWebpackPlugin(),
// 用于生成index.html
new htmlWebpackPlugin({
title:"东东吖",
meta:{
viewport:"width=device-width"
},
template:'./src/index.html'
}),
// 用于生成about.html
new htmlWebpackPlugin({
filename:'about.html'
}),
new copyWebpackPlugin({
patterns :[
{ from:'src/public',to:'public'}
]
}),
new MyPlugin()
]
};
复制代码
执行打包命令,我们通过循环compilation.assets这个对象,他里面的key就是每个文件的名称。
接下来,我们需要判断文件是否是js,然后获取里面的内容,通过正则把里面多余的注释替换,最后把内容和内容的大小返回。
通过控制台打印,我们能清楚看见没一步的内容
最后我们来看打包后的结果,发现js里面多余的注释已经被清除了。
//webpack.config.js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const htmlWebpackPlugin = require('html-webpack-plugin')
const copyWebpackPlugin = require('copy-webpack-plugin');
class MyPlugin{
apply(compiler){
console.log("MyPlugin 启动");
compiler.hooks.emit.tap("MyPlugin",compilation=>{
// compilation => 可以理解为此次打包的上下文
for(const name in compilation.assets){
// console.log("每个文件的名称:",name);
// console.log("具体文件的内容:",compilation.assets[name].source);
if (name.endsWith('.js')) { //判断是否js文件
const contents =compilation.assets[name].source() //js文件的内容
const widthoutComments =contents.replace(/\/\*\*+\*\//g,'') //利用正则替换内容丽多余的注释
//把结果通过source返回,size表示返回内容的大小
compilation.assets[name] ={
source:()=>widthoutComments,
size:()=>widthoutComments.length
}
// 打印相关信息理解
console.log("js文件的内容:",contents);
console.log("利用正则替换内容丽多余的注释",widthoutComments);
}
}
})
}
}
module.exports = {
mode: "none", //打包的模式
entry: "./src/main.js", //打包前入口
// publicPath:'dist/' , //注意dist后面的/不能省略
output: {
//打包后出口
filename: "bundle.js", //打包后文件名
path: path.join(__dirname, "dist"), //打包后路径
},
module: {
// 匹配不同的资源loader加载器
rules: [
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
},
},
},
{
test: /\.css$/,
use: [
"style-loader",
"css-loader", //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
],
},
{
test: /\.(png|jpg)$/,
use: {
loader: "url-loader",
options: {
limit: 30 * 1024, //30KB,因为这里的单位是字节,所有需要*1024
},
},
},
{
test: /\.html$/,
use: {
loader: "html-loader",
},
},
{
test: /\.md$/,
use: "./markdown-loader",
},
],
},
plugins:[
// 用于清空dist目录
new CleanWebpackPlugin(),
// 用于生成index.html
new htmlWebpackPlugin({
title:"东东吖",
meta:{
viewport:"width=device-width"
},
template:'./src/index.html'
}),
// 用于生成about.html
new htmlWebpackPlugin({
filename:'about.html'
}),
new copyWebpackPlugin({
patterns :[
{ from:'src/public',to:'public'}
]
}),
new MyPlugin()
]
};
复制代码
以上就是我们利用webpack插件移除js多余注释的过程,插件是在生命周期的钩子中挂载函数实现扩展。
结束
相信通过本文,你已经对webpack强大的插件机制有所了解,webpack还有许多强大的插件,来满足我们日常的需求 对于本文章,你有任何疑问,可在评论区留言。如果想进前端交流群(目前群里有40余人前端工程师,气氛活跃,欢迎大家加入),可以加我微信fangdongdong_25,请备注掘金哦。