Skip to content

CSS from federated modules are not loading #154

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

Open
rodoabad opened this issue Oct 10, 2024 · 59 comments
Open

CSS from federated modules are not loading #154

rodoabad opened this issue Oct 10, 2024 · 59 comments

Comments

@rodoabad
Copy link

rodoabad commented Oct 10, 2024

If you have CSS files in your federated module, they do not get loaded in run time (although they do get built).

@rodoabad rodoabad changed the title CSS From Federated Modules Are Not Loading CSS from federated modules are not loading Oct 10, 2024
@rubiks-cube
Copy link

rubiks-cube commented Oct 10, 2024

Check base value in your vite config. Faced similar issue this fixed for me.

@rodoabad
Copy link
Author

Check base value in your vite config. Faced similar issue this fixed for me.

What did you setup yours with? The default is / which is why I just left mine as is.

@rubiks-cube
Copy link

Are you exposing remote after doing build/preview or in dev mode?

@gioboa
Copy link
Collaborator

gioboa commented Oct 12, 2024

@rodoabad have you solved this issue?

@rodoabad
Copy link
Author

@rubiks-cube I'm running vite preview on both host and remote.

@gioboa I haven't resolved this issue.

Another issue I'm having and is probably another issue is for some reason, some random tests fail if the build is with federation and if I remove it from plugins, it passes. I will try and create a test repository outside of our private organization .

@rubiks-cube
Copy link

rubiks-cube commented Oct 14, 2024

in preview for remote adding base to hostname for e.g. http://localhost:5173/ resolved my issue for css

@rodoabad
Copy link
Author

rodoabad commented Oct 14, 2024

in preview adding base to hostname for e.g. http://localhost:5173/ resolved my issue for css

@rubiks-cube Let me try that right now. I literally got to office and starting my IDE. LOL. Will bring you results as I go through them.

@rodoabad
Copy link
Author

rodoabad commented Oct 14, 2024

Let me share our config.

HOST

// CORE

import {defineConfig} from 'vite';
import {federation} from '@module-federation/vite';
import react from '@vitejs/plugin-react-swc';

export default defineConfig(({mode}) => {
    return {
+        base: 'http://localhost:8080/',
        build: {
            cssCodeSplit: false, // Error: Unable to preload CSS
            minify: false,
            modulePreload: false, // Prevents 403/404 errors when preloading in network tab
            target: 'esnext'
        },
        plugins: [
            federation({
                name: 'host',
                remotes: {
                    PKGA: {
                        type: 'module', // Set to `var` for Webpack and Rspack federated modules
                        name: 'PKGA',
                        entry:  mode === 'production' ? '/assets/pkg-a/remote.js' : 'http://localhost:8081/remote.js'
                    },
                    PKGB: {
                        type: 'module', // Set to `var` for Webpack and Rspack federated modules
                        name: 'PKGB',
                        entry: mode === 'production' ? '/assets/pkg-b/remote.js' : 'http://localhost:8082/remote.js'
                    },
                },
                filename: 'remote.js',
                shared: ['react', 'react-dom', 'react-intl', 'react-router-dom']
            }),
            react()
        ]
    }
});

REMOTES

// PKG A
import {defineConfig} from 'vite';
import {federation} from '@module-federation/vite';
import react from '@vitejs/plugin-react-swc';

export default defineConfig({
+    base: 'http://localhost:8081/',
    build: {
        cssCodeSplit: false, // Error: Unable to preload CSS
        minify: false,
        modulePreload: false, // Prevents 403/404 errors when preloading in network tab
        target: 'esnext'
    },
    plugins: [
        federation({
            exposes: {
                './app': './src/app.tsx'
            },
            filename: 'remote.js',
            name: 'PKGA',
            shared: ['react', 'react-dom', 'react-intl', 'react-router-dom']
        }),
        react()
    ]
});
// PKG B
import {defineConfig} from 'vite';
import {federation} from '@module-federation/vite';
import react from '@vitejs/plugin-react-swc';

export default defineConfig(async ({command}) => ({
+    base: 'http://localhost:8082/',
    build: {
        cssCodeSplit: false, // Error: Unable to preload CSS
        minify: false,
        modulePreload: false, // Prevents 403/404 errors when preloading in network tab
        target: 'esnext'
    },
    plugins: [
        federation({
            exposes: {
                './app': './src/app.tsx'
            },
            filename: 'remote.js',
            name: 'PKGB',
            shared: ['react', 'react-dom', 'react-intl', 'react-router-dom']
        }),
        react()
    ],
    test: {
        coverage: {
            enabled: true
        },
        css: {
            modules: {
                classNameStrategy: 'non-scoped'
            }
        },
        environment: 'happy-dom',
        globals: true,
        include: ['**/__tests__/unit/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
        setupFiles: [
            '__tests__/unit/__helpers__/setup-test-framework.ts'
        ]
    }
}));

@rubiks-cube With this setup, PKG A and PKG B CSS still doesn't get loaded.

@rubiks-cube
Copy link

rubiks-cube commented Oct 15, 2024

entry: mode === 'production' ? '/assets/pkg-a/remote.js' : 'http://localhost:8081/remote.js' in preview (production mode) host will fetch remoteentry from '/assets/pkg-a/remote.js'. I think in this case css for remote is trying to load from http://localhost:8080/. Can you add hostname for remote in which preview is running like you have done for development mode in host config?

@rodoabad
Copy link
Author

rodoabad commented Oct 15, 2024

entry: mode === 'production' ? '/assets/pkg-a/remote.js' : 'http://localhost:8081/remote.js' in preview (production mode) host will fetch remoteentry from '/assets/pkg-a/remote.js'. I think in this case css for remote is trying to load from http://localhost:8080/. Can you add hostname for remote in which preview is running like you have done for development mode in host config?

Update! Still doesn't work, @rubiks-cube. I basically replaced entry with just http://localhost:8081/remote.js and http://localhost:8082/remote.js respectively for PKG A and PKG B, since I'm running local servers for preview.

@rubiks-cube
Copy link

can u check in network tab in devtools from which location browser is trying to load remote app css?

@rodoabad
Copy link
Author

rodoabad commented Oct 15, 2024

can u check in network tab in devtools from which location browser is trying to load remote app css?

It's not requesting any of the CSS files.

demo

Notice in PKG A and PKG B the CSS is messed up? That's the missing CSS not loading.

PKG A for example is supposed to look like this.

Screenshot 2024-10-15 at 2 20 14 PM

@rubiks-cube
Copy link

can u confirm if PKG A dist folder has CSS files and these CSS files are getting imported in JS files in dist folder?

@rodoabad
Copy link
Author

rodoabad commented Oct 15, 2024

Screenshot 2024-10-15 at 2 38 13 PM

@rubiks-cube It's there.

@rubiks-cube
Copy link

is style-CpnI5EpU.css being imported in any of JS files in this dist folder?

@rodoabad
Copy link
Author

@rubiks-cube Yup!
Screenshot 2024-10-15 at 2 42 52 PM

If I go to localhost:8081/pkg-a I see the CSS loading.

@rubiks-cube
Copy link

For me same thing was happening css was loading fine for remote in isolation but not when used inside host. After debugging I find out host was trying to load remote css from its own hostname, updating base fixed for me. Can you check which JS file in dist is importing this CSS file and try debugging that JS file in devtools if it is making request for that CSS?

@gioboa
Copy link
Collaborator

gioboa commented Oct 15, 2024

Can you share your repo @rubiks-cube ?
This will definitely help

@rodoabad
Copy link
Author

@rubiks-cube , @gioboa I think I HAVE AN IDEA. The suggestion to look at the dist to actually check if it's being loaded was an awesome suggestion. Because, when I looked, it was being loaded in the development index.html file for PKG A. That file is never loaded in CORE. CORE has it's own index.html file.

Note: BTW, if you're not seeing "/assets", I change assets directory to jus ..

Screenshot 2024-10-15 at 3 04 12 PM

@rubiks-cube
Copy link

Sorry but I am working in private repo of my org which I can't share here

@rodoabad
Copy link
Author

So yeah, I think that's the problem. If we're not building a lib, Vite needs an index.thml and if we are importing CSS, it will add that style tag in the index.html of the package. However, since it's federated, it won't be using the index.html from PKG A. It will however use the index.html from CORE. But Core is being built elsewhere and has no idea it needs to add that CSS file, unless PKG A will add it later on.

@rubiks-cube
Copy link

For me I am not building a lib but still css doesn't get injected by default in index.html. are u using some plugin that is doing that?

@rodoabad
Copy link
Author

For me I am not building a lib but still css doesn't get injected by default in index.html. are u using some plugin that is doing that?

Nah bruv. Whatever config I have. That's it.

@rull3211
Copy link

Im also having problems with the css not being injectedon origin js i didnt have this problem

@gioboa
Copy link
Collaborator

gioboa commented Oct 22, 2024

@rull3211 do you have a public repo to share?

@rull3211
Copy link

@gioboa i can try to make one, its an org repo but i can export it :)

@rull3211
Copy link

rull3211 commented Oct 22, 2024

@gioboa https://github.com/rull3211/demo-cssbug hey this repo reporduces it :) the remote running by it self successfully injects the styling but when fetched with host the stylesheet isnt invoked.

I have tried with running the remote both with the server.js npm run preview:server and with running just the normal preview.

and same with the host i have run it both with server, preview and with run dev none of the alternatives work.

I have also tried with and without the baseurl. all of the alternatives have worked with origin js if u are wondering. :)

If ypu need anything from me you can also contact me on Discord.

i appreciate the help cheers! :)

@gioboa
Copy link
Collaborator

gioboa commented Oct 22, 2024

I tested your app and the problem here is the hot module reload of the remote app.
If I change the scss of the remote and then I refresh the host everything is working fine.
The remote app is working great with HMR too.
so it's a different issue.

@rull3211
Copy link

rull3211 commented Oct 22, 2024

Im a bit confused now i dont exactly understand. i have the problem when i serve the host and remote with the node server too o.O what am i doing wrong?

OHH snap! i havent tried that lol. yeahh when i serve the remote with npm run dev then the css works. but when i serve it after building the project then the css doesnt get sent with the component

@gioboa
Copy link
Collaborator

gioboa commented Oct 22, 2024

I'll send you a message on discord

@rasmus0201
Copy link

I seem to have the same problem. Running the vite dev server npm run dev works fine, as the styles are automatically imported into the <head>, but when running a production build (ie. npm run build and npm run preview) the styles are gone. The styles do get build into a style.css file, but is not imported in the federated module..

For now i solved it using this plugin vite-plugin-css-injected-by-js that injects the content of the styles into the entrypoint so it looks like:

(function() {
  "use strict";
  try {
    if (typeof document != "undefined") {
      var elementStyle = document.createElement("style");
      elementStyle.appendChild(document.createTextNode(`--- content of build style.css ---`));
      document.head.appendChild(elementStyle);
    }
  } catch (e) {
    console.error("vite-plugin-css-injected-by-js", e);
  }
})();
import { init } from "./remoteEntry.js";
init();

It would be great if this library could ensure styles are loaded - also preferebly via an option to append styles to the <head> or using <link> because in my use case I'm limited by the host having a very restrictive CSP regarding loading files..

@rull3211
Copy link

rull3211 commented Oct 22, 2024

@rasmus0201 make sure to remove cssCodeSplitting from your config if you have it that helped for me.

    modulePreload: false,
    target: "esnext",
    minify: false,
    cssCodeSplit: false, <-Remove this
  },

@gioboa
Copy link
Collaborator

gioboa commented Oct 22, 2024

@rodoabad Did you solve the original issue?

@rasmus0201
Copy link

rasmus0201 commented Oct 22, 2024

@rull3211 I'm not using cssCodeSplit and i'm building in library mode so it should be disabled per https://vite.dev/config/build-options.html#build-csscodesplit. But I can see I got something wrong, the npm run preview mode is working correctly, because it uses the index.html file that vite builds, which loads the dist CSS file! But when using the remote component on the host, it will not use that index.html file, thus production builds don't have any styles.

My vite config looks something like:

plugins: [
  federation({
    name: "webComponent",
    filename: `remoteEntry.js`,
    exposes: {
      "./WebComponent": "./src/index.ts"
    },
    shared: {
      vue: {
        singleton: true,
        requiredVersion: packageJson.dependencies["vue"]
      }
    }
  }),
  vue(),
  // cssInjectedByJsPlugin() // Styles are not injected by Module Federation in library mode, this plugin inserts the styles into the entry
],
define: {
  "process.env.NODE_ENV": JSON.stringify("production")
},
build: {
  emptyOutDir: true,
  minify: false, // Why does module federation break when minify is enabled?
  modulePreload: false,
  target: ["es2022"],
  assetsDir: "",
  lib: {
    name: process.env.PUBLIC_UNIQUE_NAME,
    fileName: "index",
    entry: "./src/index.ts",
    formats: ["es"]
  },
  rollupOptions: {
    input: {
      // Necessary to also include index.html in the build,
      // This allows preview mode to work in "vite library mode" and then playwright can load the page
      // But isn't used by the host 
      // @see https://github.com/vitejs/vite/issues/7009#issuecomment-1963123981
      "index.html": "index.html"
    }
  }
},
server: {
  port: 8080
},
preview: {
  port: 8080
}

Hope this make it clearer and is aligned with the original issue (I think it does, see also this reply #154 (comment))

Appreciate the help!

@rodoabad
Copy link
Author

@rodoabad Did you solve the original issue?

@gioboa Nope. I've done every suggestion in this thread and I have not resolved this issue.

@rodoabad
Copy link
Author

But when using the remote component on the host, it will not use that index.html file, thus production builds don't have any styles.

@rasmus0201 This is exactly what I highlighted in my previous posts. The host does not care about the other index.html files from the remotes which unfortunately has the CSS files injected from the remotes.

@gioboa
Copy link
Collaborator

gioboa commented Oct 22, 2024

@rodoabad Can you share a basic repository with your issue please? I'll look at it

@rodoabad
Copy link
Author

@gioboa have you tried https://github.com/rull3211/demo-cssbug/tree/main from @rull3211 ? That repo and the repo I'll make will most likely have the same config. It's as basic as it gets.

I'll try and make one still though if you want.

@gioboa
Copy link
Collaborator

gioboa commented Oct 22, 2024

@rodoabad Thanks, we solved @rull3211's issues with cssCodeSplit and base config

@rasmus0201
Copy link

@gioboa I'm also happy to share a repository, if you still need it!

Thank you for looking into this issue :)

@gioboa
Copy link
Collaborator

gioboa commented Oct 24, 2024

@rasmus0201 yep, share your repo please.

@michael-gee
Copy link

@gioboa is there a place to see the before / after for what resolved @rull3211's issue? I'm experiencing the issue and wondering if I can resolve it with the same fix

@danielBence
Copy link

danielBence commented Oct 24, 2024

Rull 3211 here from workprofile @michael-gee in your vite.config remove the line cssCodeSplit

@michael-gee
Copy link

michael-gee commented Oct 25, 2024

ahh ok, thank you @danielBence - my fix was setting the base properties to the correct value

@rasmus0201
Copy link

@gioboa I've created a repo here https://github.com/rasmus0201/demo-mf-style-missing

STR:

  1. Clone repositories npm install
  2. in /remote run npm run preview in /host run npm run dev.
  3. If you open http://localhost:8080 - it has the styles
  4. If you open http://localhost:5173/ the remote app has no styles
  5. If you uncomment this line https://github.com/rasmus0201/demo-mf-style-missing/blob/665e8b0c60c5bb3d60269fea0fcdf0efe0181242/remote/vite.config.ts#L18 and run npm run preview again, then in the host app you will now have styling, as the stylesheet are being injected into the entrypoint.

Note that if you run npm run dev on both host and remote, you don't need that plugin as the vite-dev server automatically injects style tags into the host <head> - you can try and inspect the webpage.

Note that the stylesheet is being compiled to the dist folder, but module federation doesn't reference it anywhere, it would be nice if it could load the stylesheet into the <head> or using a <link> or embedded in a <style> - maybe it could be an option in the vite plugin?

Thank you!

@Symyon
Copy link

Symyon commented Nov 10, 2024

Same thing here, can't make the style to work. It seems everything that is in the App.css will work, what's in index.css will not. I tried different option with cssCodeSplit and not, with setting different base path, with running dev and building and preview it. Nothing will work.
For context, I'm using a custom class to avoid css collision.
The ultimate goals is to use tailwind, but for now at least a custom defined class.

By the way, I got Tailwind by safelisting used class from remote into the host, but now if I want to add a prefix to the remote tailwind classes, it will not work, hence I am trying to have a simple css example work first.

@SimionPQX
Copy link

Got it working.

The reason CSS was missing is that Tailwing CSS was setup in index.css and not in the app.css. And as the first one is not getting into the code shared by the remote, but the later does. So I moved @tailwind utilities; in App.css. Left everything else in index.css, as for example @tailwind base will reset the CSS and the host is going to lose some overwrites, if MFE is loaded. Now I get all used Tailwind classes in to the built css that is shared.

For collision I used a solution combining a postCss plugin called postcss-prefixer and an utility function that will add a prefix to the css classes in code. (taken from here: https://malcolmkee.com/blog/using-tailwindcss-with-module-federation/ )

@Judd2000
Copy link

We are seeing this issue in our code base as well. Tried all solutions mentioned here, but still no luck.

@Symyon
Copy link

Symyon commented Nov 21, 2024

@Judd2000 build your project and check your 'build/dist' folde, check the css files in there and verify if your css classes are inside. I will start with that.

@harrisKAsher
Copy link

Hi, Judd2000 works with me. I had a Demo for a different issue and I have updated it so you can see the reproduction here.

If you run npm run dev then go to localhost:3000 you will see that the words "Host App" is blue and the words "Core App" is red. Then if you run npm run build then npm run preview and check out localhost:3000 you will see that the words "Host App"are still blue, but "Core App" is no longer red.

You can check the dist directory for each app and find in the assets directory there is a css file that contains the tailwind styles, just search for text-blue-500 in the host app and text-red-500 in the core app. They are both there, but despite that the remote app, core, does not have its styling showing.

Also I have tried the above suggestions and have not been able to find a solution that works to resolve this for us.

@andrei10k
Copy link

andrei10k commented Nov 25, 2024

Same for me

L.E i managed to make it work. similar to some of the comments above: i added the base config and removed cssCodeSplit from each remote

@PaRoxUs
Copy link

PaRoxUs commented Nov 29, 2024

I tried the module-federation/vite plugin because the @originjs/vite-plugin-federation started to have an serious issue with the cmdk package.

At the beginning I also encountered the missing style issue. I solved it by:

  1. Setting the base to 'http://localhost:XXXX' instead of '/'
  2. removing cssCodeSplit: false
  3. creating a component to import the style.css that I then imported in the hosting app.

No rollupOptions or cssInjectedByJsPlugin needed. But hopefully there wont be a need for this hack in the future.

@harrisKAsher
Copy link

Okay, I thought I tried what @PaRoxUs suggested but apparently I did something wrong.

Trying again I actually have got things working on my project with just step 1 and 2. Having the import of the styles.css then in a component that is imported with federation.

@frolovsky
Copy link

frolovsky commented Dec 12, 2024

I have the same problem, in my case base won't help, because I connect remotes in runtime. Therefore, in cases, when you plan to connect in runtime, at the moment I see the solution only in cssInjectedByJsPlugin.

P.S. I also do migration from @originjs/vite-plugin-federation
P.S.S under hood @originjs/vite-plugin-federation by default append styles to <head>

@PaRoxUs
Copy link

PaRoxUs commented Dec 13, 2024

Okay, I thought I tried what @PaRoxUs suggested but apparently I did something wrong.

Trying again I actually have got things working on my project with just step 1 and 2. Having the import of the styles.css then in a component that is imported with federation.

Yeah, you do not need to create an extra component if you import the style to another component you host. I use a StyleProvider component where I import the styles to also wrap components and pages so that the correct styles get applied and to make sure portals are rendered within the styling scope.

@pcfreak30
Copy link

related #257

@vnmadhusudhan2
Copy link

still waiting for the solution

@ericdong79
Copy link

Just want to share a solution for my case below:

  • In the consumer app I am using runtime @module-federation/enhanced/runtime to registerRemotes and loadRemote
  • The producer is bundled with @module-federation/vite
  • Initially the exposed JS is loaded, but the css imported in the module is not loaded and taking effect
  • I can see network requests errors for the css and several other js files

My solution

  • Noticed this the source code vite/src/utils/normalizeModuleFederationOptions.ts saying: We are ignoring the getPublicPath options because they are natively supported by Vite ...
  • Added below in my vite config:
plugins: {/* ... */},
build:{
 /* build otpions*/
},
experimental: {
    renderBuiltUrl(filename, { hostType }) {
      if (hostType === "js") {
        // For JS files, use runtime code similar to getPublicPath
        return {
          runtime: `window.__REMOTE_HOST__? (window.__REMOTE_HOST__ + "${filename}") : "/${filename}"`,
        };
      }
      // For other file types (css, html), use relative paths
      return { relative: true };
    },
  },
....
  • In the consumer app, assigned window.REMOTE_HOST variable in the runtime (I assigned it when I call init).

@elyasaf755
Copy link

I tried multiple permutations from this thread and eventually got it work with these build config:

build: {
      ...
      target: "esnext",
      minify: false,
      modulePreload: false,
}

make sure you remove cssCodeSplit: false if you have it in the build object, and remove cssInjectedByJsPlugin from the plugins array if you have it there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests