Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: webpack/webpack
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v5.107.1
Choose a base ref
...
head repository: webpack/webpack
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v5.107.2
Choose a head ref
  • 19 commits
  • 125 files changed
  • 5 contributors

Commits on May 21, 2026

  1. Configuration menu
    Copy the full SHA
    883de7a View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    9e8717e View commit details
    Browse the repository at this point in the history
  3. test: cover all hash placeholders across js/css/html/asset outputs wi…

    …th and without realContentHash (#21009)
    alexander-akait authored May 21, 2026
    Configuration menu
    Copy the full SHA
    b3893ec View commit details
    Browse the repository at this point in the history

Commits on May 22, 2026

  1. Configuration menu
    Copy the full SHA
    c755747 View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    7dd1824 View commit details
    Browse the repository at this point in the history
  3. Configuration menu
    Copy the full SHA
    a086147 View commit details
    Browse the repository at this point in the history
  4. Configuration menu
    Copy the full SHA
    7f891b0 View commit details
    Browse the repository at this point in the history
  5. Configuration menu
    Copy the full SHA
    c05beb9 View commit details
    Browse the repository at this point in the history
  6. fix: include referenced module's hash in HTML source/inline-style upd…

    …ateHash (#21018)
    
    * fix: include referenced module's hash in HTML source/inline-style updateHash
    
    `HtmlSourceDependency` (`<img src>`, `<link href>`, `<audio src>`, …) and
    `HtmlInlineStyleDependency` (`<style>`) substitute content sourced from
    the referenced module into the rendered HTML at code-generation time —
    the asset's hashed filename for `HtmlSourceDependency`, the rendered CSS
    text for `HtmlInlineStyleDependency`. Without `updateHash`, the HTML
    module's hash didn't reflect changes to the referenced module, so the
    extracted HTML's `[contenthash]` stayed pinned across incremental
    rebuilds even when the rendered bytes had changed — the same long-term
    caching break `CssUrlDependency.updateHash` was added to prevent for CSS
    `url(...)`.
    
    Fold the referenced module's `buildInfo.hash` into each dependency's
    `updateHash`, matching the `CssUrlDependency` pattern. Adds two watch
    test cases under `test/watchCases/long-term-caching/`:
    `html-contenthash-asset-url` (regression for the fix) and
    `js-contenthash-asset-url` (the analogous case for `new URL(asset,
    import.meta.url)`, which already worked because the asset module's hash
    flows through the JS chunk hash — kept as a regression guard).
    
    * docs: require changeset descriptions to be sentence-case with a trailing period
    
    Recent changesets (`cjs-require-binding-tree-shake.md`, `public-path-fullhash-length-suffix.md`,
    `html-entry-css-chunks-link-tags.md`, `align-html-lexer-script-data.md`, …) all
    open with a capital letter and end with a period — that's what makes them read
    as proper changelog entries when changesets is concatenated into the release
    `CHANGELOG.md`. Document the rule explicitly and update the inline examples
    ("Fix split-chunks cache key collision.", "Add `module.generator.html.extract`
    option.") so the guide matches the convention reviewers already enforce.
    
    Also restyles the changeset added in the previous commit to match.
    
    * refactor: drop redundant `buildInfo` undefined check in HTML updateHash
    
    `module.buildInfo` is populated by `NormalModule#build` (and the equivalent
    hook on other module types) before any code path that calls `updateHash`
    runs — module hashing happens after the build phase. Cast straight to
    `BuildInfo` and keep only the `.hash` check (the field itself is still
    typed as optional on `KnownBuildInfo`). Matches what reviewers were
    flagging on the prior commit.
    
    * fix: recurse into inline-style module updateHash so transitive url() asset changes invalidate the HTML
    
    `HtmlInlineStyleDependency.Template.apply` pulls the rendered CSS text
    out of `codeGenerationResults` and substitutes it into the HTML — the
    rendered text already has every `url(...)` rewritten to its hashed asset
    filename by `CssUrlDependency`. The previous `updateHash` only folded
    the CSS module's `buildInfo.hash`, which captures the CSS *source*. The
    CSS source doesn't change when only the referenced asset's bytes change
    — that change rides on `CssUrlDependency.updateHash`, which contributes
    to the CSS module's *module* hash, not its `buildInfo.hash`. So the
    HTML's `[contenthash]` stayed pinned even though the rendered HTML
    embedded a new asset filename.
    
    Recurse into the inline-CSS module's full `updateHash` so the same
    asset-hash chain that already invalidates a standalone CSS chunk's
    contenthash now also invalidates the host HTML's.
    
    Adds `test/watchCases/long-term-caching/html-contenthash-inline-style-url/`,
    which fails before the fix (HTML filename stayed `page.36e6bef5…html`
    across the asset swap) and passes after.
    
    * fix: defer chunk-URL substitution in extracted HTML until chunk hashes are computed
    
    `HtmlInlineScriptDependency` and `HtmlScriptSrcDependency` (the new
    experimental HTML pipeline) used to call `compilation.getPath(chunk
    filenameTemplate, …)` from their `Template#apply` — i.e. during
    `Compilation#codeGeneration()`. That runs before `createHash()`, so
    `chunk.hash` and `chunk.contentHash[type]` are still `null`. Any
    `output.chunkFilename` (or `output.filename`) containing
    `[contenthash]` / `[chunkhash]` / `[fullhash]` would throw "Path
    variable [contenthash] not implemented in this context" from
    `TemplatedPathPlugin`, breaking every HTML compile that wanted hashed
    JS/CSS filenames. Even when the template happened to resolve, the
    HTML module's own `[contenthash]` was computed from
    placeholder-substituted bytes — so changing only an inline-script's
    transitive dep flipped the embedded chunk URL but left the HTML's
    `[contenthash]` pinned.
    
    Defer the substitution instead: dep templates now emit a sentinel
    (`__WEBPACK_HTML_CHUNK_URL__<hexChunkId>__<contentHashType>__END__`)
    via `makeHtmlChunkUrlSentinel` from a new `lib/html/htmlChunkUrl.js`
    helper, and `HtmlModulesPlugin#renderManifest` swaps every sentinel
    for `${PUBLIC_PATH_AUTO}<chunkFilename>` *before* hashing the HTML
    output — by that point `createHash()` has populated every chunk's
    `chunk.contentHash[type]`/`chunk.hash`/`compilation.hash`, so the
    chunk filenames' placeholders all resolve. Hashing the resolved
    content (rather than the raw placeholder source) is what makes the
    HTML's `[contenthash]` invalidate when a referenced chunk's filename
    changes. `HtmlGenerator#_renderHtml`'s JS-export path resolves
    sentinels inline too via the same helper; sentinels whose templates
    can't be resolved yet (e.g. an unbuildable `[contenthash]` placeholder
    at code-gen time) are left in place rather than thrown — `extract:
    true` (the HTML output path) is the one that supports dynamic
    filenames, and the JS export of the HTML string carries the
    restriction that previously surfaced as a compile-time error.
    
    Adds `test/watchCases/long-term-caching/html-contenthash-inline-script/`,
    which fails before the fix (compile errors with `[contenthash]` in
    `chunkFilename`) and after step 1 verifies the HTML invalidates when
    the inline-script's transitive dep flips.
    
    * refactor(html): extract duplicated `[contenthash]` recipe into HtmlModulesPlugin.computeContentHash
    
    `renderManifest` hashed HTML bytes twice with identical boilerplate —
    once for the `[contenthash]` substituted into `output.htmlFilename` and
    once for the final asset cache key — each call re-implementing the
    `createHash(hashFunction)` + `hashSalt` + `digest(hashDigest)` +
    `nonNumericOnlyHash(_, hashDigestLength)` recipe. Pull both call sites
    into a single static method on `HtmlModulesPlugin` so the recipe can't
    drift between them, and so anyone reaching for "the HTML pipeline's
    `[contenthash]` recipe" has a named entry point.
    
    No behaviour change; the previously inlined `createHash` /
    `nonNumericOnlyHash` requires are now inside the static method.
    
    * refactor(html): fold chunk-URL sentinel helpers into HtmlGenerator as static methods
    
    `lib/html/htmlChunkUrl.js` was a single-file module exporting the
    `makeHtmlChunkUrlSentinel` / `resolveHtmlChunkUrlSentinels` pair created
    in the previous commit. Inline them onto `HtmlGenerator` as
    `HtmlGenerator.makeChunkUrlSentinel` and `HtmlGenerator.resolveChunkUrlSentinels`
    — that's the class responsible for emitting both sides of the
    substitution (`_renderHtml` writes sentinels via dep templates and
    resolves them on the JS-export path), so it's the natural home for the
    sentinel format. `HtmlGenerator` doesn't import the HTML dependencies,
    so the two dep templates (`HtmlInlineScriptDependency`,
    `HtmlScriptSrcDependency`) can require it directly without introducing
    a circular import. `HtmlModulesPlugin` already imports `HtmlGenerator`
    and reaches the resolver through the same static method.
    
    No behaviour change; just removes the standalone helper file.
    
    * refactor(html): drop unnecessary chunk.id null-checks in chunk-URL sentinel helpers
    
    Both `HtmlGenerator.makeChunkUrlSentinel` (called from dep templates
    during `Compilation#codeGeneration()`) and
    `HtmlGenerator.resolveChunkUrlSentinels` (called from `_renderHtml`'s
    JS-export path and from `HtmlModulesPlugin#renderManifest`) run after
    `Compilation#seal`'s `optimizeChunkIds` hook, which is what
    `chunkIds`/`NamedChunkIdsPlugin`/`DeterministicChunkIdsPlugin` use to
    populate every chunk's `.id`. By the time these helpers run, every
    chunk has a non-null id, so the defensive `chunk.id == null` branches
    were dead code.
    
    * docs: require code comments to stay short and informative
    
    Adds a REQUIRED "Code comments" section to `AGENTS.md`: comments inside
    `lib/`, `hot/`, `tooling/`, `test/` must be one or at most two short
    lines and every line must add information not obvious from the code
    (invariant, ordering constraint, pinned-bug workaround, higher-level
    concept name). No multi-paragraph essays, no restating the next line,
    no diff narration, no PR-body restatements, no task-framing quotes.
    JSDoc on exported symbols is exempt because it's the type contract.
    
    Also trims the verbose comments added in this branch (chunk-URL
    sentinel docs on `HtmlGenerator`, the dep-template apply blocks, the
    `HtmlInlineStyleDependency` / `HtmlSourceDependency` `updateHash`
    explanations, `HtmlModulesPlugin.computeContentHash` JSDoc, and the
    renderManifest "resolve before hashing" comment) to fit the rule —
    105 lines removed, no behaviour change. Pre-existing comments in
    other functions are left for their respective authors to revisit.
    
    * fix: address Copilot review on PR #21018
    
    - `HtmlModulesPlugin.computeContentHash` passes `outputOptions.hashFunction`
      through to `createHash` typed as `HashFunction` instead of casting to
      `string`, so the constructor-function form of `output.hashFunction` keeps
      working.
    - Shorten the inline-script-chunk-url-sentinel changeset to fit the
      ≤80-char/no-commas guidance the previous commit added to AGENTS.md.
    - Trim the test-fixture explanatory comments Copilot flagged in
      `js-contenthash-asset-url/{0,2}`, `html-contenthash-asset-url/{0,2}`,
      `html-contenthash-inline-style-url/{0,2}`, and
      `html-contenthash-inline-script/{0/page.html,1/index.js}` — the test
      names already convey intent. No assertion logic changed.
    
    * fix: resolve chunk-URL sentinels in JS-export bundles too via processAssets
    
    The JS-export path in `HtmlGenerator._renderHtml` was leaving unresolved
    `__WEBPACK_HTML_CHUNK_URL__…__END__` sentinels in `module.exports = "<html>"`
    when chunk filenames carried `[contenthash]` / `[chunkhash]` /
    `[fullhash]` — chunk hashes don't exist at code-gen time, so the inline
    `compilation.getPath` fell into the catch and left the sentinel. Consumers
    doing `require("./page.html")` then saw the sentinel string at runtime.
    
    Drop the JS-export path's inline sentinel resolution entirely (it always
    leaves sentinels now) and add a global `processAssets` pass in
    `HtmlModulesPlugin` at `PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE` that sweeps
    every asset, resolves any surviving sentinels via
    `HtmlGenerator.resolveChunkUrlSentinels`, and collapses the freshly-emitted
    `[webpack/auto]` placeholders to `""` (root-relative — matching the prior
    JS-export behaviour). Stage choice matters: it runs after `createHash()`
    has populated every `chunk.hash` / `chunk.contentHash[type]`, so chunk
    filename templates resolve, and before `PROCESS_ASSETS_STAGE_OPTIMIZE_HASH`
    where `realContentHash` rehashes affected chunk filenames against the
    resolved bytes.
    
    Adds a step-0 assertion in `html-contenthash-inline-script/0/index.js`
    that reads `main.<hash>.js` from disk and verifies no
    `__WEBPACK_HTML_CHUNK_URL__<hex>__<type>__END__` survives into the JS
    bundle's HTML export.
    
    * fix: reuse sentinel-resolved asset source across compilations
    
    The new `processAssets` sweep was minting a fresh `RawSource` on every
    compilation, even when the resolved bytes were byte-identical to the
    previous run. `getLazyHashedEtag`'s WeakMap is keyed by source identity,
    and `MemoryCachePlugin` / `PackFileCacheStrategy` compare etags with
    reference equality, so a new source object meant a fresh
    `LazyHashedEtag` → fresh `MergedEtag` → cache miss → `set()` on
    `RealContentHashPlugin|analyse|<asset>` → "Pack got invalid because of
    write to" infra log. `ConfigCacheTestCases` treats that log as a failure
    on the 2nd (warm) run, so every HTML test with an inline script chunk
    regressed.
    
    Cache the resolved `RawSource` per asset name in a plugin-scoped Map
    and reuse it whenever the freshly-computed `resolved` string matches
    the prior content. Same bytes ⇒ same source object ⇒ same etag ⇒ the
    analyse cache hits and no infrastructure log fires.
    
    * refactor: address Copilot perf + comment-length feedback
    
    - `HtmlGenerator.resolveChunkUrlSentinels` now caches the per-compilation
      `chunksById` map in a module-level `WeakMap` instead of rebuilding it
      on every call (was O(assets × chunks) with the new `processAssets`
      sweep, now O(chunks) per compilation).
    - `HtmlModulesPlugin`'s `processAssets` pass uses `Buffer#indexOf` on
      Buffer-backed sources and skips them when the ASCII sentinel marker
      isn't present, avoiding a full UTF-8 decode of large binary blobs.
    - Trim multi-line explanatory comments down to ≤2 lines per the
      REQUIRED `AGENTS.md` rule in `lib/` and `test/`.
    - Shorten the changeset description to ≤80 chars.
    
    * test: drop unused step-2 `tag` in js-contenthash-asset-url
    
    * refactor: resolve sentinels at JS chunk render time, not processAssets
    
    `processAssets` is too late: any plugin that reads the chunk source
    between `createChunkAssets` and the `OPTIMIZE_INLINE` stage —
    `SourceMapDevToolPlugin` (stage 500), size-optimize plugins (stage 400),
    banner injection, etc. — would see unresolved
    `__WEBPACK_HTML_CHUNK_URL__…__END__` placeholders embedded in the JS
    module's export string.
    
    Tap `JavascriptModulesPlugin.getCompilationHooks(compilation).render`
    instead — fires for every JS chunk after `createHash` populates the
    content hashes (so `getPath` resolves `[contenthash]` / `[chunkhash]`
    / `[fullhash]`) and *during* chunk asset assembly, so the source every
    later pass reads is already sentinel-free. The per-chunk RawSource
    identity cache stays in place so warm rebuilds with byte-identical
    output keep the same source object and don't invalidate
    `RealContentHashPlugin|analyse`.
    
    * refactor: prune sentinel-resolved source cache in afterSeal
    
    Address Copilot review: in long-running watch sessions, chunks that
    get removed from the graph (e.g. a dynamic import the user just
    deleted) would leave their entries behind in the per-chunk RawSource
    cache forever. Tap `compilation.hooks.afterSeal` to drop entries for
    chunk IDs no longer in `compilation.chunks`. Also shorten the render-
    tap comment to two lines per the AGENTS.md rule.
    
    * refactor: trim two more multi-line comments to two lines
    
    Address Copilot review — shorten the `sentinelResolvedSourceCache`
    declaration comment (4 lines → 2) and the `afterSeal` prune comment
    (3 lines → 2) per the AGENTS.md "Code comments" REQUIRED rule.
    
    * docs: refresh stale processAssets mention in JS-export comment
    
    The JS-export-path comment in HtmlGenerator still pointed at the old
    `processAssets` resolution pass; that moved to `JavascriptModulesPlugin.render`
    in abaaf97. Update the comment to match.
    alexander-akait authored May 22, 2026
    Configuration menu
    Copy the full SHA
    26e346a View commit details
    Browse the repository at this point in the history
  7. fix(ConcatenatedModule): include runtimeCondition of external infos i…

    …n updateHash (#21023)
    
    * docs(JavascriptParser): correct TODO referring to import phases not assertions
    
    * fix(ConcatenatedModule): include runtimeCondition of external infos in updateHash
    
    * test(ConcatenatedModule): add integration regression test for runtimeCondition hashing
    
    * revert: remove programmatic integration test in favor of configCases-style
    
    * test(ConcatenatedModule): add configCase regression test for runtimeCondition hashing
    
    * test(ConcatenatedModule): drop unit test; configCase uses real UMD external info
    
    * fix(test): cast ConcatenatedModule to bypass private member type checks in test plugin
    
    * fix(ConcatenatedModule): delimit moduleId and runtimeCondition in hash to avoid collisions
    
    * fix(ConcatenatedModule): also hash nonDeferAccess and isDeferred for external infos
    alexander-akait authored May 22, 2026
    Configuration menu
    Copy the full SHA
    75f60f6 View commit details
    Browse the repository at this point in the history

Commits on May 23, 2026

  1. docs(buildChunkGraph): explain why blocksWithNestedBlocks gates the s…

    …kip (#21025)
    
    * docs(buildChunkGraph): explain why blocksWithNestedBlocks gates the skip
    
    The previous `// TODO is this needed?` left the rationale ambiguous.
    Skipping a block disconnects it from its chunk group, which orphans any
    nested block's chunk group from this block's chunk group parent, so the
    check must stay.
    
    * test(chunks): cover the blocksWithNestedBlocks skip guard
    
    Pins down the case where buildChunkGraph's connectChunkGroups would
    otherwise skip a block whose modules are already in the entry chunk.
    Without the `!blocksWithNestedBlocks.has(block)` guard, the outer
    require.ensure's chunk group is left without a parent and gets cleaned
    up together with the nested chunk group, so the inner sync require
    fails at runtime. With the guard the test passes; removing the guard
    makes the test time out waiting for the inner callback.
    alexander-akait authored May 23, 2026
    Configuration menu
    Copy the full SHA
    12cb825 View commit details
    Browse the repository at this point in the history

Commits on May 25, 2026

  1. Configuration menu
    Copy the full SHA
    cc4035b View commit details
    Browse the repository at this point in the history
  2. docs: update examples (#21031)

    Co-authored-by: alexander-akait <4567934+alexander-akait@users.noreply.github.com>
    github-actions[bot] and alexander-akait authored May 25, 2026
    Configuration menu
    Copy the full SHA
    a514897 View commit details
    Browse the repository at this point in the history
  3. Configuration menu
    Copy the full SHA
    c61c649 View commit details
    Browse the repository at this point in the history
  4. Configuration menu
    Copy the full SHA
    78158f0 View commit details
    Browse the repository at this point in the history
  5. Configuration menu
    Copy the full SHA
    c073890 View commit details
    Browse the repository at this point in the history
  6. Configuration menu
    Copy the full SHA
    d6cdebe View commit details
    Browse the repository at this point in the history
  7. Configuration menu
    Copy the full SHA
    c7d8a3a View commit details
    Browse the repository at this point in the history
  8. chore(release): new release (#21019)

    Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
    github-actions[bot] authored May 25, 2026
    Configuration menu
    Copy the full SHA
    cfb24a4 View commit details
    Browse the repository at this point in the history
Loading