class AsyncPlugin { apply(compiler) { compiler.hooks.emit.tapAsync('plugin', (comliation, cb) => { setTimeout(() => { console.log('等一等') cb() }, 1000) }) compiler.hooks.emit.tapPromise('plugin', (comliation) => { return new Promise((resolve, reject) => { setTimeout(() => { console.log('promise') resolve() }, 1000) }) }) }}module.exports = AsyncPlugin
输出列表及对应大小md
class FileListPlugin { constructor({filename}) { this.filename = filename } apply(compiler) { // 文件准备好了要进行发射 compiler.hooks.emit.tap('plugin', (compilation) => { let assets = compilation.assets let content = `## 文件名 资源大小\r\n` Object.entries(assets).forEach(([filename, statObj]) => { content += `- ${filename} ${statObj.size()}\r\n` }) assets[this.filename] = { source() { return content }, size() { return content.length } } }) }}module.exports = FileListPlugin
把js css 都内嵌至html文件中
new InlineSourcePlugin({ match: /\.(js|css)/ }),// 内联资源 css 使用style标签 js 都放在内部const HtmlWebpackPlugin = require('html-webpack-plugin')const pluginName = 'InlineSourcePlugin'class InlineSourcePlugin { constructor({match}) { this.reg = match // 正则 } apply(compiler) { // 通过 html-webpackplugin 实现这个功能 // compilation 当前编译的资源 compiler.hooks.compilation.tap(pluginName, compilation => { HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync(pluginName, (data, cb) => { // 当前文件的内容都在 compilation 中 // 虚拟dom data = this.processTags(data, compilation) cb(null, data) }) }) } processTags(data, compilation) { // 处理引入标签的数据 let headTags = [] let bodyTags = [] // 放在head里面的标签 data.headTags.forEach(headTag => { headTags.push(this.processTag(headTag, compilation)) }) data.bodyTags.forEach(bodyTag => { bodyTags.push(this.processTag(bodyTag, compilation)) }) return { ...data, headTags, bodyTags } } // 处理某一个标签 processTag(tag, compilation) { console.log(tag) let newTag, url if (tag.tagName === 'link' && this.reg.test(tag.attributes.href)) { newTag = { tagName: 'style', attributes: { type: 'text/css'} } url = tag.attributes.href } if (tag.tagName === 'script' && this.reg.test(tag.attributes.src)) { newTag = { tagName: 'style', attributes: { type: 'application/javascript' } } url = tag.attributes.src } if (url) { // 理解为 虚拟dom, 有tag 的属性 newTag.innerHTML = compilation.assets[url].source() // 文件内容 放到innerhtml属性中 // 处理完文件后 删除 文件 delete compilation.assets[url] return newTag } return tag }}module.exports = InlineSourcePlugin
上传 插件
new UploadPlugin({ bucket: '', domain: '', accessKey: '', secretKey: '' })let path = require('path')let qiniu = require('qiniu')class UploadPlugin { constructor(options) { let { bucket = '', domain = '', accessKey = '', secretKey = '' } = options let mac = new qiniu.auth.digest.Mac(accessKey, secretKey) let putPolicy = new qiniu.rs.PutPolicy({ scope: bucket }) this.uploadToken = putPolicy.uploadToken(mac) let config = new qiniu.conf.Config() this.formUploader = new qiniu.form_up.FormUploader(config) this.putExtra = new qiniu.form_up.PutExtra() } apply(compiler) { compiler.hooks.afterEmit.tapPromise('uploadPlugin', compilation => { let assets = compilation.assets let promises = [] Object.keys(assets).forEach(filename => { promises.push(this.upload(filename)) }) return Promise.all(promises) }) } upload(filename) { let localFile = path.resolve(__dirname, '../dist',filename) return new Promise((resolve, reject) => { this.formUploader.putFile(this.uploadToken, filename, localFile, this.putExtra, function(respErr, respBody, respInfo) { if (respErr) { reject(respErr) } if (respInfo.statusCode == 200) { resolve(respBody) } }) }) }}module.exports = UploadPlugin