Search code examples
asp.net-corerazormsbuild

In RCL, how to embed file generated at build time?


I have a Razor Class Library project which I would like to compile into a single .dll with all static resources embedded.

Embedding can easily be done for resources from wwwroot - with the following lines in .csproj:

<PropertyGroup>
    <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
</PropertyGroup>

<ItemGroup>
      <EmbeddedResource Include="wwwroot\**" />
</ItemGroup>

<ItemGroup>
    <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="7.0.5" />
</ItemGroup>

However, in RCL we can also use the scoped css mechanism, i.e. files named "componentName.razor.css" spread throughout the project (they must be located alongside components). At build, those files are processed (by adding scoping to css selectors) and bundled into a single assemblyName.styles.css file, temporarily located under obj\Release\net7.0\scopedcss\bundle\ (path parts can be different depending on build configuration and target framework). This file is later copied to wwwroot directory when publishing the library.

If I try to just embed the file from the location where it is going to exist, build fails - at the time embedding is performed the target file has not been generated yet:

<ItemGroup>
      <EmbeddedResource Include="$(IntermediateOutputPath)\scopedcss\bundle\$(AssemblyName).styles.css">
            <LogicalName>wwwroot.$(AssemblyName).styles.css</LogicalName>
      </EmbeddedResource>
 </ItemGroup>

error message - 'Could not find file'

Of course, I could just directly embed all the .razor.css files - but I would then loose the scoping mechanism (enforced by selector modifications that compiler makes while bundling), which is the entire point of using them.

My question is then: how can I embed the assemblyName.styles.css file generated at build time into library's main .dll?

My guess is that it could be achieved with MSBuild tasks, like in Inject EmbeddedResource created by MSBuild Task, but I can't get it right.


Solution

  • Thanks to guidance by @Jonathan Dodds (see comments) I was able to embed the generated asseblyName.style.css file in the RCL .dll.

    Bundled scoped css file I mentioned in the question turns out to be generated in the BundleScopedCssFiles target.

    The solution is to add the following to the RCL .csproj file:

    <Target Name="EmbedScopedCss" BeforeTargets="Build" DependsOnTargets="BundleScopedCssFiles">
          <ItemGroup>
                <EmbeddedResource Include="$(IntermediateOutputPath)\scopedcss\bundle\$(AssemblyName).styles.css">
                     <LogicalName>wwwroot.$(AssemblyName).styles.css</LogicalName>
                </EmbeddedResource>
          </ItemGroup>
     </Target>
    

    (The LogicalName property under EmbeddedResource is not required, but it makes embedded file named as if it existed in the wwwroot directory.)

    I also had to add my target to project's InitialTargets (otherwise it was ignored):

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