module-federation / core

Module Federation is a concept that allows developers to share code and resources across multiple JavaScript applications
https://module-federation.io/
MIT License
1.38k stars 206 forks source link

rspack module federation not firing onLoad and other hooks when exposed modules from other remotes are loaded #2537

Open MadaraUchiha-314 opened 3 months ago

MadaraUchiha-314 commented 3 months ago

Describe the bug

rspack rewrites the import for an exposed module from a remote to a static import rather than a dynamic import using loadRemote

This is causing 2 issues:

  1. The lifecycle hooks like onLoad and other hooks are not triggered for the exposed modules loaded
  2. Once the parent remote entry is loaded, all child remote entries are loaded by default because they are static imports and not dynamic.
    • This is a cause of concern as it has serious performance impact for large projects

Example:

I have 2 remotes:

project-a imports the button (which is an exposed module) from project-b.

import Button, { someThingElse } from 'project-b/button';

rspack converts it to this:

import * as __WEBPACK_EXTERNAL_MODULE_webpack_container_reference_project_b__ from 'https://rollup-plugin-module-federation-project-b.vercel.app/rspack/esm/my-remote-entry.js';

My rollup plugin rollup-plugin-module-federation converts it to:

const Button = (await loadRemote('project-b/button')).default;
const { someThingElse } = (await loadRemote('project-b/button'));

My implementation fixes both the bugs I mentioned above.

  1. Since exposed modules are loaded using loadRemote it fires all the hooks
  2. Since the exposed module is actually loaded only when it's required, it doesn't trigger additional network calls when the remote for project-a is loaded

Working example:

Just click on the buttons from left to right and check the console logs and the network tabs.

Reproduction

Provided above.

Used Package Manager

npm

System Info

NA

Validations

zhoushaw commented 3 months ago

I may not understand what you mean, do you mean that the resource is loaded repeatedly when the following dependencies: host -> remote-a -> remote-b, should not be added to the remote-b resource when loading remote-a @MadaraUchiha-314

MadaraUchiha-314 commented 3 months ago

I may not understand what you mean, do you mean that the resource is loaded repeatedly when the following dependencies: host -> remote-a -> remote-b, should not be added to the remote-b resource when loading remote-a @MadaraUchiha-314

Yes, that's one of the issue.

the other issue is that rspack internally doesn't use loadRemote, it just does a regular import of the remote.

ScriptedAlchemy commented 3 months ago

@MadaraUchiha-314 hoe are you configuring the remote? Rspack seems to be inlining the external url for import from. Can you share the Rspack build config

MadaraUchiha-314 commented 3 months ago

Here's the rspack bui.d config: https://github.com/MadaraUchiha-314/rollup-plugin-module-federation/blob/main/packages/examples/project-a/rspack.config.mjs

ScriptedAlchemy commented 2 months ago

@MadaraUchiha-314 does webpack handle the same? @zhoushaw @2heal1 how do we implement esm mode for federation in VMOK?

It seems that bundler will use esm http external imports for remoteType module

MadaraUchiha-314 commented 2 months ago

@MadaraUchiha-314 does webpack handle the same?

Webpack also handles it the same way that rspack does. Direct import like:

import*as __WEBPACK_EXTERNAL_MODULE_http_localhost_8080_packages_examples_project_b_dist_webpack_esm_my_remote_entry_js_46592bd8__ from "http://localhost:8080/packages/examples/project-b/dist/webpack/esm/my-remote-entry.js";
MadaraUchiha-314 commented 2 months ago

@ScriptedAlchemy Another bug that's happening due to this raw import is that when I use the mf-manifest.json to refer to a remote entry rather than the direct url, the import is something like:

import * as __WEBPACK_EXTERNAL_MODULE_webpack_container_reference_project_b__ from "http://localhost:8080/packages/examples/project-b/dist/rspack/esm/mf-manifest.json";

and I am getting the error:

Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "application/json". Strict MIME type checking is enforced for module scripts per HTML spec.

Reproducible URL: https://rollup-plugin-module-federation.netlify.app/packages/examples/project-a/dist/rspack/esm/

This means that federation 2.0 in rspack using ESM and mf-manifest.json just doesn't work!!

I think having these raw HTTP imports to externals is not the right design.

In my rollup federation, I convert these to loadRemote calls and let the federation runtime handle things and it works perfectly!

ScriptedAlchemy commented 1 month ago

Use remotetype: 'script' in the plugin

Also why use esm outputs vs normal js?