Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hot Reload agent improvements #60030

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

tmat
Copy link
Member

@tmat tmat commented Jan 25, 2025

Ports #58333 to main.

Refactor agent code so that it can be shared with dotnet-watch implementation via a shared project.

Add new API applyHotReloadDeltas to apply updates.

* Hot Reload agent improvements

Refactor agent code so that it can be shared with dotnet-watch implementation via a shared project.

Add new API applyHotReloadDeltas to apply updates.

* Feedback and cleanup
@tmat tmat requested review from a team as code owners January 25, 2025 00:55
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-blazor Includes: Blazor, Razor Components label Jan 25, 2025
@tmat
Copy link
Member Author

tmat commented Jan 25, 2025

@MackinnonBuck ptal

@@ -1,29 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
Copy link
Member

Choose a reason for hiding this comment

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

Do we have alternate test coverage ?

Copy link
Member Author

@tmat tmat Jan 28, 2025

Choose a reason for hiding this comment

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

I'm going to replace the agent code with a source package from https://github.com/dotnet/sdk/tree/main/src/BuiltInTools/HotReloadAgent in a follow up PR. dotnet/sdk has much more test coverage.

Copy link
Member

Choose a reason for hiding this comment

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

Would that cover testing of WASM specifically ? There are lot of moving pieces to make it work in the browser.

Copy link
Member Author

Choose a reason for hiding this comment

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

As far as I know there is no end-to-end test for WASM Hot Reload - i.e. testing that the change had an effect in the browser.

if (response.IsSuccessStatusCode)
{
var deltasJson = await response.Content.ReadAsStringAsync();
var updates = deltasJson != "" ? JsonSerializer.Deserialize<Update[]>(deltasJson, s_jsonSerializerOptions) : null;
Copy link
Member

Choose a reason for hiding this comment

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

Was the previous implementation also using JSON ?
Seems expensive for memory/cpu/transfer.

Could we make this AOT friendly by using code gen ?

Copy link
Member

Choose a reason for hiding this comment

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

Or maybe the previous json parsing was in JS ? That would be cheaper.

Copy link
Member Author

Choose a reason for hiding this comment

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

Previous parsing was in JS. Once we annotate this (dotnet/sdk#46369) it will be trimmed out.

Copy link
Member

@pavelsavara pavelsavara Jan 29, 2025

Choose a reason for hiding this comment

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

Could you please explain why/how this is better than the previous design ?

Copy link
Member

@pavelsavara pavelsavara Jan 29, 2025

Choose a reason for hiding this comment

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

I mean in the browser, anything that is C# will

  • bring more IL code, larger download, slower startup.
  • be slower, because we run interpreter to run managed code which parses the JSON
  • the native JSON.parse in the browser is very very fast in comparison.

Perhaps all of this could be neglected in the dev loop. Should it be ?

Could we rather transfer binary instead of JSON ?

Copy link
Member

Choose a reason for hiding this comment

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

Ok, fine. I would still appreciate some description of what's the overall plan.
Also I'm worried that changes in the SDK will have impact on the previous versions of the product.

Copy link
Member Author

@tmat tmat Jan 29, 2025

Choose a reason for hiding this comment

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

@pavelsavara See #60030 (comment) for context.

We prioritize simplicity (avoiding versioning nightmares) over performance here since Hot Reload is development-only tool. Moving the code to C# avoids calls between SDK code and WASM code, which version differently. That said we obviously don't want to regress WASM app size in production scenario (trimmed). Applying proper trimming attributes is definitely fair ask and we need to follow up on that (dotnet/sdk#46369).

That said, since the size of WASM app is important shouldn't there be an existing test that validates some baseline set of references and expected size range for a simple app? I'd expect such test to exist and fail in the 9.0 branch where these changes were already made a while ago, if in fact using C# JSON deserializer has significant impact. Not saying it does not but we need to start with definition of what is significant and keep measuring it in CI so that we don't regress.

Is the impact significant enough to warrant servicing 9.0? As I mentioned this exact code already shipped in 9.0 and I have not seen any test failing that would indicate we regressed size of WASM apps.

Copy link
Member

Choose a reason for hiding this comment

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

The size of the app fluctuates with every PR. There is regular pref/size regression triage.
I'm not sure we triage it for released branches. I'm not super happy that architectural change landed as patch.
Anyway, it's easier to write test for trimming specific class, than automating size trend detection and triage.
My 2c

Copy link
Member Author

Choose a reason for hiding this comment

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

Hot Reload types themselves are rather small. I don't think they cause significant size increase even if they are not trimmed at all.

What I'd be more worried about is usage of JSON. That should be easy to validate by checking if there are any types that originated in references that are not expected to be there, or checking namespaces of the types.

Copy link
Member

Choose a reason for hiding this comment

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

Test with reflection asserting that class WebAssemblyHotReload can't be found will do the trick.

@tmat
Copy link
Member Author

tmat commented Jan 28, 2025

@javiercn ptal

Copy link
Member

@javiercn javiercn left a comment

Choose a reason for hiding this comment

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

@tmat I'm assuming this is a forward port of the PR you referenced.

I'm not super familiar with this area of the code, so I think a bit of context on how this used to work and what's changing and why would be helpful in the review process.

@tmat
Copy link
Member Author

tmat commented Jan 29, 2025

@javiercn
I can definitely share more details but I'm surprised this PR is raising questions. It is a direct port of #58333, which already shipped in 9.0.

Hot Reload system is rather complex, not sure how much detail would you like to dive into.
The motivation behind these changes is to

  1. unify similar code across multiple products/repos
    See Finalize packages for reuse of the agent in VS/ASP.NET sdk#46216 for details on how various components can be shared.
  2. update the Hot Reload "apply changes" API to report logs to the IDE/dotnet-watch.

WASM Hot Reload is more complex than .NET app Hot Reload because in the latter case the IDE/dotnet-watch injects agent to the target process while in WASM we can't do that. The agent in WASM needs to be built-in. Because the WASM runtime is brought into the app via nuget package, it versions differently than the IDE/dotnet-watch. Therefore, any communication between the agent and the IDE/dotnet-watch needs multiple combinations of versions (e.g. WASM 8.0 with SDK 9.0.200). This makes it difficult to make any changes to the protocol. Some of the changes in this PR (moving code from JavaScript to C#) aim to reduce the amount of APIs/endpoints that cross this versioning boundary.

@pavelsavara
Copy link
Member

pavelsavara commented Jan 30, 2025

I have many questions, mostly because I was not part of hot-reload before.
Thank you for your patience with me. @tmat

The agent in WASM needs to be built-in. This makes it difficult to make any changes to the protocol.

By protocol, you mean the shape of "delta" bytes, right ?

Is this PR or dotnet/sdk#44539 actually making protocol changes ?

If not, what is the last PR which made any changes to it ?

Which flow (repository) is responsible for version of that protocol runtime/SDK/aspnecore/VS/another ?

Do the recent changes support backward and forward compatibility of VS/SDK/runtime ?

For example, can old VS/SDK still talk to project with new runtime+blazor on protcol level ?

Could you please explain versioning dependency between VS and the rest of it in more detail ?

aim to reduce the amount of APIs/endpoints that cross this versioning boundary.

This is more or less transport level change, right ?

Does it break the transport from new IDE/dotnet-watch to old WASM projects ?

Can latest IDE/dotnet-watch transport to Net8 WASM app ? (Net8 is Long Term Support)

@javiercn why is hot reload Blazor WASM feature and not WASM runtime feature ? (non-blazor WASM app template)
Does devserver play role in hot reload ?

@tmat
Copy link
Member Author

tmat commented Jan 30, 2025

By protocol, you mean the shape of "delta" bytes, right ?

Yes, but also endpoints that are invoked on the server side and served by Hot Reload middleware and calls between WASM ASP.NET code and JS scripts included in the SDK.

Is this PR or dotnet/sdk#44539 actually making protocol changes ?

Both are - one for each end of the communication channel. More precisely, this one was the WASM change in 9.0: #58333

Which flow (repository) is responsible for version of that protocol runtime/SDK/aspnecore/VS/another ?

dotnet/sdk.

Do the recent changes support backward and forward compatibility of VS/SDK/runtime ?
For example, can old VS/SDK still talk to project with new runtime+blazor on protcol level ?

Yes.

Could you please explain versioning dependency between VS and the rest of it in more detail ?

VS currently has it's own implementation of Hot Reload components, but I'm working on unifying it with dotnet-watch.
See dotnet/sdk#46216

Can latest IDE/dotnet-watch transport to Net8 WASM app ? (Net8 is Long Term Support)

Yes.

@pavelsavara
Copy link
Member

pavelsavara commented Jan 30, 2025

Is this PR or dotnet/sdk#44539 actually making protocol changes ?

Both are - one for each end of the communication channel. More precisely, this one was the WASM change in 9.0: #58333

What makes the 44539 to not break the Net8 compatibility ?

Because SDK is shared across versions and will get updated to latest on customer dev machines.
And Net8 WASM is stuck with old protocol.

@tmat
Copy link
Member Author

tmat commented Jan 30, 2025

What makes the 44539 to not break the Net8 compatibility ?

Because SDK is shared across versions and will get updated to latest on customer dev machines. And Net8 WASM is stuck with old protocol.

We still have the old code path around. It just doesn't support the added features (logging).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants