Webpack打包改造--插入自定義內容

Webpack打包改造--插入自定義內容

1、描述

在實際業務開發中,有可能遇到這樣一種問題,因平臺打包或者差別性等緣由,提交給測試的包,咱們須要肯定是否爲某一版本,這就要求咱們的生成包中須要有一版本標記,而且這個版本標記在運行時是固定不變但在下次編譯時是可變的,並且在打包編譯生成時寫入。
前端工程化,目前使用較多的爲Webpack,本文討論的是v4.0+的版本。
效果以下:
javascript


業務要求--在代碼裏邊寫入以下相似內容:

通過分析和比較現有方案,選擇使用HtmlWebpackPlugin這種自定義插件方式進行。

2、插件分析

1.HtmlWebpackPlugin

按按官方描述:
css

This is a webpack plugin that simplifies creation of HTML files to serve your webpack bundles. This is especially useful for webpack bundles that include a hash in the filename which changes every compilation. You can either let the plugin generate an HTML file for you, supply your own template using lodash templates or use your own loader.
html

說白了就是它能在編譯各個階段提供一系列對html,css,js資源控制的勾子回調函數,在回調函數攔截中咱們能夠對打包結果進行自定義輸出干預。 這樣就能知足當Webpack某些功不能知足咱們業務需求時,可以使用此功能做爲有利的擴充。
HtmlWebpackPlugin前端

2.勾子函數

HtmlWebpackPlugin提供的勾子分紅5個部份,以下圖所示:
vue

從上至下依次執行5個步驟:

  • 開始生成HTML以前勾子(HtmlWebpackPlugin BeforeHtmlGeneration)
    這一階作一些資源歸類工做,主要產出物爲asset資源原始對象,該對象爲插入HTML頭尾部的JS,CSS資源列表及其路徑。
    java

  • 在HTML開始處理以前勾子(HtmlWebpackPlugin BeforeHtmlProcessing)
    生成不包括JS和CSS的純HTML結果,產出物爲html字符串。
    webpack

  • 添加資源處理HTML勾子(HtmlWebpackPluginAlterAssetTags)
    組裝要插入HTML頁面中的JS,CSS等資源結構, 若是要在生成HTML頁面中加入自定義或者WEBPACK不支持的<script>標籤等,可操做該對象。
    git

  • HTML處理完畢勾子(HtmlWebpackPluginAfterHtmlProcessing)
    HTML頁處理完成階段,JS,CSS完成插入,已生成可直接打包用的文本結構,通常要輸出自定義內容在此處實現。
    github

  • 勾子任務處理完畢發送事件時(HtmlWebpackPluginAfterEmit)
    處理任務最後階段,可經過返回的html屬性訪問source和size屬性。
    web

3、功能實現

1.編寫插件類

由以上插件編譯過程分析得知,咱們須要實現的功能,須要在(HtmlWebpackPluginAfterHtmlProcessing)這一階段完成,基本原理爲,生成時間截,替換<html>標籤,插入自定義內容。

  • 類結構

    HtmlWbpackPlugin勾子,入口爲apply函數,該函數返回compiler對象,即當前處理編譯的對象,該對象有個hooks屬性,利用這個屬性和其子屬性中能夠方問tap方法,在這裏能夠掛載處理過程函數。 將全部勾子添加後的代碼結果相似以下:
    其中,htmlPluginData爲攔截的處理對象,callback爲該勾子的回調,記住須要處理回調,不然,插件沒法在該步驟往下執行。

  • 生成時間截

該功能爲特定業務需求,這裏將它們封裝在一個更細化功能劃分的函數中實現,最終實現是返回可讀時間截。

  • 替換<html>標籤
    完成業務功能以後,下一步須要的則是作打包輸出改造,在這裏將該字符串替換<html>標籤的方式進行。

2.與Vue結合

通過前面步驟,進行的是插件封裝,下一步,須要將插件與現有Webpack打包機制結合,本示例展現的是使用Vue框架狀況下的Webpack功能擴展。
在Vue中,須要改造vue.config.js
vue.config.js提供了完善的Webpack擴展機制。打開配置後,咱們只需關注點在configureWebpack: {...}這段配置中。

加入自定義插件:定位到 configureWebpack屬性中的 plugins:[],添加自定義手件便可。

3.核心代碼

/** 自定義插件,插入打包日期版本號 */
class HtmlWebpackCommonLibsPlugin {
	constructor(options) {
		// 外部傳入配置
		this.options = options || {};
	}

	apply(compiler) {
	    // 插件名
		const pluginName = 'HtmlWebpackCommonLibsPlugin';

		if (compiler.hooks) {
			
			// webpack 4 support
			compiler.hooks.compilation.tap(pluginName, (compilation) => {

				// 開始生成html以前勾子
				compilation.hooks.htmlWebpackPluginBeforeHtmlGeneration.tapAsync(
					pluginName,
					(htmlPluginData, callback) => {
						// htmlWebpackPluginBeforeHtmlGeneration 返回 HtmlWebpackPlugin對象
						// {
						// assets
						// outputName
						// plugin
						// }
						// console.log(htmlPluginData);
						callback(null, htmlPluginData);
					}
				);

				// 在html開始處理以前勾子
				compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing.tapAsync(
					pluginName,
					(htmlPluginData, callback) => {
						// htmlWebpackPluginBeforeHtmlProcessing 返回 HtmlWebpackPlugin對象
						// {
						// html
						// assets
						// outputName
						// plugin
						// }
						// console.log(htmlPluginData);
						callback(null, htmlPluginData);
					}
				);

				// 添加資源處理HTML勾子
				compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(
					pluginName,
					(htmlPluginData, callback) => {
						// htmlWebpackPluginAlterAssetTags 返回 HtmlWebpackPlugin對象
						// {
						// head
						// body
						// chunks
						// outputName
						// plugin
						// }
						// console.log(htmlPluginData);
						callback(null, htmlPluginData);
					}
				);
				
				// HTML處理完畢勾子
				compilation.hooks.htmlWebpackPluginAfterHtmlProcessing.tapAsync(
					pluginName,
					(htmlPluginData, callback) => {
						// 生成格式化後時間截
						const injectStr = this.getInjectContent();
						htmlPluginData.html = htmlPluginData.html.replace('</html>', injectStr);
						
						// htmlWebpackPluginAfterHtmlProcessing 返回 HtmlWebpackPlugin對象
						// {
						// html 字符串
						// assets
						// plugin
						// childCompilerHash
						// childCompilationOutputName
						// assetJson
						// outputName
						// }
						// console.log(htmlPluginData);
						callback(null, htmlPluginData)
					}
				);
				
				// 勾子任務處理完畢發送事件時
				compilation.hooks.htmlWebpackPluginAfterEmit.tapAsync(
					pluginName,
					(htmlPluginData, callback) => {
						// htmlWebpackPluginAfterEmit 返回 HtmlWebpackPlugin對象
						// {
						// html 簡化對象 { source, size }
						// outputName
						// plugin
						// childCompilerHash
						// childCompilationOutputName
						// assetJson
						// }
						// console.log(htmlPluginData);
						callback(null, htmlPluginData);
					}
				);
			});
		}
	}

	/** 格式化小於10數字 */
	getAbsValue(value) {
		if (value < 10) {
			return `0${value.toString()}`;
		} else {
			return value.toString();
		}
	}

	/** 生成格式化後時間截 */
	getInjectContent() {
		const dateVal = new Date(); 
		const versionNum = 
			dateVal.getFullYear() + '/' +
			this.getAbsValue((dateVal.getMonth()+1)) + '/' +
			this.getAbsValue(dateVal.getDate()) + ' ' +
			this.getAbsValue(dateVal.getHours()) + ':' +
			this.getAbsValue(dateVal.getMinutes());
		const injectStr = ` <script type="text/javascript">console.log("當前版本: ${versionNum}");</script></html> `;

		return injectStr;
	}
}
  
module.exports = HtmlWebpackCommonLibsPlugin;
複製代碼

4、總結

本示例中使用的功能能夠以此爲母板,擴充到工程化中干擾Html生成時打包結果的方方面面。好比:

  • 給輸出的<script>或者<style>標籤加上自定義內容
  • 給輸出的<script>標籤添都加上crossorigin
  • 插入免打包公共底層核心等等

下圖中所示內容爲以前作過的一個Webpack擴充方案的部份代碼片段,主要干預了<script><style>自定義輸出,僅供參考:

相關文章
相關標籤/搜索