Skip to content

fix: panic in add_entry_batch when loader calls importModule#13410

Open
henryqdineen wants to merge 6 commits intoweb-infra-dev:mainfrom
henryqdineen:hqd-fix-add-entry-import-module
Open

fix: panic in add_entry_batch when loader calls importModule#13410
henryqdineen wants to merge 6 commits intoweb-infra-dev:mainfrom
henryqdineen:hqd-fix-add-entry-import-module

Conversation

@henryqdineen
Copy link
Copy Markdown
Contributor

Summary

When compilation.addEntry() is called from a JS plugin's make hook and the added entry has a loader that calls this.importModule(), rspack panics:

panicked at crates/rspack_core/src/compilation/build_module_graph/module_executor/mod.rs:
should have event sender

I originally contributed addEntry support in #10268, modeled after addInclude. The eager build in add_entry_batch was part of that implementation to match webpack's callback semantics. This PR fixes a gap where the ModuleExecutor wasn't initialized for that eager build path.

Root cause

add_entry_batch eagerly builds modules via update_module_graph to match webpack's addEntry callback contract (the callback receives the built module). However, the ModuleExecutor event channel is never initialized for this code path.

The normal build path (do_build_module_graph) calls before_build_module_graph to set up the channel before building. add_entry_batch skips this, so ModuleExecutor::import_module panics on the missing event_sender.

Fix

Before the eager update_module_graph call in add_entry_batch, start the module executor if it isn't already running. Tear it down afterward so build_module_graph_pass can set it up fresh.

Tradeoffs considered

  • Why not remove the eager build? add_entry_batch builds eagerly to match webpack's API where the addEntry callback receives the built module. Removing it would be a behavior change — callers that read the module in the callback would get an error instead.

  • Why not leave the executor running? do_build_module_graph unconditionally calls before_build_module_graph, which would overwrite the channel and orphan the background task. Tearing down first is the safe path.

  • Double executor lifecycle: This adds a second before/after_build_module_graph cycle where there was previously one. It only fires when addEntry is called from JS during make with a loader that uses importModule. Long-term, the // TODO move to MakeArtifact on module_executor would eliminate this by tying the executor lifecycle to the artifact.

Test

Added configCases/compilation/add-entry-import-module — a plugin adds an entry via compilation.addEntry() during the make hook, and that entry's loader calls this.importModule(). Without the fix, this panics with should have event sender.

@github-actions github-actions Bot added the release: bug fix release: bug related release(mr only) label Mar 19, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 61dea169c5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".


let make_artifact = self.build_module_graph_artifact.steal();
let exports_info_artifact = self.exports_info_artifact.steal();
let (make_artifact, exports_info_artifact) = update_module_graph(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Stop the temporary executor on eager-build errors

If update_module_graph(...).await? fails after before_build_module_graph has started the executor, this returns before the teardown at lines 686-690 runs. The new entries were already registered at lines 651-652, so a JS plugin can catch the addEntry callback error and still let compilation continue; do_build_module_graph then starts the executor again unconditionally in crates/rspack_core/src/compilation/build_module_graph/mod.rs:33-38, replacing the old channel and orphaning the first background task. This leaves the executor in exactly the stale state the patch is trying to avoid, so the temporary lifecycle needs cleanup on both success and error paths.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Should be resolved if you want to re-review.

@henryqdineen henryqdineen force-pushed the hqd-fix-add-entry-import-module branch from a493040 to 93a321d Compare March 19, 2026 04:54
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Mar 19, 2026

Merging this PR will not alter performance

✅ 16 untouched benchmarks
⏩ 3 skipped benchmarks1


Comparing henryqdineen:hqd-fix-add-entry-import-module (1ecfff2) with main (9a29814)

Open in CodSpeed

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

henryqdineen and others added 6 commits March 19, 2026 11:26
When `compilation.addEntry()` is called from the JS `make` hook,
`add_entry_batch` eagerly builds modules via `update_module_graph` to
match webpack's callback semantics (the callback receives the built
module). However, the `ModuleExecutor` event channel was never
initialized for this code path, so any loader that calls
`this.importModule()` during the build would panic:

  panicked at crates/rspack_core/src/compilation/build_module_graph/module_executor/mod.rs
  should have event sender

The normal build path (`do_build_module_graph`) calls
`before_build_module_graph` which sets up the channel before
`update_module_graph` runs. `add_entry_batch` skipped this step.

This fix ensures the module executor is started before the eager build
in `add_entry_batch` and torn down afterward so that
`build_module_graph_pass` can set it up fresh.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Defer the `?` on `update_module_graph` result until after the executor
is torn down, so the background task isn't orphaned if the build fails.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
after_build_module_graph reads compilation.build_module_graph_artifact,
so the artifacts must be restored before teardown. On error, reset to
defaults to avoid reading stolen state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use StealCell::new instead of Default, move artifacts instead of
cloning on the success path, and simplify the match.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@henryqdineen henryqdineen force-pushed the hqd-fix-add-entry-import-module branch from e292a07 to 1ecfff2 Compare March 19, 2026 15:26
@chenjiahan chenjiahan requested a review from hardfist March 25, 2026 06:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release: bug fix release: bug related release(mr only)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant