Skip to content

Built-in HTML minifier corrupts copy-webpack-plugin .html assets containing {% %} template statements #22013

Closed

Description

@davidding

Have you used AI?

Yes

Which part of webpack is affected?

html

Bug Description

webpack 5.110.0 added a built-in HTML minifier that is on by default in mode: 'production'. It reserializes every .html asset, including files that copy-webpack-plugin passes through unchanged. When such a file contains {% ... %} server-side template statements (the statement delimiter of the Django/Jinja family: Jinja2, Django, Twig, Liquid, Nunjucks, HubSpot HubL), the minifier drops a %} delimiter and emits invalid template markup from valid input.

No HTML loader, html-webpack-plugin, or explicitly configured minimizer is involved. Just mode: 'production' and copy-webpack-plugin copying a .html file.

%} tokenizes as a valid HTML attribute name (the attribute-name state accepts every character except whitespace, /, >, and =), so {% if x %} y {% endif %} produces two %} attribute-name tokens on the same element, and the minifier deduplicates the repeat and loses one %}.

Link to Minimal Reproduction and steps to reproduce

https://github.com/davidding/webpack-5110-html-minify-repro

  • npm install
  • npm run verify (runs webpack then prints each src/*.html next to its dist/ output)

Expected Behavior

The minifier does not alter content inside {% ... %} in a way that changes it.

If template-awareness is out of scope, two alternatives would each resolve this:

  1. HTML minification of assets that webpack only copied through (rather than produced from an HTML-emitting module) is opt-in rather than on-by-default.
  2. The 5.110.0 change is documented as breaking, with the migration path and the workarounds called out in release notes.

Actual Behavior

The %} delimiter is dropped, producing invalid markup:

  == src/corrupt-conditional-attribute.html ==
    in : <input type="text"{% if required %} required{% endif %}>
    out: <input type=text {% if required %} required{% endif>

  == src/corrupt-space-inside-conditional.html ==
    in : <div class="btn{% if active %} btn-active{% endif %}"></div>
    out: <div class="btn{% if active %} btn-active{% endif"></div>

  == src/survive-space-outside-conditional.html ==   (control: unchanged)
    in : <div class="btn {% if active %}btn-active{% endif %}"></div>
    out: <div class="btn {% if active %}btn-active{% endif %}"></div>

The type="text" to type=text quote removal is valid minification and is not the problem. The problem is the dropped %}.

Two distinct mechanisms drop the repeated %}:

Environment

System:
  OS: macOS 26.6.2
  CPU: (12) arm64 Apple M3 Pro
  Memory: 18.00 GB
Binaries:
  Node: 24.19.0
  npm: 11.17.0
Packages:
  copy-webpack-plugin: 14.0.0
  webpack: 5.110.3
  webpack-cli: 7.2.3

Is this a regression?

Yes (please specify version below)

Last Working Version

v5.109.2

Additional Context

Byte-identical (correct) output on 5.109.2, the final 5.109.x release, which predates the built-in minifier. Identical corruption on 5.110.0, 5.110.1, 5.110.2, and 5.110.3.

Workarounds (verified against the reproduction on 5.110.3):

  1. optimization: { minimize: { html: false } } disables HTML minification only; JS/CSS minification stays on. Schema option added in 5.110.0.
  2. info: { minimized: true } on the copy-webpack-plugin pattern marks the copied assets already-minimized so the minifier skips them. Version-agnostic (works pre-5.110 too), so it is the right choice for a shared config that must support both.
  3. experiments: { html: false } turns off the built-in HTML pipeline entirely.
  4. Pin webpack < 5.110. Stopgap only.

Activity

  1. added theissue type on Sep 8, 2026
  2. added
    area: configOptions, defaults, validation (lib/config, schemas/)
    area: htmlExperimental HTML support (lib/html)
    regressionWorked in a previous release; pair with the Affected version field
    on Sep 8, 2026
  3. alexander-akait commented on Sep 8, 2026

    @alexander-akait
    Member

    That is expected, it is not a part of html syntax, you should exclude them

  4. alexander-akait commented on Sep 8, 2026

    @alexander-akait
    Member

    But take me time to think how we can avoid such problems

  5. alexander-akait commented on Sep 8, 2026

    @alexander-akait
    Member

    Fixed in the main, but it is still not html so some other parts still can be aerialized with problems, anyway feel feee to report them if you faced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: configOptions, defaults, validation (lib/config, schemas/)area: htmlExperimental HTML support (lib/html)regressionWorked in a previous release; pair with the Affected version field

    Type

    Fields

    Priority

    None yet

    Effort

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions