evaluateCompilationResult(source, publicPath, templateFilename) {
    if (!source) {
      return Promise.reject(
        new Error("The child compilation didn't provide a result"),
      );
    }

    // The LibraryTemplatePlugin stores the template result in a local variable.
    // By adding it to the end the value gets extracted during evaluation
    if (source.indexOf("HTML_WEBPACK_PLUGIN_RESULT") >= 0) {
      source += ";\nHTML_WEBPACK_PLUGIN_RESULT";
    }

    const templateWithoutLoaders = templateFilename
      .replace(/^.+!/, "")
      .replace(/\?.+$/, "");
    const vmContext = vm.createContext({
      ...global,
      HTML_WEBPACK_PLUGIN: true,
      require: require,
      htmlWebpackPluginPublicPath: publicPath,
      __filename: templateWithoutLoaders,
      __dirname: path.dirname(templateWithoutLoaders),
      AbortController: global.AbortController,
      AbortSignal: global.AbortSignal,
      Blob: global.Blob,
      Buffer: global.Buffer,
      ByteLengthQueuingStrategy: global.ByteLengthQueuingStrategy,
      BroadcastChannel: global.BroadcastChannel,
      CompressionStream: global.CompressionStream,
      CountQueuingStrategy: global.CountQueuingStrategy,
      Crypto: global.Crypto,
      CryptoKey: global.CryptoKey,
      CustomEvent: global.CustomEvent,
      DecompressionStream: global.DecompressionStream,
      Event: global.Event,
      EventTarget: global.EventTarget,
      File: global.File,
      FormData: global.FormData,
      Headers: global.Headers,
      MessageChannel: global.MessageChannel,
      MessageEvent: global.MessageEvent,
      MessagePort: global.MessagePort,
      PerformanceEntry: global.PerformanceEntry,
      PerformanceMark: global.PerformanceMark,
      PerformanceMeasure: global.PerformanceMeasure,
      PerformanceObserver: global.PerformanceObserver,
      PerformanceObserverEntryList: global.PerformanceObserverEntryList,
      PerformanceResourceTiming: global.PerformanceResourceTiming,
      ReadableByteStreamController: global.ReadableByteStreamController,
      ReadableStream: global.ReadableStream,
      ReadableStreamBYOBReader: global.ReadableStreamBYOBReader,
      ReadableStreamBYOBRequest: global.ReadableStreamBYOBRequest,
      ReadableStreamDefaultController: global.ReadableStreamDefaultController,
      ReadableStreamDefaultReader: global.ReadableStreamDefaultReader,
      Response: global.Response,
      Request: global.Request,
      SubtleCrypto: global.SubtleCrypto,
      DOMException: global.DOMException,
      TextDecoder: global.TextDecoder,
      TextDecoderStream: global.TextDecoderStream,
      TextEncoder: global.TextEncoder,
      TextEncoderStream: global.TextEncoderStream,
      TransformStream: global.TransformStream,
      TransformStreamDefaultController: global.TransformStreamDefaultController,
      URL: global.URL,
      URLSearchParams: global.URLSearchParams,
      WebAssembly: global.WebAssembly,
      WritableStream: global.WritableStream,
      WritableStreamDefaultController: global.WritableStreamDefaultController,
      WritableStreamDefaultWriter: global.WritableStreamDefaultWriter,
    });

    const vmScript = new vm.Script(source, {
      filename: templateWithoutLoaders,
    });

    // Evaluate code and cast to string
    let newSource;

    try {
      newSource = vmScript.runInContext(vmContext);
    } catch (e) {
      return Promise.reject(e);
    }

    if (
      typeof newSource === "object" &&
      newSource.__esModule &&
      newSource.default !== undefined
    ) {
      newSource = newSource.default;
    }

    return typeof newSource === "string" || typeof newSource === "function"
      ? Promise.resolve(newSource)
      : Promise.reject(
          new Error(
            'The loader "' + templateWithoutLoaders + "\" didn't return html.",
          ),
        );
  }
Once webpack is done with compiling the template into a NodeJS code this function
evaluates it to generate the html result

The evaluateCompilationResult is only a class function to allow spying during testing.
Please change that in a further refactoring

@param {string} source
@param {string} publicPath
@param {string} templateFilename
@returns {Promise<string | (() => string | Promise<string>)>}