-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add support for hot reload to dotnet-watch #16401
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
Conversation
I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label. |
5d68ec1
to
1395942
Compare
216dc0c
to
05126e0
Compare
* Host a Roslyn workspace to produce EnC deltas and apply to app * Add "agents" to support reloading ASP.NET Core and Blazor WebAssembly apps
05126e0
to
d9c1ecc
Compare
I was hoping we could yolo this change for preview3, and I can do a walkthru of this next week. There's some design issues that might be nice to get some ideas on, plus it would be good if we can have others follow what's happening here. |
@wli3 since this involves a changes to the redist, NuGet.config and the version files. |
src/BuiltInTools/AspNetCoreDeltaApplier/Microsoft.Extensions.AspNetCoreDeltaApplier.csproj
Outdated
Show resolved
Hide resolved
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) | ||
{ | ||
var customAttributes = assembly.GetCustomAttributes<AssemblyMetadataAttribute>(); | ||
var deltaReceiverAttributes = customAttributes.Where(a => a.Key == "ReceiveHotReloadDeltaNotification" && !string.IsNullOrEmpty(a.Value)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Who is responsible for applying the ReceiveHotReloadDeltaNotification
on the app's assemblies. The compiler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will eventually get replaced by a runtime API: dotnet/runtime#49361. This is a place holder until those APIs come online.
} | ||
catch (TimeoutException) | ||
{ | ||
Log("Unable to connect to hot-reload server."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the hot-reload
server log out info that would help determine why it failed to connect here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Running watch --verbose
should emits a fair bit of the diagnostics (for instance if the named pipe is in use), so that should probably help piecing this together.
} | ||
} | ||
|
||
// We want to base this off of mvids, but we'll figure that out eventually. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in eventually we'll be doing something like update.ChangedMvid
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup. Right now it's an empty collection, but it's a hypothetical idea I'd been playing around with to do different things based on what function gets updated.
location.reload(); | ||
return; | ||
} | ||
if (parsed.type == 'UpdateStaticFile') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: might be time for a switch
statement here.
context.ProcessSpec.EnvironmentVariables.DotNetStartupHooks.Add(deltaApplier); | ||
|
||
// Configure the app for EnC | ||
context.ProcessSpec.EnvironmentVariables["DOTNET_MODIFIABLE_ASSEMBLIES"] = "debug"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What values can DOTNET_MODIFIABLE_ASSEMBLIES
have?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's the only possible value for it: dotnet/runtime#47274
{ | ||
if (_deltaApplier is null) | ||
{ | ||
_deltaApplier = context.DefaultLaunchSettingsProfile.HotReloadProfile == "blazorwasm" ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do things get set up for a hosted Blazor WASM app?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
…spNetCoreDeltaApplier.csproj
await _pipe.FlushAsync(cancellationToken); | ||
|
||
var result = ApplyResult.Failed; | ||
var bytes = ArrayPool<byte>.Shared.Rent(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems unnecessary to rent an array of size 1 here. I'd bet the array returned will be size 4096. If only one call to Apply is being run at a time, you could have it in a field.
src/BuiltInTools/dotnet-watch/HotReload/BlazorWebAssemblyDeltaApplier.cs
Show resolved
Hide resolved
{ | ||
// FSW events sometimes appear before the file has been completely written to disk. Provide a small delay before we read the file contents | ||
// to ensure we are not contending with partial writes or write locks. | ||
await Task.Delay(20); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the goal here to maximize the chance of the first call succeeding?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup. This is obviously very twitchy, but so far it seems to work. I should remove the Task.Delay
and see if I can make this work.
|
||
if (!fileSet.Project.IsNetCoreApp60OrNewer()) | ||
{ | ||
_reporter.Error($"Hot reload based watching is only supported in .NET 6.0 or newer apps. Update the project's launchSettings.json to disable this feature."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems bad. Are you saying that anyone who has a mix of projects (5.0, 6.0) will need to manually go into their launchsettings.json to disable it? Could it be a property in the csproj instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The launching project must be a net6 project since the APIs to apply hot reload are only available in net6.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this fail earlier for 5.0 and earlier?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have to explicitly modify the launchSettings to enable hot reload. So it's a bit unusual to get in a bad state to begin with. This is the earliest we know of their tfm.
Co-authored-by: Justin Kotalik <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uh oh!
There was an error while loading. Please reload this page.