Skip to content

fix(rspack): lazy-load @rspack/core in create-compiler to avoid eager ESM resolution - #36476

Merged
AgentEnder merged 6 commits into
masterfrom
fix/e2e-rspack-npm-esm
Jul 27, 2026
Merged

fix(rspack): lazy-load @rspack/core in create-compiler to avoid eager ESM resolution#36476
AgentEnder merged 6 commits into
masterfrom
fix/e2e-rspack-npm-esm

Conversation

@claude

@claude claude Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Current Behavior

Since 2026-06-19, the nightly "E2E matrix" workflow's e2e-rspack job has been failing on Linux/npm and MacOS/npm on every run, in e2e/rspack/tests/rspack.legacy.spec.ts"should support a standard config object". The test generates an app with a hand-written rspack.config.js (require('@nx/rspack/app-plugin') / require('@nx/rspack/react-plugin')) and then runs nx build <app> in the production configuration, 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/core to v2, which ships as pure ESM ("type": "module", no require export condition — confirmed by installing @rspack/core@2.1.5 directly and inspecting package.json/dist/index.js). To avoid resolving that ESM entry point eagerly, the PR added lazy, function-scoped require('@rspack/core') calls in apply-base-config.ts and apply-web-config.ts — but it missed packages/rspack/src/utils/create-compiler.ts, which still had a top-level value import:

import { rspack, type Compiler, ... } from '@rspack/core';

create-compiler.ts is imported at the top of both the @nx/rspack:rspack and @nx/rspack:dev-server executors, so merely loading either executor module forces Node to resolve @rspack/core immediately — before any build runs and before a Compiler instance (whose compiler.rspack is 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/core resolution under npm.

Expected Behavior

@rspack/core (and @rspack/binding) is resolved through exactly one lazy, consistent path everywhere in @nx/rspack: reuse compiler.rspack when a Compiler instance already exists, otherwise require() it lazily inside the function that actually needs it — never at module load/parse time. Concretely:

  • Added packages/rspack/src/utils/load-rspack-core.ts: a single loadRspackCore(compiler?) helper implementing compiler.rspack ?? require('@rspack/core'), documented with the reasoning above.
  • apply-base-config.ts and apply-web-config.ts now call the shared helper instead of each having their own inline copy of the same ternary.
  • create-compiler.ts no longer statically imports the rspack value from @rspack/core; it now calls loadRspackCore() lazily, inside createCompiler(), right before constructing the compiler.

What I validated

  • Unit tests: packages/rspack Jest suite run directly (node_modules/.bin/jest --config packages/rspack/jest.config.cts) before and after the change: identical 133 passed / 26 failed split 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 loads apply-base-config.ts fine through the shared helper.
  • Typecheck: tsc -p packages/rspack/tsconfig.lib.json --noEmit before/after — identical pre-existing errors (unrelated @nx/module-federation/* resolution issues in this sandbox), no new errors from the changed files.
  • ESM interop repro: installed @rspack/core@2 + @rsbuild/core@2 fresh via npm in a scratch project on Node 22.22 and inspected @rspack/core's published package.json ("type": "module", exports["."] = { "default": "./dist/index.js" }, no require condition) and dist/index.js (genuine import/export syntax, createRequire(import.meta.url) used internally to load the native @rspack/binding). Confirmed a bare require('@rspack/core') and a full rspack({...}).run(...) build succeed on this Node version via require(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 one compiler.rspack would provide.
  • What I could not validate: I could not reach the actual GitHub Actions job logs for the failing nightly runs (blocked by this sandbox's egress policy — gh api .../logs and 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 full e2e-rspack suite (or a real nx 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 full npm 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

… 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
@netlify

netlify Bot commented Jul 27, 2026

Copy link
Copy Markdown

Deploy Preview for nx-dev ready!

Name Link
🔨 Latest commit c87a775
🔍 Latest deploy log https://app.netlify.com/projects/nx-dev/deploys/6a67c63039c0b700086a67d4
😎 Deploy Preview https://deploy-preview-36476--nx-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Jul 27, 2026

Copy link
Copy Markdown

Deploy Preview for nx-docs ready!

Name Link
🔨 Latest commit c87a775
🔍 Latest deploy log https://app.netlify.com/projects/nx-docs/deploys/6a67c630690bef0008a96768
😎 Deploy Preview https://deploy-preview-36476--nx-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@nx-cloud

nx-cloud Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit c87a775

Command Status Duration Result
nx affected --targets=lint,test,build,e2e,e2e-c... ✅ Succeeded 50m 32s View ↗
nx run-many -t check-imports check-lock-files c... ✅ Succeeded 4s View ↗
nx-cloud record -- pnpm nx-cloud conformance:check ✅ Succeeded 40s View ↗
nx build workspace-plugin ✅ Succeeded <1s View ↗
nx-cloud record -- nx sync:check ✅ Succeeded 16s View ↗
nx-cloud record -- nx format:check ✅ Succeeded 4s View ↗

☁️ Nx Cloud last updated this comment at 2026-07-27 21:52:43 UTC

nx-cloud[bot]

This comment was marked as outdated.

nx-cloud[bot]

This comment was marked as outdated.

claude added 2 commits July 27, 2026 17:24
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.
@FrozenPandaz
FrozenPandaz marked this pull request as ready for review July 27, 2026 19:34
@FrozenPandaz
FrozenPandaz requested a review from a team as a code owner July 27, 2026 19:34
@FrozenPandaz
FrozenPandaz requested a review from JamesHenry July 27, 2026 19:34
nx-cloud[bot]

This comment was marked as outdated.

@nx-cloud nx-cloud Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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:

Rerun CI

Nx Cloud View detailed reasoning on Nx Cloud ↗

🔔 Heads up, your workspace has pending recommendations ↗ to auto-apply fixes for similar failures.


🎓 Learn more about Self-Healing CI on nx.dev

@AgentEnder
AgentEnder merged commit e04ce5b into master Jul 27, 2026
25 checks passed
@AgentEnder
AgentEnder deleted the fix/e2e-rspack-npm-esm branch July 27, 2026 22:08
FrozenPandaz added a commit that referenced this pull request Jul 29, 2026
… 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)
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.

3 participants