🐥note.

小鳥とMicrosoft <3 なエンジニアの技術Blog📚

dotnet watchコマンドでファイル変更をトリガーに任意のコマンドを実行する

dotnet watchを使用してファイルの変更をトリガーに任意のbat/shellコマンドを実行する方法のメモです。今回は例としてファイル変更時に単体テストを実行し、テストが全件OKの場合アプリを起動するといった動作を実現します。

ソリューションの作成

例として以下の構成のソリューション一式を作成します。

BlazorWASM
 |-- Client
 |  | ...
 |  |
BlazorWASM.Client.csproj
 |-- Server
 |  | ...
 |  |
BlazorWASM.Server.csproj
 |-- Shared
 |  | ...
 |  |
BlazorWASM.Shared.csproj
 |-- Test
 |  | ...
 |  |
BlazorWASM.Test.csproj
 |_ BlazorWASM.sln

生成コマンドは以下の通りです。
--hostedオプション付きBlazor WebAssemblyを作成した後、xUnitによる単体テストプロジェクトを追加しています。

dotnet new blazorwasm -o BlazorWASM --hosted
cd BlazorWASM
dotnet new xunit -n BlazorWASM.Test
mv BlazorWASM.Test Test
dotnet sln BlazorWASM.sln add Test

準備完了です。

watch用csprojの作成

watch.csprojをソリューションファイルと同じ階層に作成します。
<ItemGroup>には監視対象のプロジェクトファイルを記述します。
<Target>で実行するコマンド群を記載します。

--hosted付きBlazor WebAssemblyはServer役を起動するとClient側もよしなにしてくれます。よってdotnet runではWorkingDirectoryをServer指定しています。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <EnableDefaultItems>false</EnableDefaultItems>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="Shared\BlazorWASM.Shared.csproj" />
    <ProjectReference Include="Client\BlazorWASM.Client.csproj" />
    <ProjectReference Include="Server\BlazorWASM.Server.csproj" />
    <ProjectReference Include="Test\BlazorWASM.Test.csproj" />
  </ItemGroup>

  <Target Name="TestAndRun">
    <Exec Command="dotnet build BlazorWASM.sln" />
    <Exec Command="dotnet test --no-restore" WorkingDirectory="Test/" />
    <Exec Command="dotnet run --no-restore" WorkingDirectory="Server/" />
  </Target>
</Project>

下記コマンドで起動します。msbuildを使うのがミソですね。

dotnet watch msbuild ./watch.csproj /t:TestAndRun

単体テストでNGがあると、その時点で止まってくれます。
ContinueOnErrorなどを指定する必要はありません。

監視対象のファイルを追加する場合は?

ClientやServer側のcsprojに記述するのではなくwatch.csprojに追加します。

<ItemGroup>
    <Watch Include="**/*.html" />
</ItemGroup>

余談:独立した複数プロジェクトの監視

本エントリは@mayuki氏とのやり取りが発端でdotnet watchについて色々調査した結果の副産物です。

結局上記ツイートの件、スマートに解決できそうな案は見つかりませんでした。力技が許されるなら、プロジェクト毎にdotnet watchを叩くbat/shellなりを用意しておけばいいんでしょうけど、これじゃダメですね。

cmd /c "start /d . dotnet watch run Hoge"
cmd /c "start /d . dotnet watch run Fuga"
cmd /c "start /d . dotnet watch run Piyo"

なお、BlazorのLiveReloadは.NET 5で計画されていると、一昨日(2/10)にコメントが付きました。

github.com

更に言うと.NET 5 Preview2のSprint PlanningのItemとして置かれています。

github.com

早く欲しいですね。。

おわり

dotnet watchによるファイルウォッチャーとmsbuildを組み合わせれば色々できそうですね。

公式のサンプルではnpm runとかやってみるみたいです。