重学webpack系列(四) -- webpack的plugins机制的解读
前言
我们所了解的plugin
也是webpack
核心机制的一种,与loader
在项目中加载资源模块实现模块化的工作不同的是,plugin
能够解决除了资源模块加载打包之外的项目自动化的工作,增强了webpack
在项目的构建能力。
plugin能够解决的常见的场景
-
自动清除上一次的打包结果,比如
clean-webpack-plugin
。- 上一章我们已经使用到了
clean-webpack-plugin
,实现了每一次的build
文件夹自动删除替换,因为每一次打包我们生成的文件hash
不一样,导致文件名不一样,不一样的文件只会增量叠加,覆盖的只是那些同名的文件,所以我们需要把上一次的所有build
的内容全部清除掉。
- 上一章我们已经使用到了
-
根据模板自动生成需要的
html
文件,比如html-webpack-plugin
。- 上一章我们利用了
html-webpack-plugin
插件,实现了html
的生成,他可以自动引入我们打包后依赖的js
文件。
- 上一章我们利用了
-
压缩
webpack
打包后的输出文件,比如uglifyjs-webpack-plugin
、mini-css-extract-plugin
、imagemin-webpack-plugin
。 -
每一次修改模块代码之后实现热替换,比如
Hot Module Replacement
-
帮助开发者分析打包后的文件,以便做性能优化,比如
webpack-bundle-analyzer
-
拆分不需要打包的资源直接输出到文件目录,比如
copy-webpack-plugin
,自动发布打包结果到服务器实现自动化部署等。
插件的基本使用
在这里我们就以html-webpack-plugin
为例来讲述一下它的具体使,我们可以在下面看到它的基本配置。
// 安装
npm i html-webapck-plugin -S
// 引入
const HtmlWebpackPlugin = require('html-webpack-plugin')
// webpack.config.json
module.exports = {
...
plugins:[
...
new HtmlWebpackPlugin({
// 页面title
titie: 'title',
// 使用模板
template: './index.html',
meta:{
// 修改meta标签
viewport: 'width=device-widt, initial-scale=2.0'
},
// 输出到目录的文件名,默认index.html,配合多个HtmlWebpackPlugin实例,可以生成多个html文件
filename: 'main.html'
// 用于生成外链标签的src的公共路径
publicPath: './',
// script加载方式,比如defer,type=’module‘
scriptLoading: 'module',
// 用于指定favicon到选项卡里面
favicon: '....',
// 用于破坏缓存hash,设置了true则会在改变内容之后,每一次的打包之后改变hash
hash: true
更多请查阅:https://github.com/jantimon/html-webpack-plugin
}),
...
]
...
}
所以经过这样的配置,html-webpack-plugin
就可以成功使用了,再比如一些不需要参与构建的文件,比如favicon
,我们通常希望webpack
能帮助我们把它处理到静态目录里面,以便于上线的时候,随着资源包一起发布。
// 安装
npm i copy-webpack-plugin
// 引入
const CopyWebpackplugin = require('copy-webpack-plugin');
// webpack.config.json
module.exports = {
...
plugins: [
new CopyWebpackPlugin([
{
patterns:[
{
// 以什么目录下资源作为源文件
from: path.resolve(__dirname, './static'),
// copy到那个目录里面去
to: path.resolve(__dirname, 'build/static'),
// 忽略掉不处理的文件
ignore:[
"**/index.html",
"**/.DS_Store",
]
},
]
}
])
]
}
插件系统尤其复杂,各位同学应该多多去看看官网对插件的描述及其用法,那么插件究竟是怎么样工作的呢,我们应该去探索一下插件背后的秘密。
插件的工作原理
webpack
的plugin
的工作机制,说通俗一点就类似于框架里面的生命周期机制,它具有很多的生命周期钩子,比如enterOption
、run
、watchRun
、compile
等,具体的同学们可以去查阅 官方文档,他能够提供模块
/流程中
所需要功能的处理的功能,举个例子,比如我们在使用css-loader
的时候,我们希望实现css
与js
文件的去空格化压缩,所以在这个时刻,webpack
能够利用相应的plugin
来帮我们处理。当然光了解plugin执行原理可不行,我们还得去了解一下webpack的构建流程与原理,详细请戳 >>> 重学webpack系列(八) -- webpack的构建原理与流程。
编写一个自己的插件
需求
- 我们想把一个
html
文件中的类名改掉,从index
改成main
,比如
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Document</title>
<link rel="stylesheet" href="">
</head>
<body>
<div class="index"></div>
</body>
</html>
插件的要求
- 每一个插件的本身就是一个函数。
- 每个函数内部都要实现一个
apply
方法。 - 借助
webpack
生命周期钩子,通过compiler
对象访问钩子,帮我们把插件注入到webpack
运行流程中执行。 - 根据需求编写我们的逻辑。
所以大致源码如下
// webpack.config.json
const ChangeWebpackplugin = require('./change-webpack-plugin.js')
module.exports = {
...
plugins:[
new ChangeWebpackPlugin( )
]
...
}
// change-webpack-plugin.js
class ChangeWebpackPlugin {
// webpack启动的时候会调用apply方法
apply(compiler){
console.log('ChangeWebpackPlugin 插件启动');
compiler.hooks.emit.tap('ChangeWebpackPlugin', compilation => {
for(const name in compilation.assets){
// 找到了所有打包后的文件 .assets
if(name.endsWith('.js')){
// 读取原内容
const content = compilation.assets[name].source();
// 处理逻辑
const changeClassNameContent = content.replace("index", "main")
// 处理函数逻辑
compilation.assets[name] = {
source:()=> changeClassNameContent,
size: ()=> changeClassNameContent.length
}
}
}
})
}
}
// 导出函数
module.exports = ChangeWebpackPlugin;
文件效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Document</title>
<link rel="stylesheet" href="">
</head>
<body>
<div class="main"></div>
</body>
</html>
总结
转载自:https://juejin.cn/post/7146175092349730853