webpack的插件可以加入自定义构建的行为,使webpack更加灵活的执行更广泛的任务
webpack在编译源码的过程中,会触发一系列的Tapable钩子事件,而插件就找到合适时机的钩子事件,向其挂载自己的任务,这样就会在webpack构建的时候随着钩子触发而执行
webpack生命周期两个核心对象compiler和compilation
Compiler
模块是 webpack 的主要引擎,它通过 CLI 或者 Node API 传递的所有选项创建出一个 compilation 实例。 它扩展(extends)自Tapable
类,用来注册和调用插件。 大多数面向用户的插件会首先在Compiler
上注册。
compiler.options 可以访问本次启动 webpack 时候所有的配置文件,包括但不限于 loaders 、 entry 、 output 、 plugin 等等完整配置信息。
compiler.inputFileSystem 和 compiler.outputFileSystem 可以进行文件操作,相当于 Nodejs 中 fs。
compiler.hooks 可以注册 tapable 的不同种类 Hook,从而可以在 compiler 生命周期中植入不同的逻辑。
compilation 对象代表一次资源的构建,compilation 实例能够访问所有的模块和它们的依赖。
一个 compilation 对象会对构建依赖图中所有模块,进行编译。 在编译阶段,模块会被加载(load)、封存(seal)、优化(optimize)、 分块(chunk)、哈希(hash)和重新创建(restore)。
class TestPlugin{
constructor(str){
console.log('str=============>',str)
}
apply(compiler){
//同步钩子
compiler.hooks.environment.tap("TestPlugin",() => {
console.log("enviroment");
})
compiler.hooks.emit.tap("TestPlugin",(compilation) => {
// console.log('compilation=============>',compilation)
})
//异步钩子
//emit是串行钩子,即钩子函数是一个个按顺序执行,例如以下需要花3s
compiler.hooks.emit.tapAsync("TestPlugin",(compilation,callback) => {
setTimeout(() => {
console.log("emit Async 111");
// console.log('compilation=============>',compilation)
callback()
}, 1000);
})
compiler.hooks.emit.tapPromise("TestPlugin",(compilation) => {
return new Promise((resolve,reject)=>{
setTimeout(() => {
console.log("emit Async 222");
resolve()
}, 2000);
})
})
//make是并行钩子,,以下需要花2s
compiler.hooks.make.tapAsync("TestPlugin",(compilation,callback) => {
setTimeout(() => {
console.log("make Async 111");
// console.log('compilation=============>',compilation)
callback()
}, 1000);
})
compiler.hooks.make.tapAsync("TestPlugin",(compilation) => {
return new Promise((resolve,reject)=>{
setTimeout(() => {
console.log("make Async 222");
resolve()
}, 2000);
})
})
//注册compilation的钩子
compiler.hooks.compilation.tap('TestPlugin', (compilation) => {
compilation.hooks.seal.tap('TestPlugin', () => {
console.log('compilation.hooks.seal hook called');
});
});
}
}
module.exports=TestPlugin
clean-webpack-plugin每次打包用于清除dist下目录的文件
class CleanWebpackPlugin {
apply(complier){
const outputPath = complier.options.output.path
const fs = complier.outputFileSystem
complier.hooks.emit.tap('CleanWebpackPlugin',(compliation) => {
this.removeFiles(fs,outputPath)
})
}
removeFiles(fs,outputPath){
const files = fs.readdirSync(outputPath)
files.forEach((file) => {
const pathfile = outputPath+"\\" +file
if(fs.statSync(pathfile).isFile()){
fs.unlinkSync(pathfile)
return
}else{
this.removeFiles(fs,pathfile)
}
//清空目录
fs.rmdirSync(pathfile)
})
}
//Api一行解决
// removeFiles(fs,outputPath){
// fs.rmdirSync(outputPath,{recursive:true})
// }
}
module.exports=CleanWebpackPlugin
将runtime等js文件改为内联的嵌入html的方式
runtime文件是用于解决缓存问题出现的
const HtmlWebpackPlugin = require('html-webpack-plugin');
class InlineChunkPlugin{
constructor({tests=[]}){
this.tests=tests
}
apply(compiler){
compiler.hooks.compilation.tap('InlineChunkPlugin', (compilation) => {
// console.log('The compiler is starting a new compilation...')
// Static Plugin interface |compilation |HOOK NAME | register listener
const hooks = HtmlWebpackPlugin.getHooks(compilation)
hooks.alterAssetTagGroups.tap("InlineChunkPlugin",(assets) => {
// console.log('assets.headTags=============>',assets.headTags)
/*
现在headTags的内容如下
{
tagName: 'script',
voidTag: false,
meta: { plugin: 'html-webpack-plugin' },
attributes: { defer: true, type: undefined, src: 'static/js/runtime~main.js' }
},
要修改为如下
{
tagName: 'script',
innerHTML: runtime文件内容
},
*/
assets.headTags= this.getInlineChunk(assets.headTags,compilation.assets)
//删除runtime文件
Object.keys(compilation.assets).forEach((filepath)=>{
if(this.tests.some((test)=> test.test(filepath) )){
delete compilation.assets[filepath]
}
})
})
}
)
}
getInlineChunk(headTags,assets){
return headTags.map ((tag) => {
if(tag.tagName!=='script') return tag
const filepath = tag.attributes.src;
if(!this.tests.some((test)=> test.test(filepath) ))return tag
return {
meta: { plugin: 'InlineChunkPlugin' },
tagName: 'script',
innerHTML: assets[filepath].source()
}
})
}
}
module.exports= InlineChunkPlugin