Building Blazor Developer Tools: 7 Failed Attempts and What I Learned
The Problem
Every major frontend framework has developer tools - React has React DevTools, Vue has Vue Devtools. Blazor didn't. As someone who loves working in Blazor, I wanted to change that.
The goal was simple: let developers inspect Razor component markup in the browser, just like you can with React components. The implementation? Not so simple.
The Core Challenge
To map rendered HTML back to Razor source code, I needed to inject markers into the markup. Seems straightforward, right? Add some HTML comments or data attributes during compilation, read them in the browser, done.
Except Blazor's Razor compilation pipeline had other ideas.
Attempt #1-6: Dead Ends
I tried various approaches over several weeks:
- HTML comments: Don't survive the Razor compilation process
- Data attributes on existing elements: Too invasive, changes developer's HTML
- Custom Razor directives: Couldn't access the right compilation stage
- Post-compilation IL weaving: Too fragile, broke with framework updates
- Runtime component wrapping: Performance nightmare
- And two other approaches I'm embarrassed to even mention
Each attempt taught me more about Blazor's internals, but none gave me the clean solution I wanted.
The Breakthrough: Shadow Copies + Span Markers
The working solution came from combining two insights:
1. Don't modify the developer's files
Create shadow copies of Razor files during build, inject markers into those copies, and let them go through the normal Razor pipeline.
2. Use invisible span elements as markers
<!-- Developer writes: -->
<div class="container">
<MyComponent />
</div>
<!-- Shadow copy after marker injection: -->
<span style="display:none" data-bdt="Component:MyComponent"></span>
<div class="container">
<MyComponent />
</div>
The MSBuild task creates these shadow copies, the Razor SDK processes them normally, and the browser extension reads the markers to reconstruct the component tree.
The Limitation I Didn't Foresee
This works beautifully... until it doesn't.
Some Blazor components validate their children. For example, MatTable from MatBlazor expects only MatTableRow children. When it sees my span marker, it throws an exception.
// This component would break:
<MatTable>
<!-- My span marker causes an exception here -->
<MatTableRow>...</MatTableRow>
</MatTable>
Current workaround: Let developers exclude specific components in their .csproj:
<BlazorDevToolsExclude Include="MatTable;AnotherComponent" />
It works, but it's not the extremely painless experience I wanted.
The Vision for V2: A Custom SDK
The real solution became clear after shipping v0.9: I need to build a custom Razor SDK.
Instead of injecting visible elements, the SDK would:
- Mirror the official
Microsoft.NET.Sdk.Razorin all behaviors and versioning - Add invisible metadata during compilation using Blazor's existing
b-*attribute pattern - Use
bdt-*attributes that follow the same logic as Blazor's internal markers
<!-- V2 approach - invisible to components: -->
<div bdt-component="MyComponent" bdt-line="5">
<MyComponent />
</div>
Why this is better:
- No DOM pollution - attributes don't affect component children validation
- Performance data - SDK can inject timing/render info
- Live parameter values - Can expose component state like JavaScript debuggers do
- Version alignment - Stays in sync with Blazor releases automatically
Shipping Imperfect Software
I shipped v0.9 knowing these limitations exist. Here's why:
Discipline demands shipping sooner rather than perfectly.
The current version works for 90% of Blazor apps. The workaround handles edge cases. Most importantly, shipping let me:
- Validate that developers actually want this tool
- Get real-world feedback on what matters most
- Build credibility in the community before asking for contributions
The SDK approach is the right long-term solution, but it's months of work. I needed to know people cared before investing that time.
What's Next
Blazor Developer Tools 0.9.x is live and free on GitHub. It has rough edges, but it's useful today.
Version 1.0 with the custom SDK is the next mountain to climb. If you're interested in following along or contributing, check out the repo at github.com/joe-gregory/blazor-devtools.
Lessons for Tool Builders
- Shadow copies solved the "don't modify source" problem - useful pattern for any build-time code injection
- Blazor's compilation pipeline is less documented than its runtime - expect to read source code
- Ship the imperfect version - I learned more in two weeks after launch than in two months of private development
- Some problems need infrastructure solutions - Sometimes the "hack" reveals you need to go deeper into the stack
Building developer tools is humbling. You're building for people who will immediately see your shortcuts and limitations. But it's also deeply rewarding - every GitHub star represents someone whose workflow you improved.
If you work with Blazor, I'd love your feedback. And if you've built devtools for other frameworks, I'd love to hear your war stories in the comments.
Joe Gregory is a senior .NET developer and the creator of Blazor Developer Tools. He's currently planning the architecture for v1.0 while his daughter watches Bluey.
Top comments (0)