module-federation / module-federation-examples Goto Github PK
View Code? Open in Web Editor NEWImplementation examples of module federation , by the creators of module federation
Home Page: https://module-federation.io/
License: MIT License
Implementation examples of module federation , by the creators of module federation
Home Page: https://module-federation.io/
License: MIT License
I saw that the useServiceContext in the shared-routing is using normal static import.
My code has extensive code splitting and stuff and turns out I can even use static import for my federated React components! However, changing the import in the basic example to static import won't work.
So, I am wondering under what circumstance it is ok to use static import with federated module?
Update: the basic-host-example actually can use static import as well, I might have mistaken. Just like @ ScriptedAlchemy answered below, it's a performance consideration, not webpack module federation requirement.
Hey,
I am trying to use a federated module in a personal project I am doing and I am running into issues. My webpack configuration is a bit different than ones in the examples but the federated modules part is exactly the same. The setup:
Two apps:
new ModuleFederationPlugin({
name: "dashboardshell",
library: { type: "var", name: "dashboardshell" },
filename: "remoteEntry.js",
exposes: {},
remotes: {
uicomponents: "uicomponents",
},
shared: ["react", "react-dom"],
}),
new ModuleFederationPlugin({
name: "uicomponents",
library: { type: "var", name: "uicomponents" },
filename: "remoteEntry.js",
exposes: {
Navbar: "./src/Navbar",
},
shared: ["react", "react-dom"],
}),
Both are react apps.
The error I am seeing is when I load up localhost:3001 is:
jsonp chunk loading:69 GET http://localhost:3001/static/js/src_Navbar_tsx.chunk.js net::ERR_ABORTED 404 (Not Found)
__webpack_require__.f.j @ jsonp chunk loading:68
(anonymous) @ ensure chunk:5
__webpack_require__.e @ ensure chunk:4
Navbar @ container-entry:3
get @ container-entry:9
(anonymous) @ remotes loading:31
__webpack_require__.f.remotes @ remotes loading:15
(anonymous) @ ensure chunk:5
__webpack_require__.e @ ensure chunk:4
./src/index.ts @ index.ts:1
__webpack_require__ @ bootstrap:17
(anonymous) @ startup:3
(anonymous) @ startup:5
jsonp chunk loading:45 Uncaught (in promise) ChunkLoadError: Loading chunk src_Navbar_tsx failed.
(error: http://localhost:3001/static/js/src_Navbar_tsx.chunk.js)
while loading "Navbar" from webpack/container/reference/uicomponents
at Object.__webpack_require__.f.j (http://localhost:3002/remoteEntry.js:215:29)
at http://localhost:3002/remoteEntry.js:101:40
at Array.reduce (<anonymous>)
at Function.__webpack_require__.e (http://localhost:3002/remoteEntry.js:100:67)
at Object.Navbar (http://localhost:3002/remoteEntry.js:17:30)
at Object.get (http://localhost:3002/remoteEntry.js:23:23)
at http://localhost:3001/static/js/bundle.js:9901:89
at Array.forEach (<anonymous>)
at Object.__webpack_require__.f.remotes (http://localhost:3001/static/js/bundle.js:9885:36)
at http://localhost:3001/static/js/bundle.js:9811:40
__webpack_require__.f.j @ jsonp chunk loading:44
...
The code can be seen here
Let me know if you need anything else.
Hey there,
First of all I want to say thank you! Module federation sounds awesome and makes me excited already.
There is one thing that keeps me busy thinking.
In my opinion, being able to run multiple react versions, or different frameworks at the same time is exactly what would be an important point to solve. I think one of the best advantages of micro frontend apps is that they should be independent of each other. Things like shadow dom and custom components give us tools to wire all the things up. If you still require the same version in all applications/repositories, you still have similar issues like you would have running a monolithic application. Let's say you have 20 applications, and you want to update to the new react version, you need to make all applications ready and do a big bang release. I think it's an important thing to solve. Updating react applications should be as easy as migrating and exploring to other non react framework.
It feels like it should be solvable. You can render an external react application in another react application. That sounds weird but it just works and it also works with non react freameworks. To achieve more independence, the exported component should tell the consumer how to render the requested page. So they basically should only export a single method called render(targetRootDivId). Now, a consumer can render all the micro pages and ask the components to render themself. What react version is used behind the scenes should not be important. There are probably a lot more issues that comes with this higher level of abstraction, but the benefits you get can be amazing.
What do you think about it?
Thank you for this great invention. It opens up so much possibilities!
For the basic-host-remote example, it looks like I can comment out the whole shared config and I also change to not use bundle-loader or dynamic import, the app button2
still works fine, so what have happen when I did those change? Is this ok thing to do if I don't need omnidirectional host?
I know that at some point @ScriptedAlchemy will be adding an example of module federation with next js. I wanted to get familiar with it and hence was trying to make it work with next js.
Here is the sample project that I am working on:
https://github.com/hkundnani/nextjs-mfe-demo
It's not much, I was just trying to see if I can load another component into my app but I am getting an error where my main app (app-01) can't find the component (app-02)
I have added a line like this to load the component
const MyComponent2 = dynamic(() => import("app_02/MyComponent2"));
but it can't find app-02 and results in error.
Hi,
I am wondering the reason why all examples are using html-webpack-plugin off a github repo, is that related to Module Federation?
Sincerely,
version
"webpack": "5.0.0-beta.16",
"webpack-cli": "3.3.11",
config
new ModuleFederationPlugin({
name: "app1",
library: { type: "var", name: "app1" },
remotes: {
app2: "app2",
},
shared: ["react", "react-dom"],
}),
run
webpack --mode production
The modules of the share configuration are packaged into main.js(react、react-dom)
Shouldn't the shared configuration module generate chunks?
The expected build result is this
Is there a way to bust a cached version of the remoteEntry.js
file without rebuilding the host?
If so, can we get an example on how it can be achieved?
MFE is a great idea, I'm trying to learn it.
When I see code like this https://github.com/module-federation/module-federation-examples/blob/master/basic-host-remote/app1/src/App.js#L3
const RemoteButton = React.lazy(() => import("app2/Button"));
a question just pop up, do we really need React.lazy
and dynamic import here?
We know the js file is already put into HTML as a <script>
tag, we expect the js should be loaded before this code executing.
So, I try to remove React.lazy
and change it to
import RemoteButton from "app2/Button";
It just works.
So, anything I missed?
as the number of examples grow, its getting very hard to verify everything works as i update dependencies.
If anyone would be willing to create a jest test that loops over the examples directory and runs a yarn build
if the build doesn't error, its a pass.
I have tried to put together a demo but no luck something wrong while exposing component https://github.com/anish2690/mfe-webpack-demo-vue
The Rollup demo at https://github.com/module-federation/module-federation-examples/tree/master/rollup-federation-demo doesn't work.
The instructions state you should run yarn start
but there is no package.json
file in the directory.
In addition, manually running yarn
and yarn start
in both directories starts up servers but browsing to both URLs results in various console errors and nothing being shown.
Could you please fix this?
Hi,
I opened the same issue in the book but did not get any attention, so, sorry for repeating. I was asking if there is a way to expose named exports?
I've used the Next.js sidecar example and expanded to add a ThemeProvider from an internal component library that uses Emotion for styling.
// _app.tsx
import Head from "next/head";
import { theme, Global, ThemeProvider } from '@internal/component-library';
export default function MyApp({ Component, pageProps }) {
return (
<ThemeProvider theme={theme}>
<Head>
<Global />
<script src="http://localhost:8081/remoteEntry.js" />
</Head>
<Component {...pageProps} />
</ThemeProvider>
);
}
// index.tsx
import { lazy, Suspense } from "react";
import { dependencies } from "../../package.json";
const RemoteComponent = ({ scope, module, ...props }) => {
if (!global[scope]) {
return null;
}
global[scope].init({
react: {
[dependencies.react]: {
get: () => Promise.resolve().then(() => () => require("react")),
},
},
});
const Component = lazy(() =>
global[scope].get(module).then((factory) => factory())
);
return (
<Suspense fallback={null}>
<Component {...props} />
</Suspense>
);
};
export default function Home() {
return (
<div>
<RemoteComponent scope="searchTeam" module="./ProductDetailsCard" propertyBedrooms="3" propertyId="12324" />
</div>
);
}
// ProductDetailsCard.tsx
import React, { Component } from "react";
import { CardComponent } from '@internal/component-library';
const ProductDetailsCard = () => (
<CardComponent
isPremium={true}
/>
)
export default ProductDetailsCard;
The above error occurred in the <Context.Consumer> component:
in Styled(div) (created by CardComponent)
in CardComponent (created by Context.Consumer)
in Styled(CardComponent) (created by ProductDetailsCard)
in ProductDetailsCard (at pages/index.tsx:23)
in Suspense (at pages/index.tsx:22)
in RemoteComponent (at pages/index.tsx:31)
in div (at pages/index.tsx:30)
in Home (at _app.tsx:12)
in ThemeProvider (at _app.tsx:6)
in MyApp
in ErrorBoundary (created by ReactDevOverlay)
in ReactDevOverlay (created by Container)
in Container (created by AppContainer)
in AppContainer
in Root
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.
Any help would be very appreciated !
Update from @ScriptedAlchemy - https://www.npmjs.com/package/@module-federation/typescript has been released
I can see a disadvantage using remotes libraries vs the classical libraries where e.g. typescript can be used to enforce strong types. The current typescript example defines a generic app2/Button
which is similar defining a any
type.
module-federation-examples/typescript/app1/src/app2.d.ts
Lines 3 to 7 in cf2d070
As the remote var does not have type, I don't see a way to benefit from the app2
types in app1
. Any idea on this?
This is not even a issue request, but we are testing in our company (SAP) this module federation Idea, on one of the critical project and right now. It is at the phase of POC, where we cannot go over simple usecases to get it working.
Right now we need to show-case we can do page to page navigation, technology page mix, etc.
I have described few concern in this issue fkolar/microfrontend-st#1
Is somebody willing to help to help us with this POC (right now its angular parts), then we woudl be in better possition to negotigate some sponsorship as we would be relaying on MF and without experts - this woudl be no go.
The final POC could look like this. Each card represent independent component delivered by different team. You should be able to click on the e.g. rubic cube it it will take you to the detail page.
Thanks for any inputs
The version-discrepancy example breaks a little when upgrading to from beta.16 to beta.17.
It is no longer possible to run app2 standalone without getting "Uncaught Error: Shared module is not available for eager consumption: webpack/sharing/consume/default/react/react"
Steps to reproduce:
cd version-discrepancy/app2
npm i webpack@next
npm run start
If the example relies on an external library
If the example is related to a module-federation pattern
If the example is related to a rendering/hydration pattern
proprietary code should be moved to a separate module-federation repo
Create issue templates
The dashboard example is not mentioned in the top level README, and its own README is the README from bi-directional
.
The note in the top level README should have the proprietary icon.
I'm really excited by federated modules, however when I tried to apply it to my application I had the dreaded invalid hook call. I can see from the network tab that the host is providing react, but the remote is also requesting and loading its own copy of react. This doesn't match my expectations for what federated modules is supposed to be doing.
I have cloned on this repo, ran yarn in the root and for the dynamic-system-host
example, individually started app1
, app2
, app3
. For some reason lerna wasn't running in the parent directory. Note I am using Windows as my OS.
Clearing the network tab and then clicking Load App 3 Widget
results in these network requests
I would like to understand if this example is broken, or whether there is a bug in the module federation. Some hints to why it isn't correctly federating and/or how to diagnose what is going on, would be appreciated.
I find http://localhost:3000/remoteEntry.js script file is load twice, one in head and another in body. So I delete the script in head.
Modify code module-federation-examples/shared-routing/dashboard/public/index.html
<html>
<head>
<script src="http://localhost:3000/remoteEntry.js"></script>
<!-- <script src="http://localhost:3001/remoteEntry.js"></script> -->
<script src="http://localhost:3002/remoteEntry.js"></script>
<script src="http://localhost:3003/remoteEntry.js"></script>
<script src="http://localhost:3004/remoteEntry.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
then run the Apps, visit http://localhost:3001/dashboard
Why 3001/remoteEntry.js file load order will cause the error? must manual add script in order?
app1
import 'antd.css'
app2 import 'antd.css'
加载两份,有好的解决方案吗
Hey everyone,
First of all thanks a lot for the amazing work on module federation. I was wondering if it is possible to fetch the remoteEntry.js
file from a remote source on the server. I know for client this is possible and was wondering if the same was possible on the server instead of fetching from the filesystem.
As followings, my app federation configs.
// app1
output: {
publickPath: 'http://localhost:3000'
}
plugins:[
new ModuleFederationPlugin({
name: 'main_app',
library: {
type: 'var',
name: 'main_app',
},
shared: ['react', 'react-dom', 'prop-types', 'lodash'],
});
]
// app2
output: {
publickPath: 'http://localhost:3001'
}
plugins:[
new ModuleFederationPlugin({
name: 'app2',
library: {
type: 'var',
name: 'app2',
},
remotes: {
main_app: 'main_app',
},
shared: ['react', 'react-dom', 'prop-types', 'lodash'],
}),
]
app2 build into a chunk, app1 import this chunk as a sub app.
so, app2 will use it‘s own react/react-dom/prop-types/lodash from http://localhost:3001.
the shared config not working.
How to make app2 use react/react-dom/prop-types/lodash from app1?
I'm working on an app with federated routes similar to the 'shared-routes2' example. If I have 5 apps all sharing their routes to a 'home' app, the whole app crashes if one of the apps is not available.
How can I make this resilient if app1 is offline?
import localRoutes from "./routes";
import remoteRoutes from "app1/routes";
const routes = [...localRoutes, ...remoteRoutes];
@newvladimirov when upgrading to beta.18, i run into issues on angular-universal-ssr
Mind taking a look?
#105
In the Shared shared-routing example,
when the remote component has a Router's <Link>
inside,
i get an error:
“You should not use <Link>
outside a <Router>
"
Great job on creating Module Federation. No doubt this is an important piece of how things will be done from now on. And quite awesome to see an example for implementation on NextJS. But I have to say the example itself is quite confusing, or at least not explained entirely. Why have a component (src/components/Dog.js
) - which lives under NextJS already - treated as a remote component within NextJS. Why this loop into itself? Is this part of how Module Federation works or just to showcase how to consume components from NextJS? Please clarify this bit.
One more thing, even in this simple example the performance is surprisingly bad, is SSR not yet working with Module Federation?
Thanks again!
Are there any thoughts/solutions when it comes to stylesheets and assets (e.g. images) already?
Sharing the components works flawless (my compliments), but what about compiled stylesheets?
Are we forced to use inline styling for the time being?
I want to start by saying that these examples are awesome and have been invaluable.
One thing I'm trying to understand is the pattern of using a relative path string as a key in the exposes config entry.
example:
exposes: {
"./Button": "./src/Button",
},
Is there some kind of convention here or reason not to just use Button
as the key?
Hi,
I'm really interested to make work this code samples @home :) But I can't access a repo.
Error: Command failed.
Exit code: 128
Command: git
Arguments: ls-remote --tags --heads [email protected]:module-federation/proprietary-tools.git
Directory: /Users/julien.froidefond/Sites/module-federation-examples/basic-host-remote/app1
Output:
Host key verification failed.
fatal: Could not read from remote repository.
Hi!
Im amazed and grateful by all this work, truly a gamechanger!
Very smooth to implement, but the one thing Im struggling with is publicPath. I know there is a pr up to solve this, but there seems to be debate about whether it should be merged or not.
In our case, we have a host application that has dev, test and prod environments, and then the remote apps also have dev, test and prod environments. So the host app in dev, needs to load the remote code from dev etc. It seems to me that the only way to achieve this currently is to create a separate build for each environment. Is this correct or is there a workaround?
Thanks again!
Hey all. There was a recent release which might have thrown some examples out of wack - I'm working on finishing up the update of all examples to beta 17 which will resolve the problems
Hi,
I have spend quite some time trying to configure module federation to work with HMR, however, with no success. No matter what kind of configuration I try the results is always the same:
remoteEntry.js:989 Uncaught TypeError: Cannot read property 'push' of undefined
at self.webpackHotUpdateplatform (remoteEntry.js:989)
at main.52ee0b798cefc4bb4013.hot-update.js:9
self.webpackHotUpdateplatform @ remoteEntry.js:989
(anonymous) @ main.52ee0b798cefc4bb4013.hot-update.js:9
Update failed: ChunkLoadError: Loading hot update chunk main failed.
(missing: http://localhost:3001/main.52ee0b798cefc4bb4013.hot-update.js)
at http://localhost:3001/main.js:1829:26
at new Promise ()
at loadUpdateChunk (http://localhost:3001/main.js:1824:20)
at http://localhost:3001/main.js:2253:29
at Array.forEach ()
at Object.webpack_require.hmrC.jsonp (http://localhost:3001/main.js:2248:22)
at http://localhost:3001/main.js:1416:45
at Array.reduce ()
at http://localhost:3001/main.js:1412:53
remoteEntry.js:985 Uncaught TypeError: Cannot set property './src/pages/CMS.tsx' of undefined
at self.webpackHotUpdateplatform (remoteEntry.js:985)
at src_pages_CMS_tsx-webpack_sharing_consume_default_react_react-webpack_sharing_consume_default-843145.52ee0b798cefc4bb4013.hot-update.js:9
A simple example how to do it will be much appreciated.
Thank you!
Steps:
yarn build
Expected:
Build succeed
Actual:
some build suceeded, some failed with error
ERROR in Conflict: Multiple assets emit different content to the same filename 64.js
ERROR in The comment file "64.js.LICENSE.txt" conflicts with an existing asset, this may lead to code corruption, please use a different name
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
lerna ERR! yarn run build stderr:
(node:3264) [DEP_WEBPACK_COMPILATION_ADDITIONAL_CHUNK_ASSETS] DeprecationWarning: additionalChunkAssets is deprecated (use Compilation.hook.processAssets instead and use one of Compilation.PROCESS_ASSETS_STAGE_* as stage option)
(node:3264) [DEP_WEBPACK_MAIN_TEMPLATE_ASSET_PATH] DeprecationWarning: MainTemplate.hooks.assetPath is deprecated (use Compilation.hooks.assetPath instead)
error Command failed with exit code 2.
lerna ERR! yarn run build exited 2 in '@shared-routing/shell'
error Command failed with exit code 2.
Step to reproduce
In a first terminal - Terminal 1
cd server-side-rendering/website1
yarn install
yarn build && yarn serve
In a second terminal - Terminal 2
cd server-side-rendering/website2
yarn install
yarn build && yarn serve
at this step : everything is working fine and header component is loaded through localhost:3002
Now try to update header component (website2) without touching host (website1)
Terminal 2
yarn build && yarn serve
Actual results
on localhost:3001 - Client side you will see "Zack is awesome"
however on the DOM you will still see "Header"
Result expected
we should have "Zack is awesome" on Client & DOM without having to rebuild HOST(website1)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.