postProcessHtml(
    compiler,
    originalHtml,
    assetsInformationByGroups,
    assetTags,
  ) {
    let html = originalHtml;

    if (typeof html !== "string") {
      return Promise.reject(
        new Error(
          "Expected html to be a string but got " + JSON.stringify(html),
        ),
      );
    }

    if (this.options.inject) {
      const htmlRegExp = /(<html[^>]*>)/i;
      const headRegExp = /(<\/head\s*>)/i;
      const bodyRegExp = /(<\/body\s*>)/i;
      const metaViewportRegExp = /<meta[^>]+name=["']viewport["'][^>]*>/i;
      const body = assetTags.bodyTags.map((assetTagObject) =>
        htmlTagObjectToString(assetTagObject, this.options.xhtml),
      );
      const head = assetTags.headTags
        .filter((item) => {
          if (
            item.tagName === "meta" &&
            item.attributes &&
            item.attributes.name === "viewport" &&
            metaViewportRegExp.test(html)
          ) {
            return false;
          }

          return true;
        })
        .map((assetTagObject) =>
          htmlTagObjectToString(assetTagObject, this.options.xhtml),
        );

      if (body.length) {
        if (bodyRegExp.test(html)) {
          // Append assets to body element
          html = html.replace(bodyRegExp, (match) => body.join("") + match);
        } else {
          // Append scripts to the end of the file if no <body> element exists:
          html += body.join("");
        }
      }

      if (head.length) {
        // Create a head tag if none exists
        if (!headRegExp.test(html)) {
          if (!htmlRegExp.test(html)) {
            html = "<head></head>" + html;
          } else {
            html = html.replace(htmlRegExp, (match) => match + "<head></head>");
          }
        }

        // Append assets to head element
        html = html.replace(headRegExp, (match) => head.join("") + match);
      }

      // Inject manifest into the opening html tag
      if (assetsInformationByGroups.manifest) {
        html = html.replace(/(<html[^>]*)(>)/i, (match, start, end) => {
          // Append the manifest only if no manifest was specified
          if (/\smanifest\s*=/.test(match)) {
            return match;
          }
          return (
            start +
            ' manifest="' +
            assetsInformationByGroups.manifest +
            '"' +
            end
          );
        });
      }
    }

    // TODO avoid this logic and use https://github.com/webpack-contrib/html-minimizer-webpack-plugin under the hood in the next major version
    // Check if webpack is running in production mode
    // @see https://github.com/webpack/webpack/blob/3366421f1784c449f415cda5930a8e445086f688/lib/WebpackOptionsDefaulter.js#L12-L14
    const isProductionLikeMode =
      compiler.options.mode === "production" || !compiler.options.mode;
    const needMinify =
      this.options.minify === true ||
      typeof this.options.minify === "object" ||
      (this.options.minify === "auto" && isProductionLikeMode);

    if (!needMinify) {
      return Promise.resolve(html);
    }

    const minifyOptions =
      typeof this.options.minify === "object"
        ? this.options.minify
        : {
            // https://www.npmjs.com/package/html-minifier-terser#options-quick-reference
            collapseWhitespace: true,
            keepClosingSlash: true,
            removeComments: true,
            removeRedundantAttributes: true,
            removeScriptTypeAttributes: true,
            removeStyleLinkTypeAttributes: true,
            useShortDoctype: true,
          };

    try {
      html = require("html-minifier-terser").minify(html, minifyOptions);
    } catch (e) {
      const isParseError = String(e.message).indexOf("Parse Error") === 0;

      if (isParseError) {
        e.message =
          "html-webpack-plugin could not minify the generated output.\n" +
          "In production mode the html minification is enabled by default.\n" +
          "If you are not generating a valid html output please disable it manually.\n" +
          "You can do so by adding the following setting to your HtmlWebpackPlugin config:\n|\n|" +
          "    minify: false\n|\n" +
          "See https://github.com/jantimon/html-webpack-plugin#options for details.\n\n" +
          "For parser dedicated bugs please create an issue here:\n" +
          "https://danielruf.github.io/html-minifier-terser/" +
          "\n" +
          e.message;
      }

      return Promise.reject(e);
    }

    return Promise.resolve(html);
  }
Html Post processing

@private
@param {Compiler} compiler The compiler instance
@param {any} originalHtml The input html
@param {AssetsInformationByGroups} assetsInformationByGroups
@param {{headTags: HtmlTagObject[], bodyTags: HtmlTagObject[]}} assetTags The asset tags to inject
@returns {Promise<string>}