dotnet watch is meant to identify files in referenced projects that should trigger a refresh. This does work correctly for .cs files, but not for .razor files.
Repro
Using .NET Core 3.1.300 (on Mac, but probably is the same on other platforms):
dotnet new blazorwasm --hosted -o MyAppcd MyAppdotnet watch -p Server --listExpected result: Lists the files (including .razor files from the Client project)
Actual: Gets the paths wrong. Output is:
path/MyApp/Server/Pages/Error.cshtml
path/MyApp/Server/Pages/Shared/_Layout.cshtml
path/MyApp/Server/Controllers/WeatherForecastController.cs
path/MyApp/Server/Pages/Error.cshtml.cs
path/MyApp/Server/Program.cs
path/MyApp/Server/Startup.cs
path/MyApp/Server/MyApp.Server.csproj
path/MyApp/Server/App.razor
path/MyApp/Server/Pages/Counter.razor
path/MyApp/Server/Pages/FetchData.razor
path/MyApp/Server/Pages/Index.razor
path/MyApp/Server/Shared/MainLayout.razor
path/MyApp/Server/Shared/NavMenu.razor
path/MyApp/Server/Shared/SurveyPrompt.razor
path/MyApp/Server/_Imports.razor
path/MyApp/Client/Program.cs
path/MyApp/Client/MyApp.Client.csproj
path/MyApp/Shared/WeatherForecast.cs
path/MyApp/Shared/MyApp.Shared.csproj
Notice Server/Pages/Counter.razor? This should be Client/Pages/Counter.razor. I'm not sure how it's computing these incorrect paths to non-existent files.
Also if you try editing and saving one of the Client/**/*.razor files, dotnet watch won't respond.
Is this related to or a replacement for Hot reload for Blazor (dotnet/aspnetcore #5456)?
I ask because I've referred doc readers to that issue for when they ask about hot reload.
@guardrex It's related to, but is not a replacement for, hot reloading. Hot reloading would be a much more sophisticated feature.
dotnet watch just watches for changes to files on disk and re-reruns dotnet build or dotnet run, without really speeding up the build process in any way, without refreshing the browser, and without preserving any state. Despite these limitations it's still really beneficial until a more sophisticated hot reload feature is implemented.
I'm seeing the same behavior with cshtml and a referenced MVC class library. I've posted a repo which reproduces the behavior here.
โฏ dotnet watch -p .\MainProject\ --list
C:\scratch\dotnetwatch-razorrefs\MainProject\Views\Home\Index.cshtml
C:\scratch\dotnetwatch-razorrefs\MainProject\Views\Home\Privacy.cshtml
C:\scratch\dotnetwatch-razorrefs\MainProject\Views\Shared\Error.cshtml
<snip>
C:\scratch\dotnetwatch-razorrefs\MainProject\Views\Home\_ReferencedPartialView.cshtml
C:\scratch\dotnetwatch-razorrefs\RazorClasslib\RazorClasslib.csproj
The issue seems to be that whatever is populating the razor and cshtml into the Watch item group is not using FullPath, so the relative path is being concatenated into the original project's path.
msbuild .\MainProject\MainProject.csproj -t:GenerateWatchList -p:CustomAfterMicrosoftCommonTargets="C:\dev\aspnetcore\src\Tools\dotnet-watch\src\assets\DotNetWatch.targets" -p:CustomAfterMicrosoftCommonCrossTargetingTargets=C:\dev\aspnetcore\src\Tools\dotnet-watch\src\assets\DotNetWatch.targets -p:_DotNetWatchListFile=c:\scratch\watchlist.txt -p:_DotNetWatchTraceOutput=true
Microsoft (R) Build Engine version 16.6.0+5ff7b0c9e for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.
Build started 6/25/2020 5:04:33 PM.
Project "C:\scratch\dotnetwatch-razorrefs\MainProject\MainProject.csproj" on node 1 (GenerateWatchList target(s)).
_CoreCollectWatchItems:
Collecting watch items from 'MainProject'
Views\Home\Index.cshtml
Views\Home\Privacy.cshtml
Views\Shared\Error.cshtml
Views\Shared\_Layout.cshtml
Views\Shared\_ValidationScriptsPartial.cshtml
Views\_ViewImports.cshtml
Views\_ViewStart.cshtml
C:\scratch\dotnetwatch-razorrefs\MainProject\Controllers\HomeController.cs
C:\scratch\dotnetwatch-razorrefs\MainProject\Models\ErrorViewModel.cs
C:\scratch\dotnetwatch-razorrefs\MainProject\Program.cs
C:\scratch\dotnetwatch-razorrefs\MainProject\Startup.cs
C:\scratch\dotnetwatch-razorrefs\MainProject\MainProject.csproj
Project "C:\scratch\dotnetwatch-razorrefs\MainProject\MainProject.csproj" (1) is building "C:\scratch\dotnetwatch-razor
refs\RazorClasslib\RazorClasslib.csproj" (2) on node 1 (_CollectWatchItems target(s)).
_CoreCollectWatchItems:
Collecting watch items from 'RazorClasslib'
Views\Home\_ReferencedPartialView.cshtml
C:\scratch\dotnetwatch-razorrefs\RazorClasslib\RazorClasslib.csproj
Done Building Project "C:\scratch\dotnetwatch-razorrefs\RazorClasslib\RazorClasslib.csproj" (_CollectWatchItems target(
s)).
Done Building Project "C:\scratch\dotnetwatch-razorrefs\MainProject\MainProject.csproj" (GenerateWatchList target(s)).
Workaround is to add them to Watch yourself:
<Project>
<!-- Workaround for dotnet watch with MVC and Referenced SDK Project -->
<Target Name="RazorWatch" BeforeTargets="_CoreCollectWatchItems">
<ItemGroup>
<RazorWatch Include="**\*.cshtml" />
<Watch Include="%(RazorWatch.FullPath)" />
</ItemGroup>
</Target>
</Project>
Another workaround to ensure full paths are used for all Watch items:
<Target Name="FixDotnetWatch" AfterTargets="_CoreCollectWatchItems">
<ItemGroup>
<_WatchRelativePath Include="@(Watch)" Condition="'%(Identity)' != '%(Watch.FullPath)'" />
<Watch Remove="@(_WatchRelativePath)" />
<Watch Include="%(_WatchRelativePath.FullPath)" />
</ItemGroup>
</Target>
Most helpful comment
Another workaround to ensure full paths are used for all
Watchitems: