Skip to content

[Blazor] Get rid of Blazor.boot.json and use a different strategy to flow the environment. #59456

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
4 tasks done
javiercn opened this issue Dec 12, 2024 · 4 comments
Closed
4 tasks done
Assignees
Labels
area-blazor Includes: Blazor, Razor Components Priority:1 Work that is critical for the release, but we could probably ship without
Milestone

Comments

@javiercn
Copy link
Member

javiercn commented Dec 12, 2024

Blazor webassembly environment can be configured through a response header on blazor.boot.json or directly within the call to Blazor.start in code. The environment typically flows from the ASPNETCORE_ENVIRONMENT on the server.

This approach is problematic because two reasons:

  • We can't fingerprint blazor.boot.json the same way we do for other files (we can't leverage the importmap), and we always need to request it to the server bypassing the cache to ensure it's up to date (because it's not fingerprinted).
  • Setting a header for blazor.boot.json is not always possible in standalone scenarios (like when hosting on Github pages), it's also environment dependent and hard to do.

We want blazor.boot.json to become boot.js as when it's an ES6 module, it can be easily fingerprinted by an importmap on hosted scenarios as well as on standalone scenarios by rewriting index.html and using a servicer-worker.

We can write the environment directly inside boot.js and allow the app to override it in a couple of ways:

  • We can use a comment in the document as we emit the initial response.
  • We can use a meta tag in the head.

For standalone scenarios, we can read the environment from launchSettings.json during build and place it on boot.js and we can read/take the environment from an MSBuild property at publish time.

With this, we bypass issues like #25152 and we make it possible for the entire resource load chain to be fingerprinted, avoid having to make uncached requests, and have a simpler deployment independent mechanism for flowing the environment.


Implementation plan

  • Create the feature as opt-in
  • Update tests in SDK & aspnetcore repo tests to opt-in when the feature flows into the repo
  • Make the feature opt-out
  • Remove explicit opt-in from SDK & aspnetcore repo tests
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-blazor Includes: Blazor, Razor Components label Dec 12, 2024
@javiercn javiercn added this to the .NET 10 Planning milestone Dec 12, 2024
@danroth27 danroth27 added the Priority:1 Work that is critical for the release, but we could probably ship without label Jan 13, 2025
@danroth27 danroth27 changed the title [Blazor] Getting rid of Blazor.boot.json and using a different strategy to flow the environment. [Blazor] Get rid of Blazor.boot.json and using a different strategy to flow the environment. Feb 5, 2025
@danroth27 danroth27 changed the title [Blazor] Get rid of Blazor.boot.json and using a different strategy to flow the environment. [Blazor] Get rid of Blazor.boot.json and use a different strategy to flow the environment. Feb 5, 2025
@maraf
Copy link
Member

maraf commented Feb 11, 2025

A sample of boot.js

import * as runtimeModule from "./dotnet.runtime.js";
import * as nativeModule from "./dotnet.native.js";
import nativeWasm from "./dotnet.native.wasm";
import coreLibWasm from "./System.Private.CoreLib.wasm";
import interopJavaScriptWasm from "./System.Runtime.InteropServices.JavaScript.wasm";
import mainAssemblyWasm from "./MySampleApp.wasm";

export const config = {
  "mainAssemblyName": "MySampleApp.dll",
  "assets": [
    {
        name: "dotnet.runtime.js",
        moduleExports: runtimeModule,
        behavior: "js-module-runtime"
    },
    {
        name: "dotnet.native.js",
        moduleExports: nativeModule,
        behavior: "js-module-native"
    },
    {
        name: "dotnet.native.wasm",
        resolvedUrl: nativeWasm,
        hash: "...",
        behavior: "dotnetwasm"
    },
    {
        name: "System.Private.CoreLib.wasm",
        virtualPath: "System.Private.CoreLib.wasm",
        resolvedUrl: coreLibWasm,
        hash: "...",
        behavior: "assembly",
        isCore: true
    },
    {
        name: "System.Runtime.InteropServices.JavaScript.wasm",
        virtualPath: "System.Runtime.InteropServices.JavaScript.wasm",
        resolvedUrl: interopJavaScriptWasm,
        hash: "...",
        behavior: "assembly",
        isCore: true
    },
    {
        name: "MySampleApp.wasm",
        virtualPath: "MySampleApp.wasm",
        resolvedUrl: mainAssemblyWasm,
        hash: "...",
        behavior: "assembly"
    }
  ],
  "globalizationMode": "invariant"
}

In this shape, both webpack & rollup can be configured to treat .wasm imports as static files to fingerprint & copy to output directory. For building without javascript bundler in play, we can output javascript consts instead of imports for .wasm files. So there will be a MSBuild property for switching between modes.

-import nativeWasm from "./dotnet.native.wasm";
-import coreLibWasm from "./System.Private.CoreLib.wasm";
-import interopJavaScriptWasm from "./System.Runtime.InteropServices.JavaScript.wasm";
-import mainAssemblyWasm from "./MySampleApp.wasm";
+const nativeWasm = "/_framework/dotnet.native.wasm";
+const coreLibWasm = "/_framework/System.Private.CoreLib.wasm";
+const interopJavaScriptWasm = "/_framework/System.Runtime.InteropServices.JavaScript.wasm";
+const mainAssemblyWasm = "/_framework/MySampleApp.wasm";

The shape of the config object is up to consideration, this is what we currently support.

@pavelsavara
Copy link
Member

pavelsavara commented Feb 11, 2025

The shape of the config object is up to consideration, this is what we currently support.

I think we also support the more dense shape with name:hash, right ?

    "jsModuleNative": {
-      "dotnet.native.pvtfqc5zg4.js": "sha256-BV+jiq5AAz8QOm12mgaURLuSAgk201zTAloqhtKSNhU="
+      "dotnet.native.pvtfqc5zg4.js": nativeWasm
    },

We could teach it that instead of hash, there is a ES6 module object. But I like the ability of the larger scheme to add other metadata to each asset.

In both cases we don't verify the integrity anymore. I guess that's OK for bundler, but I would love to have keep it working for non-bundled scenario.

@maraf
Copy link
Member

maraf commented Feb 11, 2025

In both cases we don't verify the integrity anymore. I guess that's OK for bundler, but I would love to have keep it working for non-bundled scenario.

The integrity will remain there. I omitted it here because it was created manually

@maraf
Copy link
Member

maraf commented Mar 19, 2025

Being friendly to javascript bundlers is moved to dotnet/runtime#77191

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 Priority:1 Work that is critical for the release, but we could probably ship without
Projects
None yet
Development

No branches or pull requests

4 participants