Skip to content

Conversation

@javiercn
Copy link
Member

@javiercn javiercn commented Sep 3, 2020

Description

This change includes several improvements to CSS isolation that we have gathered from validation and usage feedback.

We have switched from producing a single scoped CSS bundle file for the entire application with all the scoped css files from the current project, referenced projects and package projects to producing one bundle per referenced project/package and to include those bundles into an "application" bundle throught CSS @import statements.

We have cleaned up the bundle names to make them more unique by including the project name on them and we have also cleaned up the bundle extensions.

We have decided to put the individual bundles generated for the project scoped css assets into the static web assets base path of the project, so that when developers reference assets from their scoped css files (like using the CSS url function) the path they use matches what they have inside their library wwwroot folder.

We have decided to put the application bundle on the root path of the application provided that the developer has not overriden the default StaticWebAssetsBasePath.

This is so that the bundle location is consistent across templates, and can be found at ProjectName.styles.css independent of whether the app is a blazor webassembly app or a server side blazor app.

For cases where the default StaticWebAssetBasePath has been overriden, the value is respected and the bundle is placed at $(StaticWebAssetBasePath)/ProjectName.styles.css.

Packaged razor class libraries with scoped css files now package a "project" bundle instead of the individual files.

Customer Impact

  • Library authors are not able to build their libraries with scoped css components in a way that allows them to deterministically reference assets from their library/package.
  • Customers need to perform a full-rebuild within Visual Studio to pick up changes in their scoped css files.
  • Customers can run into issues with conflicting static web assets that are not correctly being detected and that are hard to diagnose.

Regression?

No

Risk

Low. The biggest risk factor is that there are MSBuild changes that can potentially impact the experience in Visual Studio, which is something that is hard to verify, but by getting this change in early we can access an early RC2 build, validate with a coherent build of the product and confirm there are no E2E issues. All that is in addition to all the tests that we have in place to prevent regressions and the new tests that we've added to validate the scenarios at the command-line level.

Fixes

#24337
#24583
#24300
#24257

@javiercn
Copy link
Member Author

javiercn commented Sep 3, 2020

Summary

This change includes several improvements to CSS isolation that we have gathered from validation and usage feedback.

We have switched from producing a single scoped CSS bundle file for the entire application with all the scoped css files from the current project, referenced projects and package projects to producing one bundle per referenced project/package and to include those bundles into an "application" bundle throught CSS @import statements.

We have cleaned up the bundle names to make them more unique by including the project name on them and we have also cleaned up the bundle extensions.

We have decided to put the individual bundles generated for the project scoped css assets into the static web assets base path of the project, so that when developers reference assets from their scoped css files (like using the CSS url function) the path they use matches what they have inside their library wwwroot folder.

We have decided to put the application bundle on the root path of the application provided that the developer has not overriden the default StaticWebAssetsBasePath.

This is so that the bundle location is consistent across templates, and can be found at ProjectName.styles.css independent of whether the app is a blazor webassembly app or a server side blazor app.

For cases where the default StaticWebAssetBasePath has been overriden, the value is respected and the bundle is placed at $(StaticWebAssetBasePath)/ProjectName.styles.css.

Packaged razor class libraries with scoped css files now package a "project" bundle instead of the individual files.

Motivation

The current way we bundled assets was problematic since it didn't allow package/library authors to deterministically reference assets within their scoped css files.

In addition to that, there were a couple of bugs regarding the integration with Visual Studio that we discovered and that ammount to a suboptimal experience (users having to perform rebuilds to get their scoped CSS files/bundles updated) that we want to fix before RTM.

Goals

  • Fix the remaining bugs and experience issues.

Non-goals

  • Implement new features related to CSS isolation.

Scenarios

  • As a developer I want to write an application that can use styles that are isolated to a given component.
  • As a developer I want to build a razor class library that includes components with styles isolated to those component and can be consumed by other projects/applications.
  • As a developer I want to pack a razor class library as a package that includes components with styles isolated to those components and can be consumed by other projects/applications.
  • As a developer I want to consume multiple Blazor WebAssembly applications with scoped styles.
  • As a developer I want to have a blazor webassembly application and a blazor server application with scoped styles that are part of the same ASP.NET Core application.

Risks

MSBuild changes are harder than normal code changes, but we have mitigated the risk with a substantial amount of tests that validate the majority of scenarios.

We had to relax some constraints in Static Web Assets in general, but the default behavior still satisfies those constraints and bypassing those constraints requires using advanced extensibility.

The constraints that we relaxed are the original limitation that all assets for a package had to share the same ContentRoot and BasePath (which in practice prevented any two assets url path from conflicting at development and publish time)

Now individual assets have the freedom to define their own base paths individually.

This is not a problem because we still use a constraint that we included while developing Blazor WebAssembly that validates that no two assets will conflict.

We perform this check before we pack the assets on a package and before we generate a manifest for development, so users still get feedback at compile time if their application has a problem.

Interaction with other parts of the framework

This feature integrates with static web assets, we had to modify a bit the way we package assets to support having assets on different base paths to keep consistency with what applications can do.

We had to change the place in MSBuild where we generate the development manifest because it was causing unintended targets to run. The change is actually good since it was likely a latent bug in static web assets that we didn't know about.

Detailed design

Drawbacks

It requires more requests to load all the styles (1 additional request per referenced project/package) but the alternative is to merge everything into a single bundle, which makes it really hard to reference assets from the scoped styles.

Considered alternatives

Single file bundle, which was the implementation we started with until we determined it wasn't good enough.

Open questions

None so far

@javiercn javiercn requested review from a team, SteveSandersonMS and pranavkm September 3, 2020 12:24
@SteveSandersonMS
Copy link
Member

As part of doing this, would it be reasonable to update the RCL project template to make use of scoped styles now it's actually possible?

If you don't want this PR to include that change it's fine, but we should definitely do it before RTM, which in practice means in a matter of days, so it might be lowest friction to include it here.

Bonus points would be adding JS isolation to the RCL template. I'm very happy to do that myself if you prefer. Just let me know.

var relativePath = NormalizePath(bundle.GetMetadata("RelativePath"));
var importPath = NormalizePath(Path.Combine(prefix, bundleBasePath, relativePath));

builder.AppendLine($"import '{importPath}'");
Copy link
Member

@SteveSandersonMS SteveSandersonMS Sep 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the syntax @import 'url';, not import 'url'? (leading @ and trailing ;)

Just want to check we've definitely got coverage to say this works for real. If there's a possibility of adding an E2E test that uses getComputedStyle to verify that a external-package-provided scoped style has actually been applied, that would be ideal. If that's too much to add at this stage, let's have an issue tracking the need for E2E coverage and make sure we do a fair amount of manual verification.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I don't know how I missed that. I'll change it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. Let's not miss the E2E test need though too, to check the style truly appears in the browser.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW there's already an E2E test that verifies styles from an RCL get applied properly: see CanUseComponentAndStaticContentFromExternalNuGetPackage in Microsoft.AspNetCore.Components.E2ETest.Tests.ComponentRenderingTest. It reads a computed style.

So it's probably not too hard to update how that test works so the style comes from a scoped CSS file.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added an E2E test for this, just took one of the styles in the TestContentPackage styles and put it on a scoped css file.

@SteveSandersonMS
Copy link
Member

Amazing work on the extensive test coverage here!

@javiercn
Copy link
Member Author

javiercn commented Sep 3, 2020

As part of doing this, would it be reasonable to update the RCL project template to make use of scoped styles now it's actually possible?

I don't want to do it until I know everything else is working fine, there should be no discussion for that update.

@javiercn javiercn force-pushed the javiercn/css-isolation-follow-ups branch from ba1655d to 0206eb6 Compare September 3, 2020 15:39
@javiercn javiercn force-pushed the javiercn/css-isolation-follow-ups branch from 0206eb6 to 831d18b Compare September 3, 2020 15:40
@javiercn javiercn marked this pull request as ready for review September 3, 2020 15:42
@javiercn
Copy link
Member Author

javiercn commented Sep 3, 2020

🆙📅

@javiercn javiercn requested a review from a team September 3, 2020 15:52
@Pilchie Pilchie added the area-blazor Includes: Blazor, Razor Components label Sep 3, 2020
@javiercn javiercn force-pushed the javiercn/css-isolation-follow-ups branch from 171bb8e to 54efc22 Compare September 3, 2020 19:11
Copy link
Member

@SteveSandersonMS SteveSandersonMS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Brilliant!

@javiercn
Copy link
Member Author

javiercn commented Sep 4, 2020

@Pilchie this is good to go

@javiercn javiercn added the ask-mode This issue / PR is a patch candidate which we will bar-check internally before patching it. label Sep 4, 2020
@Pilchie Pilchie added Servicing-approved Shiproom has approved the issue and removed ask-mode This issue / PR is a patch candidate which we will bar-check internally before patching it. labels Sep 4, 2020
@Pilchie
Copy link
Member

Pilchie commented Sep 4, 2020

Approved for .NET 5 RC2

@mkArtakMSFT mkArtakMSFT merged commit 3d38d39 into release/5.0-rc2 Sep 4, 2020
@mkArtakMSFT mkArtakMSFT deleted the javiercn/css-isolation-follow-ups branch September 4, 2020 17:54
@pranavkm pranavkm added this to the 5.0.0-rc2 milestone Sep 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-blazor Includes: Blazor, Razor Components Servicing-approved Shiproom has approved the issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants