fix(rspack): lazy-load @rspack/core in create-compiler to avoid eager ESM resolution - #36476
Conversation
… ESM resolution PR #35682 (feat(rspack): support @rspack/core@2 and @rsbuild/core@2) added lazy `require('@rspack/core')` calls in apply-base-config.ts and apply-web-config.ts to avoid resolving the pure-ESM `@rspack/core@2` entry at module parse time, but missed create-compiler.ts, which still had a top-level value import (`import { rspack, ... } from '@rspack/core'`). That file is imported at the top of the `@nx/rspack:rspack` and `@nx/rspack:dev-server` executors, so simply loading either executor forced Node to resolve `@rspack/core` immediately, before any build ran and before a `Compiler` instance (with its own already-resolved `compiler.rspack`) existed to reuse. This is consistent with the nightly E2E matrix failures in `e2e-rspack` on Linux/npm and MacOS/npm since 2026-06-19 (yarn/pnpm resolve `node_modules` more strictly and didn't hit this). Extracts the existing `compiler.rspack ?? require('@rspack/core')` pattern into a shared `loadRspackCore()` helper and uses it consistently across apply-base-config.ts, apply-web-config.ts, and now create-compiler.ts, so there is exactly one lazy resolution path instead of ad-hoc duplicates. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XC8aq1sMkkbhjCChXcvZzh
✅ Deploy Preview for nx-dev ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for nx-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
View your CI Pipeline Execution ↗ for commit c87a775
☁️ Nx Cloud last updated this comment at |
… ESM resolution [Self-Healing CI Rerun]
The e2e-release failure is unrelated to this PR's rspack change: verdaccio fails to start with ERR_PACKAGE_PATH_NOT_EXPORTED for './bin/verdaccio' (packages/js/src/executors/verdaccio/verdaccio.impl.ts), a pre-existing environment/dependency issue outside packages/rspack. Retriggering CI.
Condense multi-paragraph comments explaining the ESM lazy-load workaround down to short one-line why-comments.
There was a problem hiding this comment.
Important
At least one additional CI pipeline execution has run since the conclusion below was written and it may no longer be applicable.
Nx Cloud has identified a possible root cause for your failed CI:
We reviewed the e2e-release:e2e-ci--src/release.test.ts failure and determined it is unrelated to this PR's rspack changes. The error (ERR_PACKAGE_PATH_NOT_EXPORTED: Package subpath './bin/verdaccio') is a verdaccio version compatibility issue in the e2e test environment's fresh npm install, not caused by anything modified here. Our similar-failure check confirmed no match in the comparison branch, and the e2e-release project is not among this PR's touched projects.
No code changes were suggested for this issue.
Trigger a rerun:
🔔 Heads up, your workspace has pending recommendations ↗ to auto-apply fixes for similar failures.
🎓 Learn more about Self-Healing CI on nx.dev
… ESM resolution (#36476) Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> Co-authored-by: Jason Jean <jasonjean1993@gmail.com> (cherry picked from commit e04ce5b)
Current Behavior
Since 2026-06-19, the nightly "E2E matrix" workflow's
e2e-rspackjob has been failing on Linux/npm and MacOS/npm on every run, ine2e/rspack/tests/rspack.legacy.spec.ts→"should support a standard config object". The test generates an app with a hand-writtenrspack.config.js(require('@nx/rspack/app-plugin')/require('@nx/rspack/react-plugin')) and then runsnx build <app>in theproductionconfiguration, which exits with code 1. yarn and pnpm runs of the same job are unaffected (pnpm had also broken briefly and self-healed mid-July).Root cause: #35682 ("feat(rspack): support @rspack/core@2 and @rsbuild/core@2") bumped the default/catalog
@rspack/coreto v2, which ships as pure ESM ("type": "module", norequireexport condition — confirmed by installing@rspack/core@2.1.5directly and inspectingpackage.json/dist/index.js). To avoid resolving that ESM entry point eagerly, the PR added lazy, function-scopedrequire('@rspack/core')calls inapply-base-config.tsandapply-web-config.ts— but it missedpackages/rspack/src/utils/create-compiler.ts, which still had a top-level value import:create-compiler.tsis imported at the top of both the@nx/rspack:rspackand@nx/rspack:dev-serverexecutors, so merely loading either executor module forces Node to resolve@rspack/coreimmediately — before any build runs and before aCompilerinstance (whosecompiler.rspackis already the correctly-resolved module) exists to reuse. This is exactly the "module parse time" resolution the rest of the PR's lazy-require pattern was written to avoid; npm's node_modules hoisting/dedupe behavior differs enough from yarn/pnpm's stricter layouts that this eager, out-of-band resolution is far more likely to hit a broken/duplicate@rspack/coreresolution under npm.Expected Behavior
@rspack/core(and@rspack/binding) is resolved through exactly one lazy, consistent path everywhere in@nx/rspack: reusecompiler.rspackwhen aCompilerinstance already exists, otherwiserequire()it lazily inside the function that actually needs it — never at module load/parse time. Concretely:packages/rspack/src/utils/load-rspack-core.ts: a singleloadRspackCore(compiler?)helper implementingcompiler.rspack ?? require('@rspack/core'), documented with the reasoning above.apply-base-config.tsandapply-web-config.tsnow call the shared helper instead of each having their own inline copy of the same ternary.create-compiler.tsno longer statically imports therspackvalue from@rspack/core; it now callsloadRspackCore()lazily, insidecreateCompiler(), right before constructing the compiler.What I validated
packages/rspackJest suite run directly (node_modules/.bin/jest --config packages/rspack/jest.config.cts) before and after the change: identical133 passed / 26 failedsplit both times (the 26 failures are pre-existing inline-snapshot formatting mismatches unrelated to this change, confirmed by stashing my diff and re-running).apply-base-config.spec.ts(18 tests) passes in isolation, confirming Jest still loadsapply-base-config.tsfine through the shared helper.tsc -p packages/rspack/tsconfig.lib.json --noEmitbefore/after — identical pre-existing errors (unrelated@nx/module-federation/*resolution issues in this sandbox), no new errors from the changed files.@rspack/core@2+@rsbuild/core@2fresh via npm in a scratch project on Node 22.22 and inspected@rspack/core's publishedpackage.json("type": "module",exports["."] = { "default": "./dist/index.js" }, norequirecondition) anddist/index.js(genuineimport/exportsyntax,createRequire(import.meta.url)used internally to load the native@rspack/binding). Confirmed a barerequire('@rspack/core')and a fullrspack({...}).run(...)build succeed on this Node version viarequire(esm)in a clean, single-copy install — ruling out the simplest "any require() throws ERR_REQUIRE_ESM" theory and pointing instead at npm's node_modules layout causing an eager, out-of-band resolution (the bug this PR fixes) to land on a different/duplicate copy than the onecompiler.rspackwould provide.gh api .../logsand the job URL both return 403 as noted in the task), so I don't have the literal error text from CI. I also did not run the fulle2e-rspacksuite (or a realnx generate+ npm-installed workspace end-to-end) in this sandbox — that needs building/publishing the whole@nx/*package set to a local registry and doing fullnpm installs per e2e run, which was impractical here. This fix is based on a precise source-level inconsistency (the one file that bypasses the established lazy-require convention from feat(rspack): support @rspack/core@2 and @rsbuild/core@2 (multi-version compliance) #35682) plus the scratch-install investigation above, not a byte-for-byte reproduction of the CI stack trace.This addresses the CI failures reported in nx's nightly E2E matrix (
e2e-rspack, Linux/npm and MacOS/npm) since 2026-06-19.Related Issue(s)
No tracked GitHub issue — this was investigated directly from the nightly E2E matrix failures.
🤖 This PR was authored by an autonomous Claude agent session.
Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01XC8aq1sMkkbhjCChXcvZzh
Generated by Claude Code