Skip to content

5.109.0 regression: invalid semicolon inserted into sequence expression during harmony-import inlining (breaks Terser) #21532

Description

@dpegasusm

Have you used AI?

Yes

Bug Description

Upgrading from webpack@5.108.4 to 5.109.0 breaks our production build at the Terser minification step. Webpack itself generates syntactically invalid JavaScript (a stray ; inside a comma/sequence expression) when inlining a harmony (ESM) import reference as the non-first element of a SequenceExpression. Webpack never re-parses its own generated output, so the invalid code passes through silently — it only surfaces when a tool that does parse the output (Terser) tries to minify it.

Link to Minimal Reproduction and step to reproduce

I was not able to reduce this to a small standalone repository in the time available. Importing only the single offending source file in isolation (via a trivial webpack config, mode: 'production', default Terser minimizer) built cleanly even on 5.109.0 — whatever triggers the bad code path depends on the surrounding module graph in our real build (a WordPress plugin bundling @arcgis/core via @wordpress/scripts/webpack), likely related to how modules get grouped for concatenation.

What I can provide instead is the exact before/after of webpack's own generated output, captured with optimization.minimize: false at the precise location Terser later failed to parse:

Original library source (@arcgis/core, an ESM dependency, unmodified — a normal comma/sequence expression where n is a locally-aliased import binding):

({densifiedPath:f,distances:d}=G(a,r,P)),n(u),f=m(f,o)

Webpack-generated output on 5.109.0 (pre-minification, i.e. this is what webpack itself emits, before Terser ever sees it):

({densifiedPath:f,distances:d}=G(a,r,P)),;(0,promiseUtils/* throwIfAborted */.Te)(u),f=(0,projectionUtils.project)(f,o)

Webpack inlined the imported reference n(u) into its interop-wrapped form (0, promiseUtils.Te)(u) (the standard "unbind this" wrapper webpack uses when calling an imported function) — but in doing so it also injected a stray ; immediately after the preceding comma, before the wrapped call. expr, ; expr is not valid JavaScript:

new Function("a,b,c","let f; ({d:f}=b), ;(0, c.d)(a), f=1;")
Uncaught SyntaxError: Unexpected token ';'

Steps I used to capture this, against our real project:

  1. npm run build (via wp-scripts build, wrapping webpack) — fails with the Terser error below.
  2. Re-run the same webpack config with optimization.minimize: false to get the pre-minification bundle.
  3. Locate the chunk/line number Terser reported and inspect it — the ,; shape above is present in webpack's own output, with minimize:false, i.e. before Terser touches anything.

Expected Behavior

Webpack's generated (pre-minification) bundle code should always be syntactically valid JavaScript.

Actual Behavior

After upgrading from webpack@5.108.4 to 5.109.0, our production build fails at the Terser minification step with:

ERROR in vendors-....js
Unexpected token: punc (;) [vendors-....js:254,undefined]
at js_error (terser/dist/bundle.min.js:577:11)
at croak (terser/dist/bundle.min.js:1377:9)
at token_error (terser/dist/bundle.min.js:1385:9)
at unexpected (terser/dist/bundle.min.js:1391:9)
at expr_atom (terser/dist/bundle.min.js:2661:25)
at maybe_unary (terser/dist/bundle.min.js:3591:19)
at expr_ops (terser/dist/bundle.min.js:3666:28)
at maybe_conditional (terser/dist/bundle.min.js:3672:20)
at maybe_assign (terser/dist/bundle.min.js:3749:20)
at expression (terser/dist/bundle.min.js:3784:24)
With optimization.minimize: false, the pre-minification generated source at the reported location shows webpack itself emitting invalid JS. The original library source (from @arcgis/core, an ESM dependency) reads:

({densifiedPath:f,distances:d}=G(a,r,P)),n(u),f=m(f,o)
a normal comma (sequence) expression, where n is a locally-aliased import binding. In the 5.109.0-generated bundle, after webpack inlines/interop-wraps the imported reference (n(u) → (0, promiseUtils/* throwIfAborted */.Te)(u), the standard "unbind this" wrapper for calling an imported function), the output becomes:

({densifiedPath:f,distances:d}=G(a,r,P)),;(0,promiseUtils/* throwIfAborted */.Te)(u),f=(0,projectionUtils.project)(f,o)
Note the stray ,; — an extra semicolon injected immediately after the comma, before the wrapped call expression. X, ; Y is not valid JavaScript (confirmed independently: new Function(...) throws Unexpected token ';' on this exact shape), which is why Terser's parser rejects it. Webpack itself never re-parses its own generated output, so this invalid code passes through silently until a tool that does parse it (Terser) chokes on it.

Environment

System:
  OS: macOS 26.5.2
  CPU: (18) arm64 Apple M5 Pro
  Memory: 259.52 MB / 48.00 GB
Binaries:
  Node: 25.9.0 - /opt/homebrew/bin/node
  npm: 11.12.1 - /opt/homebrew/bin/npm
Browsers:
  Chrome: 150.0.7871.184
  Safari: 26.5.2
Packages:
  webpack: 5.109.0
  terser-webpack-plugin: 5.6.1
  terser: 5.49.0
  webpack-cli: 5.1.4

Is this a regression?

Yes (please specify version below)

Last Working Version

v5.108.4

Additional Context

I bisected every intermediate release between 5.95.0 and 5.109.0 against our real build: everything through 5.108.4 passes, 5.109.0 is the first failing version. It's a single-version regression window with no gap.

The most likely cause, based on timing and the exact shape of the affected construct, is #21453 (refactor: derive ASI positions from source instead of acorn's onInsertedSemicolon), merged into 5.109.0. That PR changed how webpack decides where automatic-semicolon-insertion applies, explicitly around comma-continued sequence elements: "isAsiPosition now treats a statement terminated by a real ; or continued by a , (a sequence element) as non-ASI." That's precisely the code path implicated here — a position immediately following a comma inside a SequenceExpression, where webpack is about to splice in a replacement for an imported identifier reference. The new ASI-position logic appears to misclassify that spot as needing a semicolon. I have not verified this against the PR's diff line-by-line, so treat it as a lead rather than a confirmed cause.

Workaround: pinning webpack to 5.108.4 via npm overrides avoids the issue.

Activity

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

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      Sponsor
      SponsoredKunjungi sekarang
      Promo