A, description,

In the actual business development, is likely to encounter such a problem, by reason of platform packaging or difference, submitted to the test package, we need to determine whether a particular version, this requires that we generate package needs to have a release tag, and the release tag is fixed at run time is variable, but in the next compile time and write when you generated on the packaging. Front-end engineering, currently used more for Webpack, this paper discusses the version of V4.0 +. The effect is as follows:









Second, plug-in analysis

1.HtmlWebpackPlugin

According to official description:

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.

To put it more simply, it provides a set of callback functions that control HTML, CSS, and JS resources at all stages of compilation. In callback interception, we can customize the output of the packaged results. This will allow us to use this feature as a useful extension when some of the Webpack features do not meet our business needs. HtmlWebpackPlugin

2. Check sub function

HtmlWebpackPlugin provides hooks that are divided into 5 parts, as shown in the figure below:


  • Before HtmlWebpackPlugin BeforeHtmlGeneration this step does some resource classification work. The main output is the original asset resource object, which is the JS inserted into the header and tail of HTML, the CSS resource list and its path.

  • HtmlWebpackPlugin BeforeHtmlProcessing generates pure HTML results without JS and CSS. The output is an HTML string.

  • Add resources processing HTML hook (HtmlWebpackPluginAlterAssetTags) assembly is inserted into the HTML page in the JS, CSS resource structure, if you want to add a custom in the generated HTML page or WEBPACK does not support the < script > tag, etc., You can manipulate the object.

  • HTML processed hook (HtmlWebpackPluginAfterHtmlProcessing) HTML page processing is completed stage, JS, CSS inserts, generated can be directly packed with text structure, typically the output custom content here.

  • Hook tasks processed when sending events (HtmlWebpackPluginAfterEmit) processing task final stages, can be accessed through the returned HTML attribute the source and the size attribute.

Three, function realization

1. Write plug-in classes

By above plug-in compilation process analysis, we need to implement the function, needs to be done in (HtmlWebpackPluginAfterHtmlProcessing) this one phase, the basic principle, generation time, replace the < HTML > tags, insert custom content.

  • Class structure

    HtmlWbpackPlugin plugin, entry isapplyFunction, which returnscompilerObject, that is, the object currently processing compilation, which has ahooksProperty, using this property and its children can be queriedtapMethod, where you can mount the procedure function. The code after adding all the ticks looks like this:

    Among them,htmlPluginDataFor intercepted processing objects,callbackIs the callback for this hook, and remember that the callback needs to be handled, otherwise the plug-in will not proceed through this step.

  • Generation time cut

  • replace<html>The label

    Once the business function is complete, the next step is to do the packaged output transformation, where the string is replaced<html>Label the way.



2. Combine with Vue

After the previous steps, the plug-in packaging, the next step, need to combine the plug-in with the existing Webpack packaging mechanism, this example shows the use of Vue framework Webpack function extension. In Vue, vue.config.js needs to be reformed. Vue.config. js provides a perfect Webpack extension mechanism. Once configuration is open, we simply focus on configureWebpack: {… } in this configuration.

configureWebpack
plugins:[]

3. Core code

/** Custom plug-in, insert package date version number */
class HtmlWebpackCommonLibsPlugin {
	constructor(options) {
		// External incoming configuration
		this.options = options || {};
	}

	apply(compiler) {
	    / / the plugin name
		const pluginName = 'HtmlWebpackCommonLibsPlugin';

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

				// Start generating HTML before the tick
				compilation.hooks.htmlWebpackPluginBeforeHtmlGeneration.tapAsync(
					pluginName,
					(htmlPluginData, callback) => {
						/ / htmlWebpackPluginBeforeHtmlGeneration return HtmlWebpackPlugin object
						/ / {
						// assets
						// outputName
						// plugin
						// }
						// console.log(htmlPluginData);
						callback(null, htmlPluginData); });// Before the HTML begins processing
				compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing.tapAsync(
					pluginName,
					(htmlPluginData, callback) => {
						/ / htmlWebpackPluginBeforeHtmlProcessing return HtmlWebpackPlugin object
						/ / {
						// html
						// assets
						// outputName
						// plugin
						// }
						// console.log(htmlPluginData);
						callback(null, htmlPluginData); });// Add resources to handle HTML hooks
				compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(
					pluginName,
					(htmlPluginData, callback) => {
						/ / htmlWebpackPluginAlterAssetTags return HtmlWebpackPlugin object
						/ / {
						// head
						// body
						// chunks
						// outputName
						// plugin
						// }
						// console.log(htmlPluginData);
						callback(null, htmlPluginData); });// complete the HTML process
				compilation.hooks.htmlWebpackPluginAfterHtmlProcessing.tapAsync(
					pluginName,
					(htmlPluginData, callback) => {
						// Generate a formatted time slice
						const injectStr = this.getInjectContent();
						htmlPluginData.html = htmlPluginData.html.replace('</html>', injectStr);
						
						/ / htmlWebpackPluginAfterHtmlProcessing return HtmlWebpackPlugin object
						/ / {
						// HTML string
						// assets
						// plugin
						// childCompilerHash
						// childCompilationOutputName
						// assetJson
						// outputName
						// }
						// console.log(htmlPluginData);
						callback(null, htmlPluginData)
					}
				);
				
				// The event is sent after the subtask is processed
				compilation.hooks.htmlWebpackPluginAfterEmit.tapAsync(
					pluginName,
					(htmlPluginData, callback) => {
						/ / htmlWebpackPluginAfterEmit return HtmlWebpackPlugin object
						/ / {
						// HTML simplified object {source, size}
						// outputName
						// plugin
						// childCompilerHash
						// childCompilationOutputName
						// assetJson
						// }
						// console.log(htmlPluginData);
						callback(null, htmlPluginData); }); }); }}/** Format less than 10 digits */
	getAbsValue(value) {
		if (value < 10) {
			return ` 0${value.toString()}`;
		} else {
			returnvalue.toString(); }}/** Generates a time cut after formatting */
	getInjectContent() {
		const dateVal = new Date(a);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(" current version:${versionNum}"); </script></html> `;

		returninjectStr; }}module.exports = HtmlWebpackCommonLibsPlugin;
Copy the code


Four,

The functionality used in this example can be used as a motherboard to extend to all aspects of engineering that interfere with Html generation when packaging results. Such as:

  • To the output of the<script>or<style>Tag with custom content
  • To the output of the<script>Add all the tagscrossorigin
  • Insert package-free common underlying core and so on

The following is a snippet of code from a Webpack extension solution that mainly interferes with the custom output of