Skip to content

Allow JS root components to reinitialize on circuit restart#20

Open
tomerqodo wants to merge 2 commits intocopilot_combined_20260121_qodo_grep_cursor_copilot_1_base_allow_js_root_components_to_reinitialize_on_circuit_restart_pr90from
copilot_combined_20260121_qodo_grep_cursor_copilot_1_head_allow_js_root_components_to_reinitialize_on_circuit_restart_pr90
Open

Allow JS root components to reinitialize on circuit restart#20
tomerqodo wants to merge 2 commits intocopilot_combined_20260121_qodo_grep_cursor_copilot_1_base_allow_js_root_components_to_reinitialize_on_circuit_restart_pr90from
copilot_combined_20260121_qodo_grep_cursor_copilot_1_head_allow_js_root_components_to_reinitialize_on_circuit_restart_pr90

Conversation

@tomerqodo
Copy link
Copy Markdown

Benchmark PR from qodo-benchmark#90

Copilot AI review requested due to automatic review settings January 21, 2026 18:14
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request aims to enable JS root components to reinitialize when a Blazor circuit restarts, addressing scenarios where users navigate away and return to a page with dynamically registered JS root components.

Changes:

  • Modified the TypeScript logic to accept reinitialization from the same renderer type during circuit restarts
  • Simplified test infrastructure by removing conditional component registration
  • Consolidated test coverage by moving tests to the existing StatePersistenceTest class

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
RazorComponentEndpointsStartup.cs Removed conditional registration logic; component is now always registered for JS root components
Program.cs Removed separate test host configuration that was specific to JS root component testing
StatePersistenceTest.cs Added test to verify persistent state works in dynamic JS roots
StatePersistanceJSRootTest.cs Deleted entire test class; functionality moved to StatePersistenceTest (also fixes spelling error in filename)
WebRendererInteropMethods.ts Added rendererId parameter to enableJSRootComponents call
JSRootComponents.ts Added logic to track rendererId and allow reinitialization, with flag to prevent duplicate initializer calls
Comments suppressed due to low confidence (1)

src/Components/test/E2ETest/Tests/StatePersistanceJSRootTest.cs:1

  • The deleted file name contained a spelling error: 'StatePersistance' should be 'StatePersistence'. This has been corrected by moving the test to the correctly-named StatePersistenceTest.cs file.

Comment on lines +279 to +291
[Theory]
[InlineData("ServerNonPrerendered")]
[InlineData("WebAssemblyNonPrerendered")]
public void PersistentStateIsSupportedInDynamicJSRoots(string renderMode)
{
Navigate($"subdir/WasmMinimal/dynamic-js-root.html?renderMode={renderMode}");

Browser.Equal("Counter", () => Browser.Exists(By.TagName("h1")).Text);
Browser.Equal("Current count: 0", () => Browser.Exists(By.CssSelector("p[role='status']")).Text);

Browser.Click(By.CssSelector("button.btn-primary"));
Browser.Equal("Current count: 1", () => Browser.Exists(By.CssSelector("p[role='status']")).Text);
}
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

The test PersistentStateIsSupportedInDynamicJSRoots verifies that dynamic JS root components work with persistent state, but it doesn't actually test the circuit restart scenario mentioned in the PR title. The test should navigate away to destroy the circuit, then navigate back to verify that the component can reinitialize after circuit restart. Consider adding assertions that verify the component continues to work after a circuit restart, similar to the StateIsProvidedEveryTimeACircuitGetsCreated test pattern.

Copilot uses AI. Check for mistakes.
// because the old circuit is gone. We don't dispose the old manager - doing so would cause
// JSDisconnectedException because the circuit that created it no longer exists.
currentRendererId = rendererId;
manager = managerInstance;
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

The variable jsComponentParametersByIdentifier is assigned but never updated when enableJSRootComponents is called during a circuit restart. This means that when a new circuit starts with potentially different component parameters, the old parameters from the initial circuit will still be used by functions like RootComponentsFunctions.add(). This could lead to incorrect parameter metadata being used for dynamically added components after a circuit restart.

Suggested change
manager = managerInstance;
manager = managerInstance;
jsComponentParametersByIdentifier = jsComponentParameters;

Copilot uses AI. Check for mistakes.
Comment on lines +126 to 130
if (manager && currentRendererId === rendererId) {
// A different renderer type (e.g., Server vs WebAssembly) is trying to enable JS root components.
// This is a multi-host scenario which is not supported for dynamic root components.
throw new Error('Dynamic root components have already been enabled.');
}
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

The condition checks if manager exists AND currentRendererId equals the new rendererId, which means it throws an error when the SAME renderer is being re-initialized (e.g., circuit restart). However, the comment states this is for detecting "A different renderer type" scenario. The logic is inverted - it should check if manager exists AND currentRendererId is DIFFERENT from rendererId to detect multi-host scenarios. As written, it prevents the intended circuit restart scenario and allows different renderers.

Copilot uses AI. Check for mistakes.
Comment on lines +145 to +146
for (const componentIdentifier of componentIdentifiers)
initializerFunc(componentIdentifier, jsComponentParameters[componentIdentifier]);
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

The for loop is written without braces as a single-line statement. While syntactically valid, this deviates from the established pattern in the codebase where multi-line control flow statements use braces. The previous version of this code used braces, and removing them reduces code consistency and makes the code more error-prone to future modifications.

Suggested change
for (const componentIdentifier of componentIdentifiers)
initializerFunc(componentIdentifier, jsComponentParameters[componentIdentifier]);
for (const componentIdentifier of componentIdentifiers)
{
initializerFunc(componentIdentifier, jsComponentParameters[componentIdentifier]);
}

Copilot uses AI. Check for mistakes.
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