Skip to content

Blazor Server scoped CSS missing after dotnet publish #40873

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
dynsim opened this issue Mar 25, 2022 · 9 comments
Closed
1 task done

Blazor Server scoped CSS missing after dotnet publish #40873

dynsim opened this issue Mar 25, 2022 · 9 comments
Labels
area-blazor Includes: Blazor, Razor Components feature-blazor-deployment Issues related to deploying Blazor feature-css-isolation This issue is related to CSS Isolation feature feature-static-web-assets ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. question Status: Resolved

Comments

@dynsim
Copy link

dynsim commented Mar 25, 2022

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

I'm not sure this is the correct repository to post this issue in, but I have not been able to find any other place that seems more fit.

Our issue is: When we run dotnet publish for our Blazor Server App in Azure Pipelines, we are missing some key styles in the output publish folder. If we use just a default Blazor Server project template from .NET 6, the missing files in the publish\wwwroot folder include the following:

  • {AssemblyName}.styles.css
  • css\site.css
  • css\bootstrap\bootstrap.min.css
  • css\open-iconic\font\css\open-iconic-bootstrap.min.css

If we run dotnet publish with the same parameters on our local machines and in GitHub Actions, it is working as expected and we get the correct stylesheet files in the publish folder.

It seems that in Azure Pipelines, the DefineStaticWebAssets task is skipped:

1:7>Target "_ComputeScopedCssStaticWebAssets" in file "/opt/hostedtoolcache/dotnet/sdk/6.0.201/Sdks/Microsoft.NET.Sdk.Razor/targets/Microsoft.NET.Sdk.Razor.ScopedCss.targets" from project "/home/vsts/work/1/s/src/BlazorTestApp.csproj" (target "_CollectAllScopedCssAssets" depends on it):
    Task "DefineStaticWebAssets" skipped, due to false condition; (@(_ScopedCss) != '') was evaluated as ( != '').
1:7>Done building target "_ComputeScopedCssStaticWebAssets" in project "BlazorTestApp.csproj".

In GitHub, the same task has the following output:

1:7>Target "_ComputeScopedCssStaticWebAssets" in file "/home/runner/.dotnet/sdk/6.0.201/Sdks/Microsoft.NET.Sdk.Razor/targets/Microsoft.NET.Sdk.Razor.ScopedCss.targets" from project "/home/runner/work/BlazorServerScopedCSSIssue/BlazorServerScopedCSSIssue/src/BlazorTestApp.csproj" (target "_CollectAllScopedCssAssets" depends on it):
    Task "DefineStaticWebAssets"
      RelativePath 'Shared/MainLayout.razor.rz.scp.css' normalized to 'Shared/MainLayout.razor.rz.scp.css' found for candidate '/home/runner/work/BlazorServerScopedCSSIssue/BlazorServerScopedCSSIssue/src/obj/Release/net6.0/scopedcss/Shared/MainLayout.razor.rz.scp.css' and will be used for matching.
      Identity for candidate '/home/runner/work/BlazorServerScopedCSSIssue/BlazorServerScopedCSSIssue/src/obj/Release/net6.0/scopedcss/Shared/MainLayout.razor.rz.scp.css' is '/home/runner/work/BlazorServerScopedCSSIssue/BlazorServerScopedCSSIssue/src/obj/Release/net6.0/scopedcss/Shared/MainLayout.razor.rz.scp.css' because it starts with content root '/home/runner/work/BlazorServerScopedCSSIssue/BlazorServerScopedCSSIssue/src/obj/Release/net6.0/scopedcss/'.
      RelativePath 'Shared/NavMenu.razor.rz.scp.css' normalized to 'Shared/NavMenu.razor.rz.scp.css' found for candidate '/home/runner/work/BlazorServerScopedCSSIssue/BlazorServerScopedCSSIssue/src/obj/Release/net6.0/scopedcss/Shared/NavMenu.razor.rz.scp.css' and will be used for matching.
      Identity for candidate '/home/runner/work/BlazorServerScopedCSSIssue/BlazorServerScopedCSSIssue/src/obj/Release/net6.0/scopedcss/Shared/NavMenu.razor.rz.scp.css' is '/home/runner/work/BlazorServerScopedCSSIssue/BlazorServerScopedCSSIssue/src/obj/Release/net6.0/scopedcss/Shared/NavMenu.razor.rz.scp.css' because it starts with content root '/home/runner/work/BlazorServerScopedCSSIssue/BlazorServerScopedCSSIssue/src/obj/Release/net6.0/scopedcss/'.
    Done executing task "DefineStaticWebAssets".
1:7>Done building target "_ComputeScopedCssStaticWebAssets" in project "BlazorTestApp.csproj".

Expected Behavior

I expect to have the following files in the publish\wwwroot folder after running dotnet publish:

  • {AssemblyName}.styles.css
  • css\site.css
  • css\bootstrap\bootstrap.min.css
  • css\open-iconic\font\css\open-iconic-bootstrap.min.css

Steps To Reproduce

  1. Create a default Blazor Server app using .NET 6.
  2. Create a minimalistic Azure Pipelines build pipeline (e.g. similar to the one found in the sample repo - https://github.com/dynsim/BlazorServerScopedCSSIssue/blob/main/azure-pipelines.yml)
  3. Run the application that was published and see that the styles are missing.

Exceptions (if any)

Publishing locally and in GitHub Actions.

.NET Version

6.0.201

Anything else?

Additional info

A sample repository can be found here: https://github.com/dynsim/BlazorServerScopedCSSIssue

What we have tried:

File outputs

Azure Pipelines

|-- publish
|   └── appsettings.Development.json
|   └── appsettings.json
|   └── BlazorTestApp
|   └── BlazorTestApp.deps.json
|   └── BlazorTestApp.dll
|   └── BlazorTestApp.pdb
|   └── BlazorTestApp.runtimeconfig.json
|   └── web.config
|   └── wwwroot\favicon.ico
|   └── wwwroot\css\bootstrap\bootstrap.min.css.map
|   └── wwwroot\css\open-iconic\FONT-LICENSE
|   └── wwwroot\css\open-iconic\ICON-LICENSE
|   └── wwwroot\css\open-iconic\README.md
|   └── wwwroot\css\open-iconic\font\fonts\open-iconic.eot
|   └── wwwroot\css\open-iconic\font\fonts\open-iconic.otf
|   └── wwwroot\css\open-iconic\font\fonts\open-iconic.svg
|   └── wwwroot\css\open-iconic\font\fonts\open-iconic.ttf
|   └── wwwroot\css\open-iconic\font\fonts\open-iconic.woff

GitHub Actions

|-- publish
|   └── appsettings.Development.json
|   └── appsettings.json
|   └── BlazorTestApp
|   └── BlazorTestApp.deps.json
|   └── BlazorTestApp.dll
|   └── BlazorTestApp.pdb
|   └── BlazorTestApp.runtimeconfig.json
|   └── web.config
|   └── wwwroot\BlazorTestApp.styles.css
|   └── wwwroot\favicon.ico
|   └── wwwroot\css\site.css
|   └── wwwroot\css\bootstrap\bootstrap.min.css
|   └── wwwroot\css\bootstrap\bootstrap.min.css.map
|   └── wwwroot\css\open-iconic\FONT-LICENSE
|   └── wwwroot\css\open-iconic\ICON-LICENSE
|   └── wwwroot\css\open-iconic\README.md
|   └── wwwroot\css\open-iconic\font\css\open-iconic-bootstrap.min.css
|   └── wwwroot\css\open-iconic\font\fonts\open-iconic.eot
|   └── wwwroot\css\open-iconic\font\fonts\open-iconic.otf
|   └── wwwroot\css\open-iconic\font\fonts\open-iconic.svg
|   └── wwwroot\css\open-iconic\font\fonts\open-iconic.ttf
|   └── wwwroot\css\open-iconic\font\fonts\open-iconic.woff

.NET info

Azure Pipelines

.NET SDK (reflecting any global.json):
 Version:   6.0.201
 Commit:    ef40e6aa06

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  20.04
 OS Platform: Linux
 RID:         ubuntu.20.04-x64
 Base Path:   /opt/hostedtoolcache/dotnet/sdk/6.0.201/

Host (useful for support):
  Version: 6.0.3
  Commit:  c24d9a9c91

.NET SDKs installed:
  6.0.201 [/opt/hostedtoolcache/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.3 [/opt/hostedtoolcache/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 6.0.3 [/opt/hostedtoolcache/dotnet/shared/Microsoft.NETCore.App]

GitHub Actions

.NET SDK (reflecting any global.json):
 Version:   6.0.201
 Commit:    ef40e6aa06

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  20.04
 OS Platform: Linux
 RID:         ubuntu.20.04-x64
 Base Path:   /home/runner/.dotnet/sdk/6.0.201/

Host (useful for support):
  Version: 6.0.3
  Commit:  c24d9a9c91

.NET SDKs installed:
  6.0.201 [/home/runner/.dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.3 [/home/runner/.dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 6.0.3 [/home/runner/.dotnet/shared/Microsoft.NETCore.App]
@javiercn
Copy link
Member

@dynsim thanks for contacting us.

None of this matters since you are publishing the app. Static web assets only plays a role when you run your app inside VS or with the CLI, there is no runtime component once the app has been published.

@javiercn javiercn added feature-css-isolation This issue is related to CSS Isolation feature feature-static-web-assets feature-blazor-deployment Issues related to deploying Blazor area-blazor Includes: Blazor, Razor Components labels Mar 25, 2022
@javiercn
Copy link
Member

@dynsim what you are describing sounds very strange.

Could you capture and share the binlog with us by adding /bl to the publish command?

@javiercn javiercn added the Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. label Mar 25, 2022
@ghost
Copy link

ghost commented Mar 25, 2022

Hi @dynsim. We have added the "Needs: Author Feedback" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

@dynsim
Copy link
Author

dynsim commented Mar 25, 2022

@javiercn: I agree, very strange indeed!

Please find attached the build bin log.
msbuild.zip

To add further to the mystery, I just tried to set up a new Azure Pipeline using the sample GitHub project as a base for the pipeline (we use Azure Repos as repository manager in the pipeline that is not working). In that pipeline, it works as expected! They share the exact same pipeline configuration.

@ghost ghost added Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. and removed Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. labels Mar 25, 2022
@javiercn
Copy link
Member

javiercn commented Mar 25, 2022

@dynsim something in your config is causing the project content not to be picked up.

It's not clear to me what's going on, but there are no css files in the content/none item groups, which is the cause for this. Are the files present on the folder to begin with? (I can't think of anything else other than the commit/checkout not having the files to begin with)

image

@javiercn javiercn added Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. and removed Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. labels Mar 25, 2022
@ghost
Copy link

ghost commented Mar 25, 2022

Hi @dynsim. We have added the "Needs: Author Feedback" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

@dynsim
Copy link
Author

dynsim commented Mar 28, 2022

@javiercn: Thanks a lot for your quick response and helpful insight. Your guidance pointed us in the right direction, and we have now identified the issue. I will briefly explain our findings below for anyone that may encounter the same in the future.

We were so focused on the bundle CSS ({ASSEMBLY NAME}.styles.css) not being built, that we did not realize that the site.css had been removed from source control and that this could cause the bundle CSS not to be generated. It turns out that the bundle CSS is only built if a .CSS file is present when starting the build (or publish) command, which kind of makes sense when looking at it now. That was the issue in our sample project (the one the binlog attached above is from).

The issue in our production app was a little bit different, however. We recently changed from using regular .CSS files to using Sass files, and for that reason, we removed our .CSS files from source control and added a .gitignore rule for these files, as we essentially saw them as build output files. (We then re-used that .gitignore file for the sample project that we sent the binlog from, which was why the .CSS files were not checked into that repo...) We then added a Sass builder as a NuGet reference (we use LibSassBuilder), that compiles the .CSS files as part of the build process. However, this does not seem to be sufficient for the .CSS files to be included in the published files - they need to be there before the publish command is executed. It's not exactly clear to us if this is the expected behavior, or if there is something we are missing. I don't know if you can see a logical explanation for that? Maybe that package compiles the files too late in the build process? We tried with a couple of other packages (e.g. Delegate.SassBuilder, which is suggested in the docs), but that produced the same result, even though the docs states that [the package] can compile SASS/SCSS files at the beginning of the build process before CSS isolation occurs. I'll leave it up to you to decide if this is the expected behavior.

As a resolution, we chose to add a step prior to the publish step in our Azure Pipelines, compiling the CSS using the LibSassBuilder-Tool, and now it works as expected, as the .CSS are present when the publish starts. We tried invoking the Sass generator tool as a pre-build event, but this does not seem to be sufficient either.

Essentially this also means that the issue is not related to Azure Pipelines, as if we freshly clone the repo and run dotnet publish right away, we would have the same issue as originally described.

We have updated the sample project in GitHub to reflect the changes, but what we did exactly was:

We added a .config/dotnet-tools.json manifest file:

{
    "version": 1,
    "isRoot": true,
    "tools": {
        "libsassbuilder-tool": {
            "version": "2.0.0",
            "commands": ["lsb"]
        }
    }
}

And then this is a snippet of our Azure Pipelines configuration, where we added the call to dotnet lsb:

...

- script: dotnet tool restore
displayName: 'Restore .NET Tools'

# The CSS files needs to be compiled before starting publish
# Else they will not be included in published files
- script: 'dotnet lsb'
displayName: 'Compile CSS files'

- task: DotNetCoreCLI@2
displayName: 'Prepare Solution for Publish'
inputs:
    command: 'publish'
    projects: '$(solutionName)'
    publishWebProjects: true
    arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)'
    zipAfterPublish: false

...

Thanks again for helping us identify the issue.

@ghost ghost added Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. and removed Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. labels Mar 28, 2022
@dynsim dynsim changed the title Blazor Server scoped CSS missing after dotnet publish on Azure Pipelines Blazor Server scoped CSS missing after dotnet publish Mar 28, 2022
@javiercn
Copy link
Member

@dynsim thanks for the additional details.

We then added a Sass builder as a NuGet reference (we use LibSassBuilder), that compiles the .CSS files as part of the build process. However, this does not seem to be sufficient for the .CSS files to be included in the published files - they need to be there before the publish command is executed. It's not exactly clear to us if this is the expected behavior, or if there is something we are missing. I don't know if you can see a logical explanation for that? Maybe that package compiles the files too late in the build process? We tried with a couple of other packages (e.g. Delegate.SassBuilder, which is suggested in the docs), but that produced the same result, even though the docs states that [the package] can compile SASS/SCSS files at the beginning of the build process before CSS isolation occurs. I'll leave it up to you to decide if this is the expected behavior.

This seems like an issue in how the CSS files are built. It normally means that the files got generated too late. We created a package in November and did a blog post around the time to help make this scenario easier. You can check the details here

In general, I would recommend against generating build artifacts in a location that makes them susceptible to be included in source control or as part of the build inputs. This is a bit different in .NET Core vs other build systems because the inputs are in many cases implicitly added (you don't need to list them all and there are "default patterns" that discover them) so whenever possible, it is best to place the outputs in a separate folder, (like the obj folder).

In general, if you want your files/assets to be considered, they should be generated before AssignTargetPaths. The blog post I linked above goes into a lot of detail on how this works build wise.

We are also looking to productionize this scenario (that is, making easier to integrate third-party client asset toolchains) in 7.0 and are gathering feedback/interest about it, so please take a moment to upvote this issue if this is something you care about.

I think the behavior here is expected and that additional steps are needed to correctly integrate within the build process, if the guidance provided above doesn't help, please update the repro and let us know, and we can take another look to see if there's something amiss.

@javiercn javiercn added question ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. and removed Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. labels Mar 28, 2022
@ghost ghost added the Status: Resolved label Mar 28, 2022
@ghost
Copy link

ghost commented Mar 29, 2022

This issue has been resolved and has not had any activity for 1 day. It will be closed for housekeeping purposes.

See our Issue Management Policies for more information.

@ghost ghost closed this as completed Mar 29, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Apr 28, 2022
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components feature-blazor-deployment Issues related to deploying Blazor feature-css-isolation This issue is related to CSS Isolation feature feature-static-web-assets ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. question Status: Resolved
Projects
None yet
Development

No branches or pull requests

2 participants