create-react-app icon indicating copy to clipboard operation
create-react-app copied to clipboard

Support Webpack Module Federation

Open raspy8766 opened this issue 2 years ago • 15 comments

Module Federation Support

Description

This PR aims to support the Webpack 5 module federation plugin natively in CRA. Micro-frontends are becoming a more prevalent form of UI development for the enterprise environment. We love what create-react-app provides, but in order to get it working at the moment, we rely on these forked changes. Hopefully this PR has what you're looking for, if not I'm happy to make additional accommodations and open to suggestions.

Proposed Changes

  • Add a new optional setupModuleFederation.js file that manages the webpack Module Federation plugin
  • When the setupModuleFederation.js file is present, use the Module Federation plugin
  • Since Micro-frontend apps do not typically have their own index.html (unless they're using iframes), the index.html file along with the public folder are now optional.

Testing

Setup

  1. Execute the following bash script which performs the following:
    • Initializes a new CRA mfe app repo
    • Clones down and installs the forked repo
    • Installs local react-scripts from forked repo
yarn create react-app mfe-app && \
git clone https://github.com/HewlettPackard/create-react-app.git && \
yarn --cwd="./create-react-app" && \
yarn --cwd="./mfe-app" add file:../create-react-app/packages/react-scripts

Negative Test

  1. In the mfe-app repo, run yarn start
  2. Navigate to http://localhost:3000/webpack-dev-server and note the files listed appear as normal

Positive Test

  1. Create a src/setupModuleFederation.js file with the following contents:
module.exports = {
  name: 'test',
  library: { type: 'var', name: 'test' },
  filename: 'remoteEntry.js',
  exposes: { '.': './src/App.js' }
}
  1. Navigate to the mfe-app repo
  2. Delete the public/index.html file (optional)
  3. Run yarn start
  4. Navigate to http://localhost:3000/webpack-dev-server and notice the remoteEntry.js file

Screenshots

Webpack served assets:

image

remoteEntry.js file:

image

raspy8766 avatar Apr 13 '22 00:04 raspy8766

Hi @raspy8766!

Thank you for your pull request and welcome to our community.

Action Required

In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.

Process

In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.

If you have received this in error or have any questions, please contact us at [email protected]. Thanks!

facebook-github-bot avatar Apr 13 '22 00:04 facebook-github-bot

Hello Hewlett Packard!

Greetings from Domino's.

Just wanted to thank you for doing this. We've been using your fork to to build out our module federation patterns and it's been great.

Hopefully this'll get merged soon.

Edit: fixed typo

mong8se avatar May 05 '22 21:05 mong8se

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

facebook-github-bot avatar May 05 '22 22:05 facebook-github-bot

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

facebook-github-bot avatar May 05 '22 22:05 facebook-github-bot

Hi @iansu @mrmckeb, my apologies with the CLA agreement delay. Had a few hoops and hurdles to go through to get that in place. Let me know if this looks good to you guys or if you have any other recommendations. Happy to augment it further where needed. Thanks!

raspy8766 avatar May 10 '22 20:05 raspy8766

This feature is extremely interesting – to support module federation without having to use craco or use a separate webpack config. Any idea when this would show up in a release?

mikeaustin avatar Jun 09 '22 15:06 mikeaustin

@raspy8766, Thanks for sharing this!

One thing, I can't get this PR to work in the CRA development env for a Host app and a Remote app scenario without slight modification.

In the remote app, when running in the CRA development env we can not set the output.publicPath correctly in webpack.config.js. Most MF examples set output.publicPath to "auto". CRA does not allow this and it does not allow us to use a full URL in the development env.

This will cause any Remote app to use a relative path and they end up looking for their own modules inside the host that is trying to consume them. In sum, in the development env, Remote apps will have the wrong URL when you try to load their shared modules from a Host app.

webpack.config.js uses the function getPublicUrlOrPath, which gives us no control over setting output.publicPath for a Remote app within the development env.

I could be missing something, but how are you getting around this? I guess you could use a combination of setupProxy.js and the PUBLIC_URL env property to route the request back to the correct webpackDev server.

Screen Shot 2022-06-09 at 12 03 54 PM

Screen Shot 2022-06-09 at 12 06 48 PM

Screen Shot 2022-06-09 at 12 04 07 PM

SlowBurner avatar Jun 09 '22 19:06 SlowBurner

@SlowBurner that's correct, we're using the PUBLIC_URL to modify the public path setting in webpack. As you can see PUBLIC_URL is directly used to set the webpack publicPath field your looking for

raspy8766 avatar Jun 09 '22 22:06 raspy8766

@SlowBurner that's correct, we're using the PUBLIC_URL to modify the public path setting in webpack. As you can see PUBLIC_URL is directly used to set the webpack publicPath field your looking for

Cool! I got things working via PUBLIC_URL. Thanks again for the PR!

SlowBurner avatar Jun 10 '22 02:06 SlowBurner

thanks for your work on this @raspy8766 , really looking forward to seeing this get merged

kahboom avatar Jul 04 '22 09:07 kahboom

Thank you @raspy8766 for your efforts to get Module Federation support in CRA. This would help many if it gets merged.

vish30 avatar Jul 22 '22 07:07 vish30

hey, great job <3! any ideea when this is going to be merged?

cmnstmntmn avatar Aug 10 '22 14:08 cmnstmntmn

Is there an example on how to use this in a monorepo with a host and remotes?

devi-prsd avatar Aug 12 '22 16:08 devi-prsd

Great addition, would like to see it merged!

lehelp avatar Aug 24 '22 14:08 lehelp

@devi-prsd - there is a repo with many examples here that are essentially tiny monorepos: https://github.com/module-federation/module-federation-examples

If you mean a remote being deployed somewhere remotely from the host app (i.e. as static files on Netlify, GitHub pages), there is a post I wrote that explains how the setup could work, but you have to look past the business logic: https://kaoto.io/docs/add-custom-view/

Namely, in this project "step extensions" = remotes, and the URL of the remote gets passed in dynamically to the UI (host) from the API through a "view definition catalog" (basically just a configuration file).

Or if you'd really like a blog post for this topic, let me know.

kahboom avatar Aug 24 '22 19:08 kahboom

Wow, brilliant! Looking forward to seeing this merged!

tobyscott25 avatar Nov 14 '22 02:11 tobyscott25

bump

wrightmk avatar Nov 17 '22 08:11 wrightmk

I'm not able to get it to work. What am I missing? I tried creating two apps, app1 and app2 with following steps:

yarn create react-app app1 --template=typescript && \
git clone https://github.com/HewlettPackard/create-react-app.git && \
yarn --cwd="./create-react-app" && \
yarn --cwd="./mfe-app" add file:../create-react-app/packages/react-scripts

Rename index.tsx -> bootstrap.tsx index.tsx

import("./bootstrap.tsx")

app1/src/setupModuleFederation.js

const { dependencies } = require('../package.json');

module.exports = {
  name: "app1",
  library: { type: "var", name: "app1" },
  filename: "remoteEntry.js",
  exposes: {
    './hello': "./src/hello.tsx"
  },
  remotes: {},
  shared: {
    ...dependencies,
    react: {
      singleton: true,
      requiredVersion: dependencies.react,
    },
    "react-dom": {
      singleton: true,
      requiredVersion: dependencies["react-dom"],
    },
  }
}

app2/src/setupModuleFederation.js

const { dependencies } = require('../package.json');

module.exports = {
  name: "app2",
  library: { type: "var", name: "app2" },
  filename: "remoteEntry.js",
  exposes: {},
  remotes: {
    app1: "app1@http://localhost:3001/remoteEntry.js"
  },
  shared: {
    ...dependencies,
    react: {
      singleton: true,
      requiredVersion: dependencies.react,
    },
    "react-dom": {
      singleton: true,
      requiredVersion: dependencies["react-dom"],
    },
  }
}

app2/src/App.tsx

import Hello from 'app1/hello';

export default function App() {
  return <div><Hello /></div>
}

SurjitSahoo avatar Dec 09 '22 05:12 SurjitSahoo

up

douglaszaltron avatar Jan 03 '23 22:01 douglaszaltron

how long to merge?

nagarakesh4 avatar Jan 17 '23 11:01 nagarakesh4

Up again

xepozz avatar Apr 04 '23 20:04 xepozz

up, why so hard to review the damn files??

hamzamihaidanielx avatar Apr 06 '23 17:04 hamzamihaidanielx

@allocenx Agreed, also wondering what the hold-up is ... 🤔

tobyscott25 avatar Apr 07 '23 03:04 tobyscott25

Any updates on this ?

maheshrajrp avatar Apr 24 '23 23:04 maheshrajrp

Any update on this?

manohar-netomi avatar Jun 30 '23 06:06 manohar-netomi

I'm about to give up on react-scripts altogether and just use raw Webpack

tobyscott25 avatar Jun 30 '23 07:06 tobyscott25

I'm about to give up on react-scripts altogether and just use raw Webpack

cool down mate! 😅 You can try mf-cra For this same reason, I created this package and have been using it in production!

SurjitSahoo avatar Jun 30 '23 08:06 SurjitSahoo

I'm just sick of waiting on Facebook to support such a great Webpack feature when this PR has been sitting open for over a year now.

Great work on your package though, kudos! Personally, I prefer to stick to official packages, so I just made a boilerplate using raw Webpack 🙂

tobyscott25 avatar Jul 01 '23 06:07 tobyscott25

I'd rather try to add the feature I want onto the official package with a script, than writing everything from scratch.

SurjitSahoo avatar Jul 02 '23 04:07 SurjitSahoo

FB makes tons of money and they can't even review this simple thing?

AdrianGolda avatar Aug 03 '23 11:08 AdrianGolda