在實際業務開發中,有可能遇到這樣一種問題,因平臺打包或者差別性等緣由,提交給測試的包,咱們須要肯定是否爲某一版本,這就要求咱們的生成包中須要有一版本標記,而且這個版本標記在運行時是固定不變但在下次編譯時是可變的,並且在打包編譯生成時寫入。
前端工程化,目前使用較多的爲Webpack,本文討論的是v4.0+的版本。
效果以下:
javascript
按按官方描述:
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前端
HtmlWebpackPlugin提供的勾子分紅5個部份,以下圖所示:
vue
開始生成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
由以上插件編譯過程分析得知,咱們須要實現的功能,須要在(HtmlWebpackPluginAfterHtmlProcessing)
這一階段完成,基本原理爲,生成時間截,替換<html>
標籤,插入自定義內容。
類結構
apply
函數,該函數返回compiler
對象,即當前處理編譯的對象,該對象有個hooks
屬性,利用這個屬性和其子屬性中能夠方問tap
方法,在這裏能夠掛載處理過程函數。 將全部勾子添加後的代碼結果相似以下:htmlPluginData
爲攔截的處理對象,callback
爲該勾子的回調,記住須要處理回調,不然,插件沒法在該步驟往下執行。 生成時間截
<html>
標籤<html>
標籤的方式進行。通過前面步驟,進行的是插件封裝,下一步,須要將插件與現有Webpack打包機制結合,本示例展現的是使用Vue框架狀況下的Webpack功能擴展。
在Vue中,須要改造vue.config.js
vue.config.js
提供了完善的Webpack擴展機制。打開配置後,咱們只需關注點在configureWebpack: {...}
這段配置中。
configureWebpack
屬性中的
plugins:[]
,添加自定義手件便可。
/** 自定義插件,插入打包日期版本號 */
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;
複製代碼
本示例中使用的功能能夠以此爲母板,擴充到工程化中干擾Html生成時打包結果的方方面面。好比:
<script>
或者<style>
標籤加上自定義內容<script>
標籤添都加上crossorigin
下圖中所示內容爲以前作過的一個Webpack擴充方案的部份代碼片段,主要干預了<script>
和<style>
自定義輸出,僅供參考: