/* MIT License http://www.opensource.org/licenses/mit-license.php */ "use strict"; const { pathToFileURL } = require("url"); const { AsyncSeriesHook, AsyncSeriesWaterfallHook } = require("tapable"); const { RawSource } = require("webpack-sources"); const Compilation = require("../Compilation"); const EntryOptionPlugin = require("../EntryOptionPlugin"); const EntryPlugin = require("../EntryPlugin"); const HotUpdateChunk = require("../HotUpdateChunk"); const { HTML_TYPE } = require("../ModuleSourceTypeConstants"); const { HTML_MODULE_TYPE } = require("../ModuleTypeConstants"); const NormalModule = require("../NormalModule"); const { toTemplateSourceFileName } = require("../TemplatedPathPlugin"); const ConstDependency = require("../dependencies/ConstDependency"); const StaticExportsDependency = require("../dependencies/StaticExportsDependency"); const WebpackError = require("../errors/WebpackError"); const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin"); const { compareModulesByFullName } = require("../util/comparators"); const createHash = require("../util/createHash"); const createHooksRegistry = require("../util/createHooksRegistry"); const { getUndoPath, makePathsRelative } = require("../util/identifier"); const implicitTypeLoaderFallback = require("../util/implicitTypeLoaderFallback"); const lazyModule = require("../util/lazyModule"); const memoize = require("../util/memoize"); const { digestNonNumericOnly } = require("../util/nonNumericOnlyHash"); const preloadModuleType = require("../util/preloadModuleType"); const { PUBLIC_PATH_AUTO: autoPlaceholder } = require("../util/publicPathPlaceholder"); const removeBOM = require("../util/removeBOM"); const HtmlModule = require("./HtmlModule"); const getMimeTypes = memoize(() => require("../util/mimeTypes")); const getHtmlSyntax = memoize(() => require("./syntax")); // Lazy: this plugin is applied on every build (`experiments.html` defaults on), // but the HTML parser and tokenizer are only reached once HTML is in the graph. const getHtmlParser = lazyModule(() => require("./HtmlParser")); // html generation only happens once a build actually has an html module const getHtmlGenerator = memoize(() => require("./HtmlGenerator")); /** * @import { * EntryDescriptionNormalized, * OutputHtmlOptions, * HtmlFaviconIcon * } from "../../declarations/WebpackOptions" */ /** @typedef {import("../../declarations/WebpackOptions").OutputHtmlOptions["favicon"]} FaviconOption */ /** @typedef {import("../../declarations/WebpackOptions").OutputHtmlOptions["manifest"]} ManifestOption */ /** @typedef {Exclude} FaviconIcon */ /** @import Compiler from "../Compiler" */ /** @import { HtmlModuleBuildInfo } from "./HtmlModule" */ /** @import HtmlParser from "./HtmlParser" */ /** @typedef {{ request: string, entryName: string, type: "script" | "script-module" | "modulepreload" | "stylesheet" | "html" | "preload" | "prefetch", css?: boolean }} HtmlEntryInfo */ /** @typedef {{ outputName: string }} HtmlTransformHtmlContext */ /** @typedef {{ outputName: string }} HtmlEmittedContext */ /** * A tag to inject into an emitted page as a structured descriptor. Injected * verbatim (not re-bundled) at the `injectTo` position. * @typedef {object} HtmlTagDescriptor * @property {string} tag tag name, e.g. `"script"` / `"link"` / `"meta"` * @property {Record=} attrs attributes; `true` renders a bare boolean attribute, `false`/`undefined` is omitted * @property {string=} children inner content (ignored for void elements like ``/``) * @property {("head" | "body" | "head-prepend" | "body-prepend")=} injectTo placement; defaults to `"head"` * @property {boolean=} voidTag force a void element (no closing tag); inferred from the tag name when omitted */ /** @typedef {{ outputName: string, html: string }} HtmlInjectTagsContext */ /** * A ``); } } const headTags = getHtmlSyntax().buildHeadTags(htmlObj); // Injected into webpack-generated pages only; each icon's href is a // normal request the parser turns into a hashed asset. const faviconTag = resolveFaviconLinks(htmlObj.favicon, name) .map(([rel, icon]) => faviconLinkTag(rel, icon)) .join(""); const manifestTag = manifestLinkTag(htmlObj.manifest, name); const inject = htmlObj.inject; const scriptsInHead = inject === "head" || (inject !== "body" && output.module); const scriptsFirst = output.module || scriptAttr === " defer"; const headScripts = scriptsInHead ? scripts.join("") : ""; return `data:text/html,${faviconTag}${manifestTag}${headTags}${ scriptsFirst ? headScripts + links.join("") : links.join("") + headScripts }${scriptsInHead ? "" : scripts.join("")}`; } ); // Per-chunk `RawSource` reused across builds when bytes are unchanged: // keeping identity stable avoids invalidating `RealContentHashPlugin|analyse`. /** @type {Map} */ const sentinelResolvedSourceCache = new Map(); // `