Project Init

This commit is contained in:
Muluhabt
2026-05-29 15:23:46 +03:00
commit 2fbc557aac
67387 changed files with 6063341 additions and 0 deletions

427
node_modules/webpack/lib/html/HtmlGenerator.js generated vendored Normal file
View File

@@ -0,0 +1,427 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const { RawSource, ReplaceSource } = require("webpack-sources");
const ConcatenationScope = require("../ConcatenationScope");
const Generator = require("../Generator");
const {
HTML_TYPE,
JAVASCRIPT_TYPE,
JAVASCRIPT_TYPES
} = require("../ModuleSourceTypeConstants");
const RuntimeGlobals = require("../RuntimeGlobals");
const CssUrlDependency = require("../dependencies/CssUrlDependency");
/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../../declarations/WebpackOptions").HtmlGeneratorOptions} HtmlGeneratorOptions */
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Compilation").DependencyConstructor} DependencyConstructor */
/** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */
/** @typedef {import("../Dependency")} Dependency */
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
/** @typedef {import("../Generator").UpdateHashContext} UpdateHashContext */
/** @typedef {import("../Module").SourceType} SourceType */
/** @typedef {import("../Module").SourceTypes} SourceTypes */
/** @typedef {import("../Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext */
/** @typedef {import("../ModuleGraph")} ModuleGraph */
/** @typedef {import("../NormalModule")} NormalModule */
/** @typedef {import("../util/Hash")} Hash */
/**
* @template T
* @typedef {import("../InitFragment")<T>} InitFragment
*/
/**
* @type {ReadonlySet<"javascript" | "html">}
*/
const JAVASCRIPT_AND_HTML_TYPES = new Set([JAVASCRIPT_TYPE, HTML_TYPE]);
/** @type {WeakMap<Compilation, Map<string, Chunk>>} */
const chunksByIdCache = new WeakMap();
class HtmlGenerator extends Generator {
/**
* Emit a sentinel for a chunk URL that can't be resolved at code-gen time
* (chunk hashes aren't computed yet); `resolveChunkUrlSentinels` swaps it
* for `${PUBLIC_PATH_AUTO}<chunkFilename>` once they are.
* @param {Chunk} chunk chunk
* @param {"javascript" | "css"} contentHashType which chunk content hash slot the resolved URL should reference
* @returns {string} sentinel
*/
static makeChunkUrlSentinel(chunk, contentHashType) {
const hexId = Buffer.from(String(chunk.id), "utf8").toString("hex");
return `__WEBPACK_HTML_CHUNK_URL__${hexId}__${contentHashType}__END__`;
}
/**
* Replace every `makeChunkUrlSentinel` sentinel in `content` with
* `${PUBLIC_PATH_AUTO}<chunkFilename>`. Must run after
* `Compilation#createHash()` so `[contenthash]` resolves.
* @param {string} content content
* @param {Compilation} compilation compilation
* @returns {string} resolved content
*/
static resolveChunkUrlSentinels(content, compilation) {
if (!content.includes("__WEBPACK_HTML_CHUNK_URL__")) return content;
const outputOptions = compilation.outputOptions;
let chunksById = chunksByIdCache.get(compilation);
if (chunksById === undefined) {
chunksById = new Map();
for (const chunk of compilation.chunks) {
chunksById.set(String(chunk.id), chunk);
}
chunksByIdCache.set(compilation, chunksById);
}
return content.replace(
/__WEBPACK_HTML_CHUNK_URL__([0-9a-f]+)__([a-z]+)__END__/g,
(_, hexId, contentHashType) => {
const chunkId = Buffer.from(hexId, "hex").toString("utf8");
const chunk = chunksById.get(chunkId);
if (!chunk) return "data:,";
let filenameTemplate;
if (contentHashType === "css") {
const CssModulesPlugin = require("../css/CssModulesPlugin");
filenameTemplate = CssModulesPlugin.getChunkFilenameTemplate(
chunk,
outputOptions
);
} else {
filenameTemplate =
chunk.filenameTemplate ||
(chunk.canBeInitial()
? outputOptions.filename
: outputOptions.chunkFilename);
}
const filename = compilation.getPath(
/** @type {import("../TemplatedPathPlugin").TemplatePath} */
(filenameTemplate),
{
chunk,
contentHashType
}
);
return `${CssUrlDependency.PUBLIC_PATH_AUTO}${filename}`;
}
);
}
/**
* Creates an instance of HtmlGenerator.
* @param {HtmlGeneratorOptions=} options generator options
* @param {ModuleGraph=} moduleGraph the module graph; used to detect when an HTML module is reached as a compilation entry so `extract` can default to `true` for it
*/
constructor(options, moduleGraph) {
super();
this.options = options || {};
/** @type {ModuleGraph | undefined} */
this._moduleGraph = moduleGraph;
}
/**
* Returns the reason this module cannot be concatenated, when one exists.
* @param {NormalModule} module module for which the bailout reason should be determined
* @param {ConcatenationBailoutReasonContext} context context
* @returns {string | undefined} reason why this module can't be concatenated, undefined when it can be concatenated
*/
getConcatenationBailoutReason(module, context) {
return undefined;
}
/**
* Whether this HTML module is reached as a compilation entry. Entry
* modules have at least one incoming connection without an
* `originModule` (the EntryDependency added by `compilation.addEntry`).
* @param {NormalModule} module module
* @returns {boolean} true when the module is an entry
*/
_isEntryModule(module) {
if (!this._moduleGraph) return false;
for (const connection of this._moduleGraph.getIncomingConnections(module)) {
if (!connection.originModule) return true;
}
return false;
}
/**
* Whether to emit the extracted `.html` file for this module.
* `options.extract === true` always extracts; `false` never; when the
* option is left unspecified, extraction defaults to on for HTML modules
* used as compilation entries — that's the HTML-as-entry-point use case.
* @param {NormalModule} module module
* @returns {boolean} true when the `.html` file should be emitted
*/
_shouldExtract(module) {
const { extract } = this.options;
if (extract === true) return true;
if (extract === false) return false;
return this._isEntryModule(module);
}
/**
* Returns the source types available for this module.
* @param {NormalModule} module fresh module
* @returns {SourceTypes} available types (do not mutate)
*/
getTypes(module) {
if (this._shouldExtract(module)) {
return JAVASCRIPT_AND_HTML_TYPES;
}
return JAVASCRIPT_TYPES;
}
/**
* Returns the estimated size for the requested source type.
* @param {NormalModule} module the module
* @param {SourceType=} type source type
* @returns {number} estimate size of the module
*/
getSize(module, type) {
const originalSource = module.originalSource();
if (!originalSource) return 0;
if (type === HTML_TYPE) return originalSource.size();
return originalSource.size() + 10;
}
/**
* Processes the provided module.
* @param {NormalModule} module the current module
* @param {Dependency} dependency the dependency to generate
* @param {InitFragment<GenerateContext>[]} initFragments mutable list of init fragments
* @param {ReplaceSource} source the current replace source which can be modified
* @param {GenerateContext} generateContext the render context
* @returns {void}
*/
sourceDependency(module, dependency, initFragments, source, generateContext) {
const constructor =
/** @type {DependencyConstructor} */
(dependency.constructor);
const template = generateContext.dependencyTemplates.get(constructor);
if (!template) {
throw new Error(
`No template for dependency: ${dependency.constructor.name}`
);
}
/** @type {DependencyTemplateContext} */
/** @type {InitFragment<GenerateContext>[] | undefined} */
let chunkInitFragments;
/** @type {DependencyTemplateContext} */
const templateContext = {
runtimeTemplate: generateContext.runtimeTemplate,
dependencyTemplates: generateContext.dependencyTemplates,
moduleGraph: generateContext.moduleGraph,
chunkGraph: generateContext.chunkGraph,
module,
runtime: generateContext.runtime,
runtimeRequirements: generateContext.runtimeRequirements,
concatenationScope: generateContext.concatenationScope,
codeGenerationResults:
/** @type {CodeGenerationResults} */
(generateContext.codeGenerationResults),
initFragments,
get chunkInitFragments() {
if (!chunkInitFragments) {
const data =
/** @type {NonNullable<GenerateContext["getData"]>} */
(generateContext.getData)();
chunkInitFragments = data.get("chunkInitFragments");
if (!chunkInitFragments) {
chunkInitFragments = [];
data.set("chunkInitFragments", chunkInitFragments);
}
}
return chunkInitFragments;
}
};
template.apply(dependency, source, templateContext);
}
/**
* Processes the provided dependencies block.
* @param {NormalModule} module the module to generate
* @param {import("../DependenciesBlock")} block the dependencies block which will be processed
* @param {InitFragment<GenerateContext>[]} initFragments mutable list of init fragments
* @param {ReplaceSource} source the current replace source which can be modified
* @param {GenerateContext} generateContext the generateContext
* @returns {void}
*/
sourceBlock(module, block, initFragments, source, generateContext) {
for (const dependency of block.dependencies) {
this.sourceDependency(
module,
dependency,
initFragments,
source,
generateContext
);
}
for (const childBlock of block.blocks) {
this.sourceBlock(
module,
childBlock,
initFragments,
source,
generateContext
);
}
}
/**
* Processes the provided module.
* @param {NormalModule} module the module to generate
* @param {InitFragment<GenerateContext>[]} initFragments mutable list of init fragments
* @param {ReplaceSource} source the current replace source which can be modified
* @param {GenerateContext} generateContext the generateContext
* @returns {void}
*/
sourceModule(module, initFragments, source, generateContext) {
for (const dependency of module.dependencies) {
this.sourceDependency(
module,
dependency,
initFragments,
source,
generateContext
);
}
if (module.presentationalDependencies !== undefined) {
for (const dependency of module.presentationalDependencies) {
this.sourceDependency(
module,
dependency,
initFragments,
source,
generateContext
);
}
}
for (const childBlock of module.blocks) {
this.sourceBlock(
module,
childBlock,
initFragments,
source,
generateContext
);
}
}
/**
* Run all HTML dependency templates against the original module source and
* return the rewritten HTML. When `undoPath` is a string, `[webpack/auto]`
* placeholders left in by asset/url dependencies are resolved to that
* undo path (use `""` to make URLs root-relative). When `undoPath` is
* `undefined`, the placeholders are preserved so the caller (typically
* `HtmlModulesPlugin#renderManifest`, which only knows the final
* `.html` filename after code generation) can resolve them itself.
* @param {NormalModule} module the module to render
* @param {GenerateContext} generateContext the generate context
* @param {string=} undoPath value to substitute for `[webpack/auto]` placeholders
* @returns {string} the rewritten HTML
*/
_renderHtml(module, generateContext, undoPath) {
const originalSource = /** @type {Source} */ (module.originalSource());
const source = new ReplaceSource(originalSource);
/** @type {InitFragment<GenerateContext>[]} */
const initFragments = [];
this.sourceModule(module, initFragments, source, generateContext);
if (undoPath === undefined) {
// HTML output — leave sentinels and `[webpack/auto]` for renderManifest.
return /** @type {string} */ (source.source());
}
// JS-export path — resolve `[webpack/auto]` inline; chunk-URL sentinels
// stay for `HtmlModulesPlugin`'s `JavascriptModulesPlugin.render` tap.
let content = /** @type {string} */ (source.source());
content = content.split(CssUrlDependency.PUBLIC_PATH_AUTO).join(undoPath);
return content;
}
/**
* Generates generated code for this runtime module.
* @param {NormalModule} module module for which the code should be generated
* @param {GenerateContext} generateContext context for generate
* @returns {Source | null} generated code
*/
generate(module, generateContext) {
const originalSource = module.originalSource();
if (!originalSource) {
return new RawSource("");
}
if (generateContext.type === HTML_TYPE) {
// Preserve `[webpack/auto]`; renderManifest resolves it once `.html` filename is known.
return new RawSource(
this._renderHtml(module, generateContext, undefined)
);
}
// JS export: resolve `[webpack/auto]` to root-relative URLs.
const generated = this._renderHtml(module, generateContext, "");
/** @type {string} */
let sourceContent;
if (generateContext.concatenationScope) {
generateContext.concatenationScope.registerNamespaceExport(
ConcatenationScope.NAMESPACE_OBJECT_EXPORT
);
sourceContent = `${generateContext.runtimeTemplate.renderConst()} ${
ConcatenationScope.NAMESPACE_OBJECT_EXPORT
} = ${JSON.stringify(generated)};`;
} else {
generateContext.runtimeRequirements.add(RuntimeGlobals.module);
sourceContent = `${module.moduleArgument}.exports = ${JSON.stringify(
generated
)};`;
}
return new RawSource(sourceContent);
}
/**
* Generates fallback output for the provided error condition.
* @param {Error} error the error
* @param {NormalModule} module module for which the code should be generated
* @param {GenerateContext} generateContext context for generate
* @returns {Source | null} generated code
*/
generateError(error, module, generateContext) {
if (generateContext.type === HTML_TYPE) {
// Strip `<`, `>`, `--` runs from `error.message` so it can't escape the comment.
const safe = String(error.message)
.replace(/[<>]/g, "")
.replace(/-{2,}/g, (m) => `${"-".repeat(m.length - 1)} `);
return new RawSource(`<!-- webpack error: ${safe} -->`);
}
return new RawSource(`throw new Error(${JSON.stringify(error.message)});`);
}
/**
* Updates the hash with the data contributed by this instance.
* @param {Hash} hash hash that will be modified
* @param {UpdateHashContext} updateHashContext context for updating hash
*/
updateHash(hash, updateHashContext) {
hash.update("html");
// Hash effective extraction state — source-type set changes when this flips.
if (this._shouldExtract(updateHashContext.module)) {
hash.update("extract");
}
}
}
module.exports = HtmlGenerator;

492
node_modules/webpack/lib/html/HtmlModulesPlugin.js generated vendored Normal file
View File

@@ -0,0 +1,492 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const { RawSource } = require("webpack-sources");
const EntryPlugin = require("../EntryPlugin");
const HotUpdateChunk = require("../HotUpdateChunk");
const { HTML_TYPE } = require("../ModuleSourceTypeConstants");
const { HTML_MODULE_TYPE } = require("../ModuleTypeConstants");
const NormalModule = require("../NormalModule");
const ConstDependency = require("../dependencies/ConstDependency");
const HtmlInlineScriptDependency = require("../dependencies/HtmlInlineScriptDependency");
const HtmlInlineStyleDependency = require("../dependencies/HtmlInlineStyleDependency");
const HtmlScriptSrcDependency = require("../dependencies/HtmlScriptSrcDependency");
const HtmlSourceDependency = require("../dependencies/HtmlSourceDependency");
const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
const { compareModulesByFullName } = require("../util/comparators");
const removeBOM = require("../util/removeBOM");
const HtmlGenerator = require("./HtmlGenerator");
const HtmlParser = require("./HtmlParser");
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {{ request: string, entryName: string, kind: "classic" | "esm-script" | "modulepreload" | "stylesheet" }} EntryScriptInfo */
const PLUGIN_NAME = "HtmlModulesPlugin";
/**
* @param {string} name definition name in `schemas/WebpackOptions.json`
* @returns {EXPECTED_OBJECT} a schema referencing `#/definitions/<name>`
*/
const getSchema = (name) => {
const { definitions } = require("../../schemas/WebpackOptions.json");
return {
definitions,
oneOf: [{ $ref: `#/definitions/${name}` }]
};
};
const generatorValidationOptions = {
name: "Html Modules Plugin",
baseDataPath: "generator"
};
class HtmlModulesPlugin {
/**
* `output.hashFunction`/`hashSalt`/`hashDigest`/`hashDigestLength`
* digest of `content`, with `nonNumericOnlyHash` applied — webpack's
* standard `[contenthash]` recipe.
* @param {string | Buffer} content content to hash
* @param {import("../../declarations/WebpackOptions").Output} outputOptions output options
* @returns {string} content hash
*/
static computeContentHash(content, outputOptions) {
const createHash = require("../util/createHash");
const nonNumericOnlyHash = require("../util/nonNumericOnlyHash");
const hash = createHash(
/** @type {import("../../declarations/WebpackOptions").HashFunction} */
(outputOptions.hashFunction)
);
if (outputOptions.hashSalt) hash.update(outputOptions.hashSalt);
hash.update(content);
return nonNumericOnlyHash(
/** @type {string} */ (
hash.digest(/** @type {string} */ (outputOptions.hashDigest))
),
/** @type {number} */ (outputOptions.hashDigestLength)
);
}
/**
* Applies the plugin by registering its hooks on the compiler.
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
// Per-chunk `RawSource` reused across builds when bytes are unchanged:
// keeping identity stable avoids invalidating `RealContentHashPlugin|analyse`.
/** @type {Map<string, { content: string, source: import("webpack-sources").RawSource }>} */
const sentinelResolvedSourceCache = new Map();
// `<script src>` and `<link rel="modulepreload">` references collected
// by HtmlParser become real compilation entries here. The classic
// and esm-script groups are chained via a leader-only dependOn so
// they share a runtime — the first entry of the group owns it and
// every subsequent entry sets `dependOn: [leader]`. Modulepreload
// entries are emitted as independent entries (no dependOn) so they
// can never be imported as a runtime leader by a later script —
// that's what keeps the "preload but don't execute" contract of
// `<link rel="modulepreload">` intact.
/** @type {WeakMap<import("../Compilation"), Set<string>>} */
const stylesheetEntriesPerCompilation = new WeakMap();
compiler.hooks.finishMake.tapAsync(PLUGIN_NAME, (compilation, callback) => {
/** @type {Promise<void>[]} */
const promises = [];
/** @type {Set<string>} */
const stylesheetEntries = new Set();
stylesheetEntriesPerCompilation.set(compilation, stylesheetEntries);
for (const module of compilation.modules) {
if (module.type !== HTML_MODULE_TYPE) continue;
const buildInfo = module.buildInfo;
const htmlEntryScripts =
buildInfo &&
/** @type {Record<string, EntryScriptInfo[]> | undefined} */
(buildInfo.htmlEntryScripts);
if (!htmlEntryScripts) continue;
const context = /** @type {string} */ (module.context);
for (const [groupKind, group] of Object.entries(htmlEntryScripts)) {
// Only the script chains (`classic`, `esm-script`) need a
// shared runtime via leader-only `dependOn` — the others
// either preload without executing (`modulepreload`) or
// produce CSS chunks (`stylesheet`) which have no runtime
// to share. CSS entries must NOT chain into a JS leader
// either, because the resulting chunk would mix a CSS
// stylesheet with a JS runtime.
const isChainGroup =
groupKind !== "modulepreload" && groupKind !== "stylesheet";
/** @type {string | undefined} */
let leaderName;
for (const entry of group) {
const dependOn =
isChainGroup && leaderName !== undefined
? [leaderName]
: undefined;
if (isChainGroup && leaderName === undefined) {
leaderName = entry.entryName;
}
if (groupKind === "stylesheet") {
stylesheetEntries.add(entry.entryName);
}
promises.push(
new Promise((resolve, reject) => {
compilation.addEntry(
context,
EntryPlugin.createDependency(entry.request, {
name: entry.entryName
}),
{
name: entry.entryName,
// Each script src / modulepreload entry gets its own
// filename derived from the synthetic entry name so it
// doesn't collide with the user's `output.filename`.
// For CSS entries the JS `filename` is irrelevant (no
// `.js` is emitted) — the CSS file's name is set on the
// chunk via `cssFilenameTemplate` in `afterChunks` below.
filename:
compilation.outputOptions.chunkFilename || "[name].js",
dependOn
},
(err) => {
if (err) reject(err);
else resolve();
}
);
})
);
}
}
}
Promise.all(promises).then(
() => callback(),
(err) => callback(err)
);
});
compiler.hooks.compilation.tap(
PLUGIN_NAME,
(compilation, { normalModuleFactory }) => {
// CSS entries created by `<link rel="stylesheet">` in HTML need
// their `.css` filename set via `chunk.cssFilenameTemplate`
// (the field `CssModulesPlugin.getChunkFilenameTemplate` reads).
// Compilation only flows `options.filename` to `chunk.filenameTemplate`,
// which controls JS emit — there's no entry-level `cssFilename`.
// Set it ourselves after chunks are created so each stylesheet
// entry emits to a distinct file derived from `output.cssFilename`
// (or `output.cssChunkFilename` for non-initial CSS chunks).
compilation.hooks.afterChunks.tap(PLUGIN_NAME, () => {
const stylesheetEntries =
stylesheetEntriesPerCompilation.get(compilation);
if (!stylesheetEntries || stylesheetEntries.size === 0) return;
for (const entryName of stylesheetEntries) {
const entrypoint = compilation.entrypoints.get(entryName);
if (!entrypoint) continue;
const chunk = entrypoint.getEntrypointChunk();
if (!chunk) continue;
// Each html-derived stylesheet entry uses the
// `cssChunkFilename` template — even though the entry
// chunk technically `canBeInitial()`, we deliberately
// avoid `cssFilename` here because that template often
// has no per-entry placeholder (it's derived from
// `output.filename`, which can be a literal like
// `bundle0.js`), and multiple `<link rel="stylesheet">`
// tags would then collide on the same emitted `.css`
// file. `cssChunkFilename` is derived from
// `output.chunkFilename` which webpack auto-extends
// with `[id].` when needed, guaranteeing uniqueness.
chunk.cssFilenameTemplate =
compilation.outputOptions.cssChunkFilename;
}
});
compilation.dependencyFactories.set(
HtmlSourceDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
HtmlSourceDependency,
new HtmlSourceDependency.Template()
);
compilation.dependencyFactories.set(
HtmlScriptSrcDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
HtmlScriptSrcDependency,
new HtmlScriptSrcDependency.Template()
);
// Inline `<script>` content is bundled as its own entry — the
// same pipeline that handles `<script src>` — via a
// `data:text/javascript,...` request. The dependency
// template rewrites the original tag to `<script src=…>`.
compilation.dependencyFactories.set(
HtmlInlineScriptDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
HtmlInlineScriptDependency,
new HtmlInlineScriptDependency.Template()
);
// Inline `<style>` content is routed through the CSS pipeline
// as a `data:text/css` module. The dependency template reads
// the processed CSS text from the CSS module's code
// generation data (`css-text` channel set by CssGenerator
// when `exportType` is `"text"`).
compilation.dependencyFactories.set(
HtmlInlineStyleDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
HtmlInlineStyleDependency,
new HtmlInlineStyleDependency.Template()
);
compilation.dependencyTemplates.set(
StaticExportsDependency,
new StaticExportsDependency.Template()
);
// `ConstDependency` is used by HtmlParser to insert
// ` type="module"` into the rewritten <script> tag when
// `output.module` is on. Register its template so the HTML
// generator runs the insertion.
compilation.dependencyTemplates.set(
ConstDependency,
new ConstDependency.Template()
);
const cssEnabled = Boolean(
compiler.options.experiments && compiler.options.experiments.css
);
normalModuleFactory.hooks.createParser
.for(HTML_MODULE_TYPE)
.tap(
PLUGIN_NAME,
() =>
new HtmlParser(
compilation.outputOptions.hashFunction,
compiler.context,
compilation.outputOptions.module,
cssEnabled
)
);
normalModuleFactory.hooks.createGenerator
.for(HTML_MODULE_TYPE)
.tap(PLUGIN_NAME, (generatorOptions) => {
compiler.validate(
() => getSchema("HtmlGeneratorOptions"),
generatorOptions,
generatorValidationOptions,
(options) =>
require("../../schemas/plugins/HtmlGeneratorOptions.check")(
options
)
);
return new HtmlGenerator(generatorOptions, compilation.moduleGraph);
});
NormalModule.getCompilationHooks(compilation).processResult.tap(
PLUGIN_NAME,
(result, module) => {
if (module.type === HTML_MODULE_TYPE) {
const [source, ...rest] = result;
return [removeBOM(source), ...rest];
}
return result;
}
);
// Emit extracted `.html` files for any HTML module that opted
// into extraction. The opt-in is computed by
// `HtmlGenerator#_shouldExtract`: `module.generator.html.extract:
// true` always extracts, `false` never extracts, and when
// `extract` is unset the generator extracts iff the HTML module
// is a compilation entry — the iteration below picks up only
// modules whose generator reported the `html` source type, so
// that decision is honored implicitly. The HTML content is read
// from the generator's secondary `"html"` source type (see
// HtmlGenerator#generate). The filename template comes from
// `output.htmlFilename` (initial chunks) or
// `output.htmlChunkFilename` (non-initial chunks), mirroring
// the CSS pipeline. Path data follows the asset-module pattern —
// `module` + a relative source `filename`, with `chunk`
// intentionally omitted so `[name]` resolves to the HTML
// source's basename (e.g. `page` for `./page.html`) rather
// than the importing chunk's name (e.g. `main`). A per-module
// content hash is computed from the rewritten HTML so the
// template's `[contenthash]` placeholder works; the
// compilation hash is also forwarded so `[fullhash]` /
// `[hash]` work in user-supplied templates.
const {
getUndoPath,
makePathsRelative
} = require("../util/identifier");
const CssUrlDependency = require("../dependencies/CssUrlDependency");
const autoPlaceholder = CssUrlDependency.PUBLIC_PATH_AUTO;
compilation.hooks.renderManifest.tap(
PLUGIN_NAME,
(result, { chunk, codeGenerationResults, hash: compilationHash }) => {
// HMR's `HotUpdateChunk`s flow through the same hook
// but aren't real output chunks — extracting `.html`
// for them would create stray hot-update HTML files.
// `CssModulesPlugin` early-returns for the same reason.
if (chunk instanceof HotUpdateChunk) return result;
const { chunkGraph } = compilation;
const modules =
chunkGraph.getOrderedChunkModulesIterableBySourceType(
chunk,
HTML_TYPE,
compareModulesByFullName(compilation.compiler)
);
if (!modules) return result;
const outputOptions = compilation.outputOptions;
for (const module of modules) {
const normalModule = /** @type {NormalModule} */ (module);
const codeGenResult = codeGenerationResults.get(
module,
chunk.runtime
);
const placeholderSource = codeGenResult.sources.get(HTML_TYPE);
if (!placeholderSource) continue;
const filenameTemplate = chunk.canBeInitial()
? outputOptions.htmlFilename
: outputOptions.htmlChunkFilename;
const sourceFilename = makePathsRelative(
compiler.context,
/** @type {string} */
(normalModule.getResource() || normalModule.resource),
compiler.root
).replace(/^\.\//, "");
const placeholderContent = /** @type {string} */ (
placeholderSource.source()
);
// Resolve sentinels *before* hashing so the HTML's `[contenthash]`
// invalidates with the referenced chunks' filenames.
const resolvedContent = HtmlGenerator.resolveChunkUrlSentinels(
placeholderContent,
compilation
);
const contentHash = HtmlModulesPlugin.computeContentHash(
resolvedContent,
outputOptions
);
const { path: filename, info } = compilation.getPathWithInfo(
/** @type {import("../TemplatedPathPlugin").TemplatePath} */
(filenameTemplate),
{
module,
runtime: chunk.runtime,
chunkGraph,
contentHash,
contentHashType: HTML_TYPE,
filename: sourceFilename,
hash: compilationHash
}
);
// Resolve any remaining `[webpack/auto]` placeholders to
// an undo path computed from the emitted HTML's location.
// Without this, an `output.htmlFilename` that emits into
// a subdirectory (e.g. `pages/[name].html`) would leave
// asset URLs like `image.png` and chunk URLs like
// `main.js` root-relative, so the browser would resolve
// them under the HTML's directory instead of the
// `output.path` root.
const undoPath = getUndoPath(
filename,
/** @type {string} */ (outputOptions.path),
false
);
const finalContent = resolvedContent
.split(autoPlaceholder)
.join(undoPath);
const finalSource = new RawSource(finalContent);
// The same HTML module can land in multiple chunks
// with different `output.htmlFilename` /
// `output.htmlChunkFilename` shapes, which means
// different `undoPath`s and therefore different
// final content for the same module id. Include
// the emitted filename in the asset cache key and
// the post-undo-path content in the hash, so the
// asset cache can't reuse one variant's bytes at
// another variant's URL.
const finalContentHash = HtmlModulesPlugin.computeContentHash(
finalContent,
outputOptions
);
result.push({
render: () => finalSource,
filename,
info,
auxiliary: true,
identifier: `htmlModule${chunkGraph.getModuleId(
module
)}|${filename}`,
hash: finalContentHash
});
}
return result;
}
);
// Resolve sentinels at JS chunk render time so later passes
// (SourceMapDevToolPlugin, size optimizers, RealContentHash) see resolved bytes.
const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin");
const jsHooks =
JavascriptModulesPlugin.getCompilationHooks(compilation);
jsHooks.render.tap(PLUGIN_NAME, (source, renderContext) => {
const raw = source.source();
if (typeof raw !== "string") return source;
if (!raw.includes("__WEBPACK_HTML_CHUNK_URL__")) return source;
const resolved = HtmlGenerator.resolveChunkUrlSentinels(
raw,
compilation
)
.split(autoPlaceholder)
.join("");
if (resolved === raw) return source;
const chunkId = String(renderContext.chunk.id);
const prior = sentinelResolvedSourceCache.get(chunkId);
if (prior !== undefined && prior.content === resolved) {
return prior.source;
}
const newSource = new RawSource(resolved);
sentinelResolvedSourceCache.set(chunkId, {
content: resolved,
source: newSource
});
return newSource;
});
// Prune cache entries for chunks no longer in the graph so a
// long watch session can't accumulate stale entries.
compilation.hooks.afterSeal.tap(PLUGIN_NAME, () => {
if (sentinelResolvedSourceCache.size === 0) return;
const live = new Set();
for (const chunk of compilation.chunks) {
live.add(String(chunk.id));
}
for (const id of sentinelResolvedSourceCache.keys()) {
if (!live.has(id)) sentinelResolvedSourceCache.delete(id);
}
});
}
);
}
}
module.exports = HtmlModulesPlugin;

1489
node_modules/webpack/lib/html/HtmlParser.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

3249
node_modules/webpack/lib/html/walkHtmlTokens.js generated vendored Normal file

File diff suppressed because one or more lines are too long