From 2b72907f103caa9fbb42d6c2bf71e4300eff62b8 Mon Sep 17 00:00:00 2001 From: tmat Date: Sun, 24 Nov 2024 11:43:38 -0800 Subject: [PATCH] Refresh browser for all transitively referencing projects (9.0.1xx) --- .../HotReload/CompilationHandler.cs | 2 +- .../HotReload/ScopedCssFileHandler.cs | 61 +++++++++++++------ .../Utilities/ProjectGraphNodeExtensions.cs | 24 ++++++++ 3 files changed, 66 insertions(+), 21 deletions(-) diff --git a/src/BuiltInTools/dotnet-watch/HotReload/CompilationHandler.cs b/src/BuiltInTools/dotnet-watch/HotReload/CompilationHandler.cs index cdfc4cf3f9c2..e05e9478a90c 100644 --- a/src/BuiltInTools/dotnet-watch/HotReload/CompilationHandler.cs +++ b/src/BuiltInTools/dotnet-watch/HotReload/CompilationHandler.cs @@ -348,7 +348,7 @@ private async ValueTask DisplayResultsAsync(WatchHotReloadService.Updates update switch (updates.Status) { case ModuleUpdateStatus.None: - _reporter.Output("No hot reload changes to apply."); + _reporter.Output("No C# changes to apply."); break; case ModuleUpdateStatus.Ready: diff --git a/src/BuiltInTools/dotnet-watch/HotReload/ScopedCssFileHandler.cs b/src/BuiltInTools/dotnet-watch/HotReload/ScopedCssFileHandler.cs index 3a6961854987..7d7a79644f9f 100644 --- a/src/BuiltInTools/dotnet-watch/HotReload/ScopedCssFileHandler.cs +++ b/src/BuiltInTools/dotnet-watch/HotReload/ScopedCssFileHandler.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Diagnostics; using Microsoft.Build.Graph; +using Microsoft.Build.Framework; using Microsoft.DotNet.Watcher.Internal; using Microsoft.Extensions.Tools.Internal; @@ -52,41 +53,61 @@ public async ValueTask HandleFileChangesAsync(IReadOnlyList files, } } - var logger = reporter.IsVerbose ? new[] { new Build.Logging.ConsoleLogger() } : null; + if (!hasApplicableFiles) + { + return; + } + + var logger = reporter.IsVerbose ? new[] { new Build.Logging.ConsoleLogger(LoggerVerbosity.Minimal) } : null; - var tasks = projectsToRefresh.Select(async projectNode => + var buildTasks = projectsToRefresh.Select(projectNode => Task.Run(() => { - if (!projectNode.ProjectInstance.DeepCopy().Build(BuildTargetName, logger)) + try { - return false; + if (!projectNode.ProjectInstance.DeepCopy().Build(BuildTargetName, logger)) + { + return null; + } } - - if (browserConnector.TryGetRefreshServer(projectNode, out var browserRefreshServer)) + catch (Exception e) { - await HandleBrowserRefresh(browserRefreshServer, projectNode.ProjectInstance.FullPath, cancellationToken); + reporter.Error($"[{projectNode.GetDisplayName()}] Target {BuildTargetName} failed to build: {e}"); + return null; } - return true; - }); + return projectNode; + })); - var results = await Task.WhenAll(tasks).WaitAsync(cancellationToken); + var buildResults = await Task.WhenAll(buildTasks).WaitAsync(cancellationToken); - if (hasApplicableFiles) + var browserRefreshTasks = buildResults.Where(p => p != null)!.GetTransitivelyReferencingProjects().Select(async projectNode => { - var successfulCount = results.Sum(r => r ? 1 : 0); - - if (successfulCount == results.Length) - { - reporter.Output("Hot reload of scoped css succeeded.", emoji: "🔥"); - } - else if (successfulCount > 0) + if (browserConnector.TryGetRefreshServer(projectNode, out var browserRefreshServer)) { - reporter.Output($"Hot reload of scoped css partially succeeded: {successfulCount} project(s) out of {results.Length} were updated.", emoji: "🔥"); + reporter.Verbose($"[{projectNode.GetDisplayName()}] Refreshing browser."); + await HandleBrowserRefresh(browserRefreshServer, projectNode.ProjectInstance.FullPath, cancellationToken); } else { - reporter.Output("Hot reload of scoped css failed.", emoji: "🔥"); + reporter.Verbose($"[{projectNode.GetDisplayName()}] No refresh server."); } + }); + + await Task.WhenAll(browserRefreshTasks).WaitAsync(cancellationToken); + + var successfulCount = buildResults.Sum(r => r != null ? 1 : 0); + + if (successfulCount == buildResults.Length) + { + reporter.Output("Hot reload of scoped css succeeded.", emoji: "🔥"); + } + else if (successfulCount > 0) + { + reporter.Output($"Hot reload of scoped css partially succeeded: {successfulCount} project(s) out of {buildResults.Length} were updated.", emoji: "🔥"); + } + else + { + reporter.Output("Hot reload of scoped css failed.", emoji: "🔥"); } } diff --git a/src/BuiltInTools/dotnet-watch/Utilities/ProjectGraphNodeExtensions.cs b/src/BuiltInTools/dotnet-watch/Utilities/ProjectGraphNodeExtensions.cs index 762811f2d372..5bf18b604449 100644 --- a/src/BuiltInTools/dotnet-watch/Utilities/ProjectGraphNodeExtensions.cs +++ b/src/BuiltInTools/dotnet-watch/Utilities/ProjectGraphNodeExtensions.cs @@ -31,4 +31,28 @@ public static bool IsNetCoreApp(this ProjectGraphNode projectNode, Version minVe public static IEnumerable GetCapabilities(this ProjectGraphNode projectNode) => projectNode.ProjectInstance.GetItems("ProjectCapability").Select(item => item.EvaluatedInclude); + + public static IEnumerable GetTransitivelyReferencingProjects(this IEnumerable projects) + { + var visited = new HashSet(); + var queue = new Queue(); + foreach (var project in projects) + { + queue.Enqueue(project); + } + + while (queue.Count > 0) + { + var project = queue.Dequeue(); + if (visited.Add(project)) + { + foreach (var referencingProject in project.ReferencingProjects) + { + queue.Enqueue(referencingProject); + } + } + } + + return visited; + } }