Open hrmcdonald opened 2 months ago
Really interesting idea. Would love to chat through this more and bring in some folks for a design discussion. Want to hop on a meetup sometime next week?
Would love to sync and discuss this some more with anyone @zackarychapple! Unfortunately we're pretty booked up next week. The week after or beyond should be fine though (September onwards). I just joined the module-federation discord and can maybe reach out to you there if that'd be easier to schedule something?
Thanks your advice , it's very usefule ,so you want mf to provider a hook which likes insert hook to control the css/js element ? Am i understand right ?
Would love to sync and discuss this some more with anyone @zackarychapple! Unfortunately we're pretty booked up next week. The week after or beyond should be fine though (September onwards). I just joined the module-federation discord and can maybe reach out to you there if that'd be easier to schedule something?
I think i shot you a dm. If not can you shoot me one zmanc
on there.
Thanks your advice , it's very usefule ,so you want mf to provider a hook which likes insert hook to control the css/js element ? Am i understand right ?
Yes, that hook actually isn't even that great because it's run completely out of context from the rest of the page. So being able to pass in some kind of function hook like this alongside a call to loadRemote
/preloadRemote
would actually even help solve that problem for us.
The goal of the callback would be the same though; be called with any <link>
elements that need to be appended to the DOM for some incoming module(s) and then implement the logic that does append them where we want them.
We might even be able to investigate loading those CSS assets JS-side to initialize them as constructed styles sheets so they could be shared across any repeat instances of a "micro-app", but that'd be a separate investigation and not a requirement.
@2heal1 here is a super simplified example to showcase the basic idea behind the scenario I outlined above. Imagine logic contained inside appContext.mount()
is just where something like a React root would be created for a component and hydrated as needed. It's not really important for the ask here.
const mountApp = async (outlet: Element, route: string) => {
const moduleMetadata = appManifest.get(route);
const shadowRoot = outlet.shadowRoot ?? outlet.attachShadow({ mode: 'open' });
const { default: remoteModuleConfig } = await loadRemote(`${moduleMetadata.scope}/${moduleMetadata.module}`, {
insertLink: (linkTag: HTMLLinkElement) => shadowRoot.append(linkTag)
});
const appContext = remoteModuleConfig();
await appContext.mount(shadowRoot);
}
The idea here is that the insertLink
callback could be passed down into the manifest loader logic and be called where that attaches link asset elements to the DOM instead of always appending them to the document head. This would let us ensure an application's styles are always loaded and scoped inside of its parent shadowRoot instead of outside of it where they cannot affect it at all.
After looking into the docs a bit more, I do see there is a plugin system for the FederationRuntime we might be able to user here it seems? I see a createScript
hook in the docs but no createLink
. It seems like there are types for a createLink
hook though, is that something public we could tap into here?
CreateLink is techincally controlled by "webpack runtime" not federation runtime. So this would be something in mini-css runtime module. We may be able to provide some way to patch the function and provide a insert hook though, maybe
CreateLink is techincally controlled by "webpack runtime" not federation runtime. So this would be something in mini-css runtime module. We may be able to provide some way to patch the function and provide a insert hook though, maybe
mini-css
as in something similar to the classic mini-css-extract-plugin
? Could you maybe point me to where in the src that occurs? When we have some time we can play around with some potential implementations until maybe y'all have time to get around to looking into this further.
Mini css has insert option. That's what controls style inject location. My runtime doesn't actually inject the css. It's the bundlers runtime. I only inject the remote, the bundler injects the chunks
Just go to mini css plugin Readme. It's one of the options.
We're using Rsbuild/Rspack everywhere for this at the moment. So if I'm understanding correctly you're referring to the CssExtractRspackPlugin right?
We have that configured on the "remotes" to log the insert
so we could see if we can work with that. While
that does get called if loaded in directly via classic remoteEntry.js
, it isn't called when the remote manifest is loaded via mf runtime (from mf-manifest.json
). When loaded via runtime is it handled by the "host's" version of the plugin I guess? We'll have to check that out.
Okay so this is with the manifest specifically?
Okay so this is with the manifest specifically?
Yes, when loaded from mf-manifest.json
the CssExtractRspackPlugin insert
hook is never called. I might be wrong, but it appears that somehow something else was loading the link assets in there. I assumed it was tied to how link assets are loaded with manifests so that they can also potentially be preloaded.
We can probably hack something around this by intercepting document.head.appendChild
calls somehow, but if it's simple enough to add a hook that works with loadRemote
/manifests that'd be nice given it seems to be bypassing the css build plugin somehow.
Clear and concise description of the problem
Issue
Today the federation runtime seems to handle the loading and insertion of CSS files on our behalf. Even in projects where we specifically remove and re-append the
CssExtractRspackPlugin
so that we can define our owninsert
callback, that seems to be ignored since the runtime appears to be loading and inserting CSS asset links instead.There are many places where this seems to possibly occur today. Essentially anywhere where
document.head.appendChild
is called to append styles. The location of where JS assets get appended shouldn't really be relevant here though.Why is this an issue?
In an MFE platform we are building out for our wider organization (with MF 2.0 and the federation runtime which are awsome so far!) we need to make use of Shadow DOMs. Each top-level "micro-app" (which we have defined as anything with it's own route/sub-routes) gets loaded into its own isolated shadow root. We need this for two reasons:
The issue here is that the Module Federation Runtime is inserting CSS asset links in the head of the document on our behalf. This leads to these styles now affecting everything except the isolated shadow root where it is needed (the opposite of what we want to have happen 😆).
Suggested solution
If we could get some kind of callback hook that we could pass to
preloadRemote
and hopefully evenloadRemote
that'd be amazing. Ideally this hook works like theinsert
function ofCssExtractRspackPlugin
where it is just called with each link element that needs to be inserted.This approach would allow us to define the implementation for how link elements get appended to the DOM. In our case this means we could append the Link elements to the shadow root created for a given micro-app, but also possibly cache it to reinsert it across multiple instances of a micro-app being initialized across the platform.
Alternative
There is not a good alternative right now. This would block us from being able to use MF manifests and any value they provide.
Eventually I assume we'd consider trying to develop some custom solution for importing CSS assets that allows us to manage them better at build and run time, but just being able to control the insertion of these seems far more simple.
Additional context
No response
Validations