🐥note.

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

自作RazorClassLibraryの静的ファイルのロードができずに困った話

BlazorのComponentを別プロジェクト(RazorClassLibrary)へ切り分けた際、
Blazorから別プロジェクトの静的リソースへアクセスすることが出来ずにハマったので、それの件について記録します。

SolutionとProjectの作成

以下のコマンドでBlazorAppと、Component役のMyComponentを作成します。
※Component役プロジェクトはrazorclasslibで生成します。

dotnet new sln -o BlazorComponentSample
cd BlazorComponentSample
dotnet new blazorserver -o BlazorApp
dotnet new razorclasslib -o MyComponent
dotnet add .\BlazorApp\BlazorApp.csproj reference .\MyComponent\MyComponent.csproj
dotnet sln .\BlazorComponentSample.sln add BlazorApp MyComponent

MyComponentの作成

MyComponent.csprojTargetFrameworkバージョンを上げておきます。

<Project Sdk="Microsoft.NET.Sdk.Razor">

  <PropertyGroup>
-   <TargetFramework>netstandard2.0</TargetFramework>
+   <TargetFramework>netstandard2.1</TargetFramework>
    <RazorLangVersion>3.0</RazorLangVersion>
  </PropertyGroup>

</Project>

MyComponentではCSSフレームワークBulmaを使用することにします。 Bulmaはnpmで入れたいので、MyComponentフォルダ以下にpackage.jsonを作成します。

package.json

{
  "version": "1.0.0",
  "name": "blazor",
  "private": true
}

以下のコマンドでBulmaをインストールします。
MyComponentフォルダ以下にnode_moduleフォルダが生成されます。

npm install --save-dev Bulma

ビルド時にnode_moduleフォルダからwwwrootフォルダへBulmacssをコピーする設定を行います。
以下のコマンドで、BuildBundlerMinifierをインストールします。

dotnet add package BuildBundlerMinifier

MyComponentフォルダbundleconfig.jsonを作成します。

[
  {
    "outputFileName": "wwwroot/lib/bulma/css/bulma.min.css",
    "inputFiles": ["node_modules/bulma/css/bulma.min.css"],
    "minify": {
      "enabled": false,
      "renameLocals": true
    }
  }
]

これでビルド時にファイルのバンドルが行われるようになりました。
試しにdotnet buildでビルドしてみましょう。wwwroot以下にlib/bulma/css/bulma.min.cssがあれば成功です。

続いてComponent.razorの編集を行います。

呼び元からName, SNSId, ContentをParameterとして受け取り、表示するだけです。

<div class="box">
    <article class="media">
        <div class="media-left">
            <figure class="image is-64x64">
                <img src="bird.png" alt="Image">
            </figure>
        </div>
        <div class="media-content">
            <div class="content">
                <p>
                    <strong>@Name</strong> <small>@SNSId</small>
                    <br>
                    @Content
                </p>
            </div>
        </div>
    </article>
</div>

@code {
    [Parameter]
    public string Name { get; set; }
    [Parameter]
    public string SNSId { get; set; }
    [Parameter]
    public string Content { get; set; }
}

ここまで書いて、ようやくハッと気が付きました。
このComponent役を呼ぶと、静的ファイルのパスってどこ起点になるんでしょうか?

調べた結果、Microsoft Docs先生に答えが書いてありました。

docs.microsoft.com

RCL のwwwrootフォルダーに含まれるファイルは、使用中のアプリにプレフィックス content/{LIBRARY NAME}/で公開されます。 たとえば、という名前のライブラリを使用すると、 content/Razor.Class.Lib/の静的コンテンツへのパスが生成されます。

つまりMyComponent\wwwroot\bird.pngにあるファイルは_content/MyComponent/bird.pngで参照するのが正しいようです。
<img>のsrcを_content/MyComponent/bird.pngに修正します。

以上でMyComponent側の作業は完了です。

BlaozrApp側の作成

Index.razorMyComponentで作成したコンポーネントを表示します。

@page "/"

<h1>Hello, world!</h1>

Welcome to your new app.

<MyComponent.Component1 Name="piyosi" SNSId="piyo_esq" Content="👈このかわいいトリちゃんは実家のセキセイインコです。以後よろしくお願い致します。"></MyComponent.Component1>

MyComponentで使用しているBulmaCSS_Host.cshtmlでロードします。
※bootstrapとbulmaが共存している件は、サンプルコードなので無視します。

@page "/"
@namespace BlazorApp.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>BlazorApp</title>
    <base href="~/" />
    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    <link href="css/site.css" rel="stylesheet" />
 +  <link href="_content/MyComponent/lib/bulma/css/bulma.min.css" rel="stylesheet" />
</head>
<body>
    <app>
        @(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
    </app>

    <script src="_framework/blazor.server.js"></script>
</body>
</html>

動かしてみます

cd BlazorApp
dotnet run

f:id:piyo_esq:20191103070751p:plain
実行結果

デフォのBootstrapも入ってるの分かりにくいですが、ちゃんとBulmaが効いています。

おわり

自分で作ったRazorClassLibraryや静的ファイルを使用するライブラリを使用する際は_content/{LibraryName}/{静的ファイルのパス}に注意しないといけないの、覚えました。

もっと画像の表示領域を大きくしておけばよかったな、と反省しています。