Skip to content
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

[Static Web Assets] Runtime APIs to consume the generated endpoint manifest from the SDK #54875

Closed
Tracked by #52824
javiercn opened this issue Apr 1, 2024 · 3 comments
Assignees
Labels
api-approved API was approved in API review, it can be implemented area-blazor Includes: Blazor, Razor Components area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates
Milestone

Comments

@javiercn
Copy link
Member

javiercn commented Apr 1, 2024

We need a few runtime APIs to consume the static web asset endpoints manifest in different locations:

  • API to read the manifest and map it to a list of endpoints.
  • API to find the fingerprinted route for an asset given their "canonical" name.
  • Update Url tag helper to automatically apply fingerprinted versions where possible.
  • Razor component to use the fingerprinted version of an asset.
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates label Apr 1, 2024
@javiercn javiercn added the area-blazor Includes: Blazor, Razor Components label Apr 1, 2024
@javiercn javiercn added this to the 9.0-preview4 milestone Apr 1, 2024
@javiercn javiercn self-assigned this Apr 1, 2024
@javiercn
Copy link
Member Author

javiercn commented May 9, 2024

Static assets compression API review

Usage

// This is it, its equivalent to UseStaticFiles but endpoint aware. The vast majority of the functionality on static files is not needed for most web apps (and you can still reach for it if you need it) and this optimizes serving the known assets at compile/publish time from your app, which is the most common scenario for web apps by far.

app.MapStaticAssetEndpoints()

// You might want to specify a path to the manifest, this is useful for testing scenarios and for scenarios like web assembly, which is "its own app" hosted inside an asp.net core process.

app.MapStaticAssetEndpoints("MyWebAssemblyApp.staticwebassets.endpoints.json");

// Used to indicate webassembly the path to the manifest where its files live. It's only ever set in the case you might have more than one webassembly application.

app.MapStaticWebAssetEndpoints("<<manifest-path>>");
app.MapRazorComponents<App>()
    .AddInteractiveWebAssemblyRenderMode(options => options.AssetsManifestPath = "<<manifest-path>>")

Common APIs users interact with

namespace Microsoft.AspNetCore.Builder;

+public static class StaticAssetsEndpointRouteBuilderExtensions
+{
+    public static StaticAssetsEndpointConventionBuilder MapStaticAssetEndpoints(this IEndpointRouteBuilder endpoints, string? staticAssetsManifestPath = null);
+}
public sealed class WebAssemblyComponentsEndpointOptions
{
+    public string? AssetsManifestPath { get; set; }
}

Other APIs that are public because of layering and other aspects

Metadata added to an endpoint to indicate is compressed.

+namespace Microsoft.AspNetCore.Routing.Matching;

+public class ContentEncodingMetadata(string value, double quality)
+{
+   public string Value { get; } = value;

+   public double Quality { get; } = quality;
+}

Plumbing

public static class ComponentEndpointConventionBuilderHelper
{
+    public static IEndpointRouteBuilder GetEndpointRouteBuilder(RazorComponentsEndpointConventionBuilder builder)
}
namespace Microsoft.AspNetCore.Builder;

+public static class StaticAssetsEndpointRouteBuilderExtensions
+{
+    public static StaticAssetsEndpointConventionBuilder MapStaticAssetEndpoints(this IEndpointRouteBuilder endpoints, string? staticAssetsManifestPath = null);
+}
+namespace Microsoft.AspNetCore.StaticAssets;

+public class StaticAssetsEndpointConventionBuilder : IEndpointConventionBuilder
+{
+   public void Add(Action<EndpointBuilder> convention);
+   public void Finally(Action<EndpointBuilder> convention);
+}
+namespace Microsoft.AspNetCore.StaticAssets

+public class StaticAssetsEndpointDataSource : EndpointDataSource
+{
+      public string ManifestPath { get; }
+      public StaticAssetsEndpointConventionBuilder DefaultBuilder { get; }
      
        // From Endpoint data source
+     public override IReadOnlyList<Endpoint> Endpoints { get; }
+     public override IChangeToken GetChangeToken()
+}

@javiercn javiercn added the api-ready-for-review API is ready for formal API review - https://github.com/dotnet/apireviews label May 9, 2024
@halter73
Copy link
Member

halter73 commented May 9, 2024

API Review Notes:

  • Is MapStaticAssetEndpoints replacing UseBlazorFrameworkFiles and/or UseStaticFiles?
    • This is a UseStaticFiles replacement if all the static files are known at build time. It should work with any application using the Web SDK.
  • Does it always serve from wwwroot?
    • Yes. And it's currently not configurable. If you want to serve from somewhere else, call UseStaticFiles
    • We shied away from MapStaticResources because the files need to be in the filesystem. They are not embedded.
  • Do we have a better name for MapStaticAssetEndpoints?
    • MapStaticFiles?
      • It's similar to UseStaticFiles middleware which can both be clarifying (because they're similar) and confusing (because they aren't exactly the same since the files must be known in advance usually at compile/publish time).
      • MapStaticStaticFiles? 😛 MapPreconfiguredStaticFiles?
    • MapStaticAssets?
      • This makes it clearer that these are evaluated at publish/build time and cannot change with user uploads and the like.
      • It does sound a little too similar to "static web assets" despite not being specific to Blazor.
      • We still prefer this name.
  • Can we change the behavior so it does serve files added to wwwroot after publish like the static files middleware?
    • This does happen in development using a fallback endpoint, but not in production.
      • We should make it clear to customers that this is a development-only behavior possibly via a log.
    • Implementation-wise this would be difficult to do well in production.
  • What dll is StaticAssetsEndpointRouteBuilderExtensions going in?
    • Microsoft.AspNetCore.StaticAssets
  • Let's rename WebAssemblyComponentsEndpointOptions.AssetsManifestPath to StaticAssetsManifestPath to match the MapStaticAssets parameter name.
  • Let's move ContentEncodingMetadata to the Microsoft.AspNetCore.Routing namespace.
  • Why isn't GetEndpointRouteBuilder an extension method?
  • We're hiding it.
  • Let's seal StaticAssetsEndpointConventionBuilder.
  • Why is StaticAssetsEndpointDataSource public?
    • So we can detect in AddInteractiveWebAssemblyRenderMode whether MapStaticAssets already and can avoid calling UseBlazorFrameworkFiles.
    • The DefaultBuilder does not need to be public, but ManifestPath needs to say so the web assembly logic can see whether it matches WebAssemblyComponentsEndpointOptions.StaticAssetsManifestPath.
    • Let's seal this too.
  • And let's seal ContentEncodingMetadata too.

API Approved!

+// Microsoft.AspNetCore.StaticAssets.dll
namespace Microsoft.AspNetCore.Builder;

+public static class StaticAssetsEndpointRouteBuilderExtensions
+{
+    public static StaticAssetsEndpointConventionBuilder MapStaticAssets(this IEndpointRouteBuilder endpoints, string? staticAssetsManifestPath = null);
+}

// Microsoft.AspNetCore.Components.WebAssembly.Server.dll
namespace Microsoft.AspNetCore.Components.WebAssembly.Server;

public sealed class WebAssemblyComponentsEndpointOptions
{
+    public string? StaticAssetsManifestPath { get; set; }
}

// Microsoft.AspNetCore.Routing.dll
+namespace Microsoft.AspNetCore.Routing;

+public sealed class ContentEncodingMetadata(string value, double quality)
+{
+   public string Value { get; } = value;
+   public double Quality { get; } = quality;
+}

// Microsoft.AspNetCore.Components.Endpoints.dll
namespace Microsoft.AspNetCore.Components.Endpoints.Infrastructure;

public static class ComponentEndpointConventionBuilderHelper
{
+    public static IEndpointRouteBuilder GetEndpointRouteBuilder(RazorComponentsEndpointConventionBuilder builder)
}

+// Microsoft.AspNetCore.StaticAssets.dll
+namespace Microsoft.AspNetCore.StaticAssets;

+public sealed class StaticAssetsEndpointConventionBuilder : IEndpointConventionBuilder
+{
+   public void Add(Action<EndpointBuilder> convention);
+   public void Finally(Action<EndpointBuilder> convention);
+}

+public sealed class StaticAssetsEndpointDataSource : EndpointDataSource
+{
+      public string ManifestPath { get; }

        // From Endpoint data source
+     public override IReadOnlyList<Endpoint> Endpoints { get; }
+     public override IChangeToken GetChangeToken()
+}

@javiercn
Copy link
Member Author

51838a2

@halter73 halter73 added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for formal API review - https://github.com/dotnet/apireviews labels May 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-approved API was approved in API review, it can be implemented area-blazor Includes: Blazor, Razor Components area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates
Projects
None yet
Development

No branches or pull requests

4 participants
@halter73 @javiercn @mkArtakMSFT and others