dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.2k stars 9.95k forks source link

Add a mechanism to override how Blazor's JS dynamic imports are performed #45148

Open SteveSandersonMS opened 1 year ago

SteveSandersonMS commented 1 year ago

Is there an existing issue for this?

Is your feature request related to a problem? Please describe the problem.

When you do JS.InvokeAsync("import", "./some/module.js"), the JS interop system will perform a JS dynamic import for "./some/module.js". We even recommend that package authors use this technique to load their JS dependencies dynamically so the package consumer doesn't have to add any <script> tags manually.

However, in some deployment scenarios, the app author wants to override how all static resources are loaded. The app author can control Blazor boot resource loading (e.g., .NET assemblies, our baked-in JS library, and the .wasm file) using a loadBootResource callback. But they have no comparable way to override the URL used by a JSInterop-triggered import.

Originally reported at https://github.com/dotnet/aspnetcore/issues/45104

Describe the solution you'd like

We could consider either:

  1. A general-purpose way to register a callback that handles JS dynamic import
  2. Making JS dynamic import call through the existing loadBootResource API (which is admittedly strange since those files are loaded arbitrarily when the app is running, not as part of its boot process - they aren't boot resources as per normal definition)

Additional context

A counterargument would be that JS dynamic imports are only one of many other static file types that may be loaded by a component in a package. They might also dynamically load images, CSS, JSON files via fetch, or whatever else. In all those cases you wouldn't have a way to intercept and modify their URLs, so it would be strange to special-case a feature for JS imports.

We could argue that a better, more all-encompassing solution is for such developers to implement a service worker that gives them full control over all the static resources fetched by their site.

javiercn commented 1 year ago

However, in some deployment scenarios, the app author wants to override how all static resources are loaded. The app author can control Blazor boot resource loading (e.g., .NET assemblies, our baked-in JS library, and the .wasm file) using a loadBootResource callback. But they have no comparable way to override the URL used by a JSInterop-triggered import.

Yep, we need something for JsInitializers too, since this has been brought up a couple of times.

javiercn commented 1 year ago

2. Making JS dynamic import call through the existing loadBootResource API (which is admittedly strange since those files are loaded arbitrarily when the app is running, not as part of its boot process - they aren't boot resources as per normal definition)

This won't work for Server scenarios though :(

javiercn commented 1 year ago

A counterargument would be that JS dynamic imports are only one of many other static file types that may be loaded by a component in a package. They might also dynamically load images, CSS, JSON files via fetch, or whatever else. In all those cases you wouldn't have a way to intercept and modify their URLs, so it would be strange to special-case a feature for JS imports.

I think we already "interfere" with the original request, so I think it is fair we give people control back.

javiercn commented 1 year ago

We could argue that a better, more all-encompassing solution is for such developers to implement a service worker that gives them full control over all the static resources fetched by their site.

Maybe, but how would that work on first load?

martinlingstuyl commented 1 year ago

It's a bit of an edge case maybe (or is it?), but what if you can control static clientside resources, but the server itself is out of reach? A service worker/proxy is no solution in that case.

martinlingstuyl commented 1 year ago

What I mean is that I can control the CDN or server that hosts the WASM files AND I can control static files on a website where the Blazor WASM app needs to be incorporated, but I don't control the actual website or server, so I cannot configure a proxy.

SteveSandersonMS commented 1 year ago

This won't work for Server scenarios though :(

I agree - it's not a good, general-purpose solution.

I think we already "interfere" with the original request, so I think it is fair we give people control back.

Which original request?

Maybe, but how would that work on first load?

Wait until the service worker is loaded before calling Blazor.start? Not sure if this necessitates auto-refreshing the page.

what if you can control static clientside resources, but the server itself is out of reach? A service worker/proxy is no solution in that case.

Service workers are just static content loaded from the CDN/server.

martinlingstuyl commented 1 year ago

Service workers are just static content loaded from the CDN/server.

In that case, I think I need to do some reading up!

ghost commented 1 year ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

cveld commented 4 months ago

I believe I am currently blocked with my use case:

blazor.webassembly.js currently tries to load my module myapp.lib.module.js but does that from the wrong path:

GET vscode-webview://0knolpkv5olkqn3b8frsm6kntt3sfqn3snrbojmgmbn9ucck8h2c/myapp.lib.module.js net::ERR_ACCESS_DENIED

vscode webview api provides asWebviewUri to get the correct uri. But it seems that Blazor currently does not provide means to override the base path for these dynamic imports. asWebviewUri generates https://file+.vscode-resource.vscode-cdn.net based uris.

(Side note: during development I am running the blazor wasm app on localhost. Due to cors I had to put up a simple cors proxy and loadBootResource provides a uri to there)

Is there another way to call into wasm from javascript, e.g. as part of the Blazor.start api? Or to provide any way of specific configuration?

In the meanwhile I replaced const t=document.baseURI; in blazor.webassembly.js with const t="thedesiredpath";.

FYI: these initializers get read twice. Once from blazor.webassembly.js using the baseuri; once from dotnet.js through relative paths as specified in blazor.boot.json.

I decided to set up a global JavaScript function that returns a different value per hosting environment. From wasm I call into this function early in the app's lifecycle synchronously. Thereafter the app can respond differently per hosting environment (vscode / browser).