Comments (11)
We are overhauling nextjs-mf in v8 you will have a real lifecycle hook set to use, we will also look at improved HMR (real hmr) capabilities in production as ByteDance has figured it out already
from universe.
You need to have something like App.getInitialProps or getServerProps, otherwise it static generation and theres no server, so threads restart the application to static generate it
from universe.
@AmineAyachi I had a similar issue with my setup as well. I have 5 NextJS apps, 1 is the host, the others are all remotes. They are all built as standalone NextJS apps in Docker images and deployed through Fargate (ECS). Whenever I updated a remote, the host would error out on the server until I redeployed the host.
The only way I could reproduce the error locally was to do this:
- Build the host and a remote (
npm run build
) - Boot up the remote, then the host
- Navigate to the host in a browser (at this point, the host works as expected)
- Change the filename of one of the remote JS chunks under
.next/static/ssr/
and reboot the remote - Refresh the page ---> Error
What happens locally is that revalidate()
sees the same remote remoteEntry.js
and doesn't invalidate it (this is the correct behavior). However, because the chunk is different, when Webpack tries to load the chunk that is referenced in remoteEntry.js
, the fetch returns 404 and throws the fetch error (which is what I see in the logs as Error [Object object]
-- yeah, super helpful error message).
Obviously this doesn't happen exactly the same way in Production, but i've tried so many different ways to reproduce this locally, and this was the only way it worked. I think what's going on in Production for me is that we boot up 2 legs of each app, and one of them updates before the other. So one version of remoteEntry.js
is loaded and cached, and then it attempts to fetch a chunk but gets redirected to the other leg where the chunk doesn't exist. This is just a hypothesis, though.
In any case, i was able to mostly fix this issue by modifying my delegate module a bit:
Updated Delegate Module (lots of code, expand to view)
const { importDelegatedModule } = require('@module-federation/utilities')
// eslint-disable-next-line no-async-promise-executor
module.exports = new Promise(async (resolve, reject) => {
// <some custom remote string parsing logic here>
importDelegatedModule({
global: remoteID,
url: `${url}?${Date.now()}`,
globalThis: true, // this is because of a quirk here: https://github.com/module-federation/universe/blob/main/packages/utilities/src/utils/importDelegatedModule.ts#L16
}).then((remote) => {
// shim the async container to catch remote module loading errors
const container = {
get: async (arg) => {
try {
// call the async container's `get` function and catch any errors it might throw
return await remote?.get?.(arg)
} catch (err) {
if (typeof window === 'undefined' && globalThis.__remote_scope__[remoteID]) {
// if there is an error, mark the container as fake to invalidate the cache
globalThis.__remote_scope__[remoteID].fake = true
// ensure this chunk is flushed to prevent caching
if (globalThis.usedChunks) {
globalThis.usedChunks.add(`${remoteID}->${arg}`)
}
}
}
// if it's broken, return an empty module
return {
__esModule: true,
default: () => {
return null
},
}
},
init: remote?.init,
}
// store the shimmed container in the remote scope
if (typeof window === 'undefined') {
globalThis.__remote_scope__[remoteID] = container
}
resolve(container)
}, reject)
})
Basically, this wraps the remote container with some error handling that forcibly invalidates itself from the cache if there is a chunk-load error. I hijacked the "fake" container property so that the built-in revalidate()
function always invalidates it right away. Additionally, I wrapped the revalidate()
function when i want to forcibly invalidate the cache elsewhere in the host like this:
const invalidate = () => {
const globalScope = globalThis.__remote_scope__
if (globalScope) {
Object.keys(globalScope).forEach((remoteID) => {
if (!remoteID.startsWith('_') && Object.prototype.hasOwnProperty.call(globalScope, remoteID)) {
globalScope[remoteID].fake = true
}
})
}
return revalidate()
}
It's not perfect, it recently occurred randomly a couple weeks ago. But instead of it happening most of the time, its down to probably about 2% of the time. Let me know if you try it and if it helps or not.
from universe.
Try with latest, ive rewritten most of this now.
from universe.
Thanks , i did and its working in production here is my setup :
pages/_app.js:
import App from 'next/app';
function MyApp({ Component, pageProps }) {
return (
<>
<Component {...pageProps} />
<style jsx>{`
.hero {
width: 100%;
color: #333;
}
.title {
margin: 0;
width: 100%;
padding-top: 80px;
line-height: 1.15;
font-size: 48px;
}
.title,
.description {
text-align: center;
}
.row {
max-width: 880px;
margin: 80px auto 40px;
display: flex;
flex-direction: row;
justify-content: space-around;
}
.card {
padding: 18px 18px 24px;
width: 220px;
text-align: left;
text-decoration: none;
color: #434343;
border: 1px solid #9b9b9b;
}
.card:hover {
border-color: #067df7;
}
.card h3 {
margin: 0;
color: #067df7;
font-size: 18px;
}
.card p {
margin: 0;
padding: 12px 0 0;
font-size: 13px;
color: #333;
}
`}</style>
</>
);
}
MyApp.getInitialProps = async ctx => {
const appProps = await App.getInitialProps(ctx);
return appProps;
};
export default MyApp;
pages/_document.js:
import Document, { Html, Head, Main, NextScript } from "next/document";
import React from "react";
import { revalidate, FlushedChunks, flushChunks } from "@module-federation/nextjs-mf/utils";
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
// can be any lifecycle or implementation you want
ctx?.res?.on('finish', () => {
revalidate().then((shouldUpdate) => {
console.log('finished sending response', shouldUpdate);
});
});
return initialProps;
}
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
index.js:
import Head from 'next/head';
import styles from '../styles/Home.module.css';
export default function Home() {
const handleclick = () => {
}
return (
<div className={styles.container}>
Auth App 6
</div>
);
}
Home.getServerProps = async ctx => {
return {};
};
But i need to restart the host when i make changes and redeploy the remote :/ can you help me on that please
from universe.
try debugging revalidate, check if it returns a boolean "true" revalidate in your case is lazy, so it will send stale replay for first new render after update, you can make that await instead of res.on.send so it clears require cache before rendering again after update, otherwise its stale while revalidate.
Do you use express or docker?
from universe.
Yes, I am using Docker and I am experiencing an issue with the remote which requires me to clear the cache using Ctrl + F5 in order to refresh the remote
note that i have the same issue with npm run build npm start without docker
from universe.
In my Next.js application, whenever I make changes to the remote and redeploy, it's necessary to refresh the page using CTRL+F5. For replication purposes, I've created repositories and would greatly appreciate if you could analyze the code. Any feedback would be extremely helpful as I'm currently facing some issues.
My solution consists of 3 projects:
Shared Package: https://github.com/AmineAyachi/template-auth-core-package
Host: https://github.com/AmineAyachi/template-host-app
Remote: https://github.com/AmineAyachi/template-auth-app
The core package is deployed on GitHub. The host application includes a simple button to switch languages. However, if you make changes in the remote and then refresh the page, the latest updates from the remote are not reflected in the host
from universe.
Okay, thank you sir. I need to get this work done as soon as possible 👍
from universe.
@AmineAyachi I had a similar issue with my setup as well. I have 5 NextJS apps, 1 is the host, the others are all remotes. They are all built as standalone NextJS apps in Docker images and deployed through Fargate (ECS). Whenever I updated a remote, the host would error out on the server until I redeployed the host.
The only way I could reproduce the error locally was to do this:
- Build the host and a remote (
npm run build
)- Boot up the remote, then the host
- Navigate to the host in a browser (at this point, the host works as expected)
- Change the filename of one of the remote JS chunks under
.next/static/ssr/
and reboot the remote- Refresh the page ---> Error
What happens locally is that
revalidate()
sees the same remoteremoteEntry.js
and doesn't invalidate it (this is the correct behavior). However, because the chunk is different, when Webpack tries to load the chunk that is referenced inremoteEntry.js
, the fetch returns 404 and throws the fetch error (which is what I see in the logs asError [Object object]
-- yeah, super helpful error message).Obviously this doesn't happen exactly the same way in Production, but i've tried so many different ways to reproduce this locally, and this was the only way it worked. I think what's going on in Production for me is that we boot up 2 legs of each app, and one of them updates before the other. So one version of
remoteEntry.js
is loaded and cached, and then it attempts to fetch a chunk but gets redirected to the other leg where the chunk doesn't exist. This is just a hypothesis, though.In any case, i was able to mostly fix this issue by modifying my delegate module a bit:
Updated Delegate Module (lots of code, expand to view)
Basically, this wraps the remote container with some error handling that forcibly invalidates itself from the cache if there is a chunk-load error. I hijacked the "fake" container property so that the built-inrevalidate()
function always invalidates it right away. Additionally, I wrapped therevalidate()
function when i want to forcibly invalidate the cache elsewhere in the host like this:const invalidate = () => { const globalScope = globalThis.__remote_scope__ if (globalScope) { Object.keys(globalScope).forEach((remoteID) => { if (!remoteID.startsWith('_') && Object.prototype.hasOwnProperty.call(globalScope, remoteID)) { globalScope[remoteID].fake = true } }) } return revalidate() }It's not perfect, it recently occurred randomly a couple weeks ago. But instead of it happening most of the time, its down to probably about 2% of the time. Let me know if you try it and if it helps or not.
Thanks , I will try it
from universe.
Stale issue message
from universe.
Related Issues (20)
- Optimizing the problem of overly long identifiers of the container entry module of the issuerPath in the stats.json file HOT 2
- @module-federation/native-federation-typescript - support destination folder, loadRemote typings and other improvements HOT 7
- Type file missing when using vue-tsc HOT 6
- remote component error in react when this version different HOT 5
- Add documentation / example for including module federation runtime via CDN in browser script tag HOT 4
- Module Federation not working with Content Security Policy (CSP) HOT 9
- getPublicPath or publicPath is not part of ModuleFederationPluginOptions HOT 5
- @mf-types. expose typings for shared modules HOT 1
- Infer shared modules based from the host's manifest file. HOT 2
- Duplicate network request for chunk from multiple entryfiles HOT 5
- Module Federation SSR is incompatible with webpack-node-externals HOT 2
- The remote module is missing on the Window when running in the sandbox of the micro-frontend framework micro-app. HOT 5
- i try to use init() and app cant find it HOT 4
- Using the `revalidate` method to trigger hot reload can cause service crashes HOT 5
- dts for entries exposed with aliases are not emitting HOT 1
- Can't create Error Fallback when any Remote fails. HOT 7
- Chrome Extension is not working due to empty `moduleInfo` HOT 3
- web worker error in host HOT 2
- Exact matching alias does not work as expected in bridge webpack plugin HOT 2
- Shared dependency version cannot be resolved if installed at root of a monorepo
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from universe.