Skip to content

Make the Razor decl/impl markup split opt-in (default off) - #85040

Merged
chsienki merged 2 commits into
mainfrom
copilot/fix-sdk-split-phase-registration
Aug 27, 2026
Merged

Make the Razor decl/impl markup split opt-in (default off)#85040
chsienki merged 2 commits into
mainfrom
copilot/fix-sdk-split-phase-registration

Conversation

Copilot AI commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Summary

The Sonic unrevert made the Razor decl/impl markup split unconditional: DefaultRazorMarkupSplitPhase ran for every RazorProjectEngine, but the only public accessor (RazorCodeDocumentExtensions.GetCSharpDocument()) is hard-wired to the impl half. A host that consumes only the implementation document — notably the SDK's classic, non-source-generator Razor compilation — therefore silently lost everything the split moved into the decl half.

This gates the split behind an opt-in option, so classic mode again produces a single complete document.

Changes

  • RazorCodeGenerationOptions — new internal EnableMarkupSplit flag (Flags.EnableMarkupSplit = 1 << 13), option property, and Builder property, defaulting to off. No public API change, so no PublicAPI.Unshipped.txt churn.
  • DefaultRazorMarkupSplitPhase — returns the document untouched when the flag is clear, the same early-out it already takes for non-components. DefaultRazorDeclCSharpLoweringPhase then no-ops (no decl subtree stashed) and DefaultRazorCSharpLoweringPhase writes the whole document as a single file. Both phases stay registered, so the public phase list and RazorProjectEngineTest's ordering assertion are unchanged, and nothing downstream needed to change.
  • Source generatorRazorSourceGenerator.Helpers.GetProjectEngine opts in (it emits both .g.cs and .decl.g.cs). The separate declaration/discovery engine stays off.
  • Test infrastructure — opts in so existing split/baseline assertions are unchanged: RazorIntegrationTestBase (via a new overridable internal virtual bool EnableMarkupSplit => true), IntegrationTestBase, RazorProjectEngineTestBase, RazorToolingIntegrationTestBase, RazorToolingProjectEngineTestBase, RazorCodeDocumentFactory.
  • New MarkupSplitterDisabledComponentTest — overrides EnableMarkupSplit => false and asserts a splittable component yields a null decl document and a single impl document carrying both the markup-free member and the lifted markup method, and that it still compiles.

Why an option rather than conditional phase registration

The phase list is public (RazorProjectEngine.Phases) and asserted on in tests; conditional registration would also have to be threaded through the RazorProjectEngine.Create overloads and ProcessDeclarationOnly, and would make the presence of a pipeline stage configuration-dependent. The option flag gets the same effect with the pipeline shape unchanged, which is the lower-risk answer to "will downstream steps expect the phase to have run?".

Validation

  • dotnet build src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Microsoft.CodeAnalysis.Razor.Compiler.csproj — 0 warnings, 0 errors
  • dotnet build Razor.slnf — 0 errors
  • dotnet test --framework net10.0: Razor Language 3976 passed, SourceGenerators 220 passed, Razor.Workspaces 391 passed, Remote.Razor 488 passed, VSCode RazorExtension (includes CohostingShared) 1525 passed. No baselines changed.
Microsoft Reviewers: Open in CodeFlow

Fixes dotnet/sdk#55765

Copilot AI and others added 2 commits August 25, 2026 23:11
Co-authored-by: chsienki <16246502+chsienki@users.noreply.github.com>
Co-authored-by: chsienki <16246502+chsienki@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

@chsienki
chsienki marked this pull request as ready for review August 26, 2026 00:35
@chsienki
chsienki requested a review from a team as a code owner August 26, 2026 00:35
Copilot AI lite review requested due to automatic review settings August 26, 2026 00:35
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI 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.

Pull request overview

This PR makes the Razor decl/impl markup split behavior opt-in (default off) so hosts that only consume the implementation C# document continue to get a complete, single generated output. It introduces an internal codegen option to gate the split phase, updates the source generator and test infrastructure to explicitly opt in, and adds a regression test that pins the default-off behavior for components.

Changes:

  • Added an internal RazorCodeGenerationOptions.EnableMarkupSplit flag (default false) and corresponding builder flag to control whether components are split into decl/impl halves.
  • Updated DefaultRazorMarkupSplitPhase to early-out (no split) unless EnableMarkupSplit is enabled.
  • Updated source generator + test infrastructure to opt in, and added a new integration test verifying classic (single-document) output when the split is disabled.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/Razor/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/RazorProjectEngineTestBase.cs Opts test project engines into markup split so existing split-based assertions keep working.
src/Razor/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/RazorIntegrationTestBase.cs Adds overridable EnableMarkupSplit test hook and wires it into codegen options.
src/Razor/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/IntegrationTestBase.cs Opts integration tests into markup split to preserve existing baselines/expectations.
src/Razor/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/RazorCodeDocumentFactory.cs Opts tooling test code document factory into markup split to preserve expected output.
src/Razor/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Language/RazorToolingProjectEngineTestBase.cs Opts tooling test engines into markup split consistently.
src/Razor/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Language/IntegrationTests/RazorToolingIntegrationTestBase.cs Opts tooling integration tests into markup split to match split-based assertions.
src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.Helpers.cs Ensures the source generator opts into markup split (it emits both impl and decl outputs).
src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeGenerationOptions.Flags.cs Adds a new internal flag bit (EnableMarkupSplit).
src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeGenerationOptions.cs Adds internal EnableMarkupSplit option accessor with rationale in XML docs.
src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeGenerationOptions.Builder.cs Adds internal EnableMarkupSplit builder property to set the flag.
src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorMarkupSplitPhase.cs Gates the split phase behavior behind CodeGenerationOptions.EnableMarkupSplit.
src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorDeclCSharpLoweringPhase.cs Updates documentation to reflect the new “host didn’t opt in” no-op case.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/MarkupSplitterDisabledComponentTest.cs New regression test verifying that disabling the split yields a single complete impl document and compiles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants