之后便可以看到打包前后的html文件的差别了。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta content="width=device-width,initial-scale=1.0"> <title><%= htmlWebpackPlugin.options.title %></title> </head> <body> <!-- inject:name="header" --> <div></div> <!-- inject:name="footer" --> <!-- built files will be auto injected --> </body> </html> <!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><title>Webpack Template</title></head><body><div>HEADER</div><div id=app></div><div>FOOTER</div><!-- built files will be auto injected --><script src=http://www.likecs.com/index.js?7e2c7994f2e0891ec351></script></body></html>webpack5对于hooks有一次更新,使用上边的插件会提示:
(node:5760) [DEP_WEBPACK_COMPILATION_ASSETS] DeprecationWarning: Compilation.assets will be frozen in future, all modifications are deprecated. BREAKING CHANGE: No more changes should happen to Compilation.assets after sealing the Compilation. Do changes to assets earlier, e. g. in Compilation.hooks.processAssets. Make sure to select an appropriate stage from Compilation.PROCESS_ASSETS_STAGE_*.所以我们可以根据其提示提前将资源进行处理,可以实现同样的效果。
// static-page-slice.js const simulateRemoteData = key => { const data = { header: "<div>HEADER</div>", footer: "<div>FOOTER</div>", }; return Promise.resolve(data[key]); }; class StaticPageSlice { constructor(options) { this.options = options || {}; // 传递参数 } apply(compiler) { compiler.hooks.thisCompilation.tap("StaticPageSlice", compilation => { compilation.hooks.processAssets.tapPromise( { name: "StaticPageSlice", stage: compilation.constructor.PROCESS_ASSETS_STAGE_ADDITIONS, additionalAssets: true, }, assets => this.replaceAssets(assets, compilation) ); }); } replaceAssets(assets, compilation) { return new Promise(resolve => { const cache = {}; const assetKeys = Object.keys(assets); for (const key of assetKeys) { const isLastAsset = key === assetKeys[assetKeys.length - 1]; if (!/.*\.html$/.test(key)) { if (isLastAsset) resolve(); continue; } let target = assets[key].source(); const matchedValues = target.matchAll(/<!-- inject:name="(\S*?)" -->/g); // `matchAll`函数需要`Node v12.0.0`以上 const tags = []; for (const item of matchedValues) { const [tag, name] = item; tags.push({ tag, name, data: cache[name] ? cache[name] : simulateRemoteData(name), }); } Promise.all(tags.map(item => item.data)) .then(res => { res.forEach((data, index) => { const tag = tags[index].tag; const name = tags[index].name; if (!cache[name]) cache[name] = data; target = target.replace(tag, data); }); }) .then(() => { compilation.assets[key] = { source() { return target; }, size() { return this.source().length; }, }; }) .then(() => { if (isLastAsset) resolve(); }); } }); } } module.exports = StaticPageSlice; 每日一题 https://github.com/WindrunnerMax/EveryDay 参考 https://webpack.docschina.org/concepts/ https://juejin.cn/post/6854573216108085261 https://webpack.docschina.org/api/plugins/ https://juejin.cn/post/6844903942736838670 https://segmentfault.com/a/1190000012840742 https://segmentfault.com/a/1190000021821557 https://webpack.docschina.org/api/compilation-hooks/ https://webpack.docschina.org/api/normalmodulefactory-hooks/