Skip to content

fix: revert ESM dynamic import, require less >= 4.6.3#588

Open
lemachadoh wants to merge 1 commit into
webpack:mainfrom
lemachadoh:fix/revert-esm-breaking-change
Open

fix: revert ESM dynamic import, require less >= 4.6.3#588
lemachadoh wants to merge 1 commit into
webpack:mainfrom
lemachadoh:fix/revert-esm-breaking-change

Conversation

@lemachadoh
Copy link
Copy Markdown

@lemachadoh lemachadoh commented May 15, 2026

Problem

PR #578 replaced require('less') with await import('less').default to work around an ESM/CJS interop issue introduced in less@4.6.x. This was a breaking change shipped as a patch: any CJS consumer that calls the loader in a Jest environment without --experimental-vm-modules breaks with:

SyntaxError: Cannot use import statement outside a module

Tracked in: #584

Root Cause Fix in less@4.6.3

less@4.6.3 resolves the root cause by shipping a pre-built CJS bundle at dist/less-node.cjs and pointing the "require" exports condition to it:

"exports": {
  "require": "./dist/less-node.cjs",
  "import": "./index.js"
}

No more Proxy, no more ESM-in-CJS problem. less-loader can now safely use require() again.

Changes

  • Revert getLessImplementation from async + await import() back to sync require()
  • Restore test:only script to cross-env NODE_ENV=test jest (remove --experimental-vm-modules)
  • Remove exclude: ["transform-dynamic-import"] from babel config (no longer needed)
  • Update peer dependency: less: "^3.5.0 || ^4.0.0""^3.5.0 || ^4.6.3" (4.x users must be on >= 4.6.3)
  • Update dev dependency: less^4.6.3
  • Preserve sourceMap improvements from fix: compatibility with ECMA modules less version #578 (sourceMapBasepath: "", disableSourcemapAnnotation: true, normalizeSourceMap) — these are correct and independent of the ESM issue
  • Update tests to match less@4.6.3 source map path behavior

Testing

All 110 tests pass.

Use of AI

yes

@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla Bot commented May 15, 2026

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: lemachadoh / name: lemachadoh (af246be)

@alexander-akait
Copy link
Copy Markdown
Member

Please accept CLA

Comment thread package.json Outdated
"peerDependencies": {
"@rspack/core": "0.x || ^1.0.0 || ^2.0.0-0",
"less": "^3.5.0 || ^4.0.0",
"less": "^3.5.0 || ^4.6.3",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this change, it is a breaking change

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the concern, but #578 already introduced an undeclared breaking change. It shipped as a patch (12.3.1 -> 12.3.2) but broke any CJS consumer using Jest without --experimental-vm-modules. That's what this PR is fixing.

The peer dep update is necessary because less@4.0.0–4.6.2 don't ship a real CJS bundle. require('less') on those versions returns a Proxy that breaks at runtime. Without the constraint, reverting to require() would silently break users on less@4.6.0–4.6.2.

Would it make sense to release this as a major (13.0.0) to properly declare the breaking change? That would acknowledge that 12.3.2 was a breaking patch and restore CJS compatibility with the correct constraint.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will break developers with old version of less, we should not touch this field at all

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They publish this fix as a patch, so we should do the same, because it is a bug on their side

@alexander-akait
Copy link
Copy Markdown
Member

Also please accept CLA

@lemachadoh
Copy link
Copy Markdown
Author

Can you wait? I'm trying to accept it. For some reason it was logged with another account and not this one.

@lemachadoh lemachadoh force-pushed the fix/revert-esm-breaking-change branch from e922fa6 to af246be Compare May 15, 2026 15:42
@alexander-akait
Copy link
Copy Markdown
Member

@lemachadoh because your email in commits is not the same as you accept in CLA, change it

@alexander-akait
Copy link
Copy Markdown
Member

alexander-akait commented May 15, 2026

This is due you are using AI, by default they generate no-reply email, not your

@lemachadoh
Copy link
Copy Markdown
Author

hey @alexander-akait everything seems to be fine with the CLA

less@4.6.3 ships a pre-built CJS bundle (dist/less-node.cjs) and maps
the "require" exports condition to it, resolving the ESM/CJS interop
issue that prompted the dynamic import workaround in webpack#578.

Revert getLessImplementation back to synchronous require() and restore
the standard test:only script. Remove peer dependency constraint added
in previous commit as it would break users on less@4.0.0-4.6.2.

Source map improvements introduced in webpack#578 (sourceMapBasepath,
disableSourcemapAnnotation, normalizeSourceMap) are preserved.
@lemachadoh lemachadoh force-pushed the fix/revert-esm-breaking-change branch from 54fd554 to 65be0b9 Compare May 15, 2026 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants