module-federation / module-federation-examples

Implementation examples of module federation , by the creators of module federation
https://module-federation.io/
MIT License
5.51k stars 1.73k forks source link

How can I use mf in react with 「externals」? #3467

Open qiujie8092916 opened 9 months ago

qiujie8092916 commented 9 months ago

Hi, I am using module federation to build a application

my remote webpack conf:

// remote webpack
shared: {
  ...deps,
  react: {
    singleton: true,
    import: false,
    eager: false,
    version: '0',
    requiredVersion: "*"
  },
  'react-dom': {
    singleton: true,
    import: false,
    eager: false,
    version: '0',
    requiredVersion: "*"
  },
},

my host webpack conf:

// host webpack
shared: {
  react: {
    eager: true,
    singleton: true,
    requiredVersion: "16.14.0"
  },
  'react-dom': {
    eager: true,
    singleton: true,
    requiredVersion: "16.14.0"
  }
},
//...
externals: {
  react: 'React',
  'react-dom': 'ReactDOM'
},

And I use <script> to import react and react-dom from public/index.html

I got an error: image

what should I do? thanks for your help

ScriptedAlchemy commented 7 months ago

You can use

https://github.com/module-federation/universe/tree/main/packages/runtime https://github.com/module-federation/universe/tree/main/packages/enhanced or use rspack

i believe runtimePlugin will be what you want to look at writing. resolveShare might be the hook for you.

You can share the library as import:false

{react: {import:false}}

then in a runtimePlugin, you can use resolveShare hook,

OR

you can use federation runtime and init({mfConfig}).

import { init, loadRemote, loadShare } from '@module-federation/runtime';

init({
  name: '@demo/main-app',
  remotes: [],
  shared: {
    react: {
      version: '17.0.0',
      scope: 'default',
      lib: () => window.React,
      shareConfig: {
        singleton: true,
        requiredVersion: '^17.0.0',
      },
    },
    'react-dom': {
      version: '17.0.0',
      scope: 'default',
      lib: () => window.ReactDOM,
      shareConfig: {
        singleton: true,
        requiredVersion: '^17.0.0',
      },
    },
  },
});
qiujie8092916 commented 7 months ago

Are there any examples of better integration with umijs?

ScriptedAlchemy commented 7 months ago

No but I can make one, or if you have a basic host remote with the framework, send me a PR and I’ll make it do whatever you’re wanting it to do.

qiujie8092916 commented 7 months ago

No but I can make one, or if you have a basic host remote with the framework, send me a PR and I’ll make it do whatever you’re wanting it to do.

Thanks a lot. We are exploring the module federation in our project. Our projects are all based on UmiJs@3 and UmiJs@4.

3608

qiujie8092916 commented 7 months ago

In addition, the umd library may be dynamic, not limited to just react and react-dom. If using runtimePlugin, can dynamic umd libraries be passed in through function parameters? Similar to:

// webpack.config.ts
const externals = {
  react: "window.React",
  "react-dom": "window.ReactDOM",
};
// ...  
runtimePlugins: [require.resolve('./runtime.js')(externals)],
// runtime.js
import type { FederationRuntimePlugin } from '@module-federation/runtime/types';

export default function (umds): FederationRuntimePlugin {
  return {
    name: 'umd-library-shared-plugin',
    resolveShare(args: any) {
      const { shareScopeMap, scope, pkgName, version } = args;

      if (!Object.keys(umds).includes(pkgName)) {
        return args;
      }

      args.resolver = function () {
        shareScopeMap[scope][pkgName][version] = eval(umds[pkgName]);
        return shareScopeMap[scope][pkgName][version];
      };
    },
  };
}
ScriptedAlchemy commented 6 months ago

that should work. You can probbably set import: false for react and whatever else, not externals. Since resolveShare can resolve it to window for you, webpack doesnt need to know about it import:false is "externals" via federation sharing negotiation, which you can control with that runtime plugin