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

Allow import of Blazor and DotNet JS objects from Blazor WASM startup script #48974

Closed
mvromer opened this issue Jun 22, 2023 · 3 comments
Closed
Labels
area-blazor Includes: Blazor, Razor Components design-proposal This issue represents a design proposal for a different issue, linked in the description enhancement This issue represents an ask for new feature or an enhancement to an existing one ✔️ Resolution: Duplicate Resolved as a duplicate of another issue Pillar: Technical Debt Status: Resolved

Comments

@mvromer
Copy link

mvromer commented Jun 22, 2023

Summary

As part of trying out ideas to enable multiple Blazor WebAssembly apps to co-exist on the same page (a la micro frontends as described in #38128), one thing that would be helpful is getting access to the Blazor and DotNet JavaScript objects setup as part the Blazor WASM startup script (blazor.webassembly.js) through a means other than the global window object. Ideally these objects should be retrievable when the Blazor WASM startup script is loaded dynamically, such as when lazy loading a Blazor WASM application in cases like (but not limited to) Blazor-based micro frontends.

Motivation and goals

As I mentioned in my comments here and here, my main motivation for supporting Blazor-based MFEs is to enable teams I work with who are more comfortable with Blazor to continue developing Blazor-based frontend modules that plug into an app shell at runtime in the browser to form one cohesive app portal experience. At the same time, I want to enable teams to build modules using JS-based technologies in those situations where it's more beneficial, such as when the module needs to interop heavily with JS-based components (e.g., Mapbox for maps, Highcharts for time series strip charts, Tableau for dashboards, and Cesium for geo-spatial visualization).

While I understand #38128 has been pushed out of the .NET 8 timeline, I wanted to continue investigating on my end things my teams can do in the short term to make Blazor-based MFEs more feasible. As a proof of concept, I made a set of patches to the Blazor WASM startup script (available on GitHub here), and I've been able to get some basic Blazor-based MFEs working (with a demo app published on GitHub here).

One constraint I see with my current approach is that I need to ensure that I only load one Blazor WASM app at a time, and by "load" I mean import the app's Blazor WASM startup script. The reason is I need to grab a reference to the Blazor and DotNet objects that correspond to a particular MFE so that I can properly manage its lifecycle when I mount and unmount that MFE. I believe the one-at-a-time limitation exists due to a possible race condition I call out in my demo app here, but the basic idea is that if I try to load more than one startup script at the same time, I could possibly end up in a situation where one MFE's script will overwrite window.Blazor and window.DotNet with its runtime objects before my code has had a chance to capture the corresponding references for the other MFE.

If there were a way to get these references other than through the global namespace, my belief is that this potential race condition can get mitigated.

In scope

Given a URL to a Blazor-based MFE's startup script, I would ideally like to dynamically load it from JavaScript like so and, in the process, get the Blazor and DotNet objects created when the startup script is executed by the browser:

const blazorStartup = await import(blazorStartupScriptUrl);
const mfeBlazor = blazorStartup.Blazor;
const mfeDotNet = blazorStartup.DotNet;

// Do some other MFE init, followed by...
await mfeBlazor.start(/* arguments typically passed to Blazor.start */);

I think the ideal way of exposing this would be if the Blazor startup script were a true JS module that exported the Blazor and DotNet objects. This would allow JS code to resolve those via a dynamic import using the import() syntax.

Out of scope

I'm really only considering Blazor WASM apps at this point. Other uses of Blazor really aren't in scope with this request (and I'm not sure how relevant they would be here).

Risks / unknowns

One possible challenge of switching the startup script to a JS module is that <script> tags would need to specify the type="module" attribute to ensure the script is executed as a JS module. This would likely be a breaking change for existing Blazor WASM apps.

Just as a straw man, a couple mitigations may include:

  • Provide a separate build of the script (e.g., blazor.webassembly.esm.js) that is basically the same script with exports for the Blazor and DotNet objects included.
  • Make the existing blazor.webassembly.js script simply a shim that dynamically imports the ESM variant. It sounds like based on the last paragraph on dynamic imports described here on MDN, a dynamic import of an ES module should be possible in "classic script" environments within a browser. I'm hand waving a bit here, but that should help avoid breaking existing Blazor WASM applications.

Examples

See the snippet above to get a basic idea of how I would roughly expect this import mechanism to work. For a more complete context of where I would ideally like to use this capability, the bootstrap function in my demo app offers a decent example here. In that example, I'm reading the Blazor and DotNet objects from the window object, but getting them from the module object resolved from the dynamic import of the Blazor startup script would be the ideal outcome.

@mvromer mvromer added the design-proposal This issue represents a design proposal for a different issue, linked in the description label Jun 22, 2023
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-blazor Includes: Blazor, Razor Components label Jun 22, 2023
@mkArtakMSFT mkArtakMSFT added this to the Backlog milestone Jun 29, 2023
@ghost
Copy link

ghost commented Jun 29, 2023

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.

@mkArtakMSFT mkArtakMSFT added the enhancement This issue represents an ask for new feature or an enhancement to an existing one label Jun 29, 2023
@mkArtakMSFT mkArtakMSFT modified the milestones: Backlog, BlazorPlanning Nov 5, 2023
@ghost
Copy link

ghost commented Jan 3, 2024

Thanks for contacting us.

We're moving this issue to the .NET 9 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@mkArtakMSFT
Copy link
Member

We'll address this as part of #53215

@mkArtakMSFT mkArtakMSFT closed this as not planned Won't fix, can't repro, duplicate, stale Jan 8, 2024
@mkArtakMSFT mkArtakMSFT added the ✔️ Resolution: Duplicate Resolved as a duplicate of another issue label Jan 8, 2024
@ghost ghost added the Status: Resolved label Jan 8, 2024
@ghost ghost locked as resolved and limited conversation to collaborators Feb 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components design-proposal This issue represents a design proposal for a different issue, linked in the description enhancement This issue represents an ask for new feature or an enhancement to an existing one ✔️ Resolution: Duplicate Resolved as a duplicate of another issue Pillar: Technical Debt Status: Resolved
Projects
None yet
Development

No branches or pull requests

3 participants