Skip to content

Commit

Permalink
fix: get delegates working (#527)
Browse files Browse the repository at this point in the history
* feat: delegates part two

* fix:  use container proxy on script VM instead of host resolver point

* cleaning up code
  • Loading branch information
ScriptedAlchemy authored Jan 27, 2023
1 parent 18c9491 commit 7655568
Show file tree
Hide file tree
Showing 19 changed files with 223 additions and 154 deletions.
2 changes: 0 additions & 2 deletions apps/3000-home/components/SharedNav.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React from 'react';
import { Menu, Layout, Badge } from 'antd';
import { useRouter } from 'next/router';
// @ts-ignore
import {tjhin} from './thing.module.css'
import { useMFRemote } from '@module-federation/nextjs-mf/client';
import cookie from 'js-cookie'

Expand Down
9 changes: 6 additions & 3 deletions apps/3000-home/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ const nextConfig = {
const { isServer } = options;
;
const remotes = {
home: createDelegatedModule(require.resolve('./remote-delegate.js'), {
remote: `home_app@http://localhost:3000/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
}),
shop: createDelegatedModule(require.resolve('./remote-delegate.js'), {
remote: `shop@http://localhost:3001/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
}),
Expand All @@ -25,9 +28,9 @@ const nextConfig = {
// shop: `shop@http://localhost:3001/_next/static/${
// isServer ? 'ssr' : 'chunks'
// }/remoteEntry.js`,
checkout: `checkout@http://localhost:3002/_next/static/${
isServer ? 'ssr' : 'chunks'
}/remoteEntry.js`,
// checkout: `checkout@http://localhost:3002/_next/static/${
// isServer ? 'ssr' : 'chunks'
// }/remoteEntry.js`,
};

config.plugins.push(
Expand Down
1 change: 0 additions & 1 deletion apps/3000-home/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ function MyApp(props) {

const { Component, pageProps } = props
const [MenuComponent, setMenuComponent] = useState(() => HostAppMenu);

useMFClient({
onChangeRemote: async (remote) => {
if (remote) {
Expand Down
4 changes: 2 additions & 2 deletions apps/3000-home/pages/home/test-broken-remotes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ export default function TestBrokenRemotes() {
<p>
Check unresolved host –{' '}
<Link href="/unresolved-host">
/unresolved-host
<a>/unresolved-host</a>
</Link>{' '}
(on http://localhost:<b>3333</b>/_next/static/chunks/remoteEntry.js)
</p>
<p>
Check wrong response for remoteEntry –{' '}
<Link href="/wrong-entry">
/wrong-entry
<a>/wrong-entry</a>
</Link>{' '}
(on http://localhost:3000/_next/static/chunks/remoteEntry<b>Wrong</b>
.js)
Expand Down
3 changes: 2 additions & 1 deletion apps/3000-home/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react';
import Head from 'next/head';
import dynamic from 'next/dynamic';

const CheckoutTitle = dynamic(() => import('checkout/CheckoutTitle'), {
ssr: true,
ssr: false,
});
const ButtonOldAnt = dynamic(() => import('checkout/ButtonOldAnt'), {
ssr: false,
Expand Down
6 changes: 4 additions & 2 deletions apps/3000-home/remote-delegate.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { importDelegatedModule } from '@module-federation/utilities';

module.exports = new Promise((resolve, reject) => {
//eslint-disable-next-line
console.log('Delegate being called for', __resourceQuery);
//eslint-disable-next-line
const currentRequest = new URLSearchParams(__resourceQuery).get('remote');

const [global, url] = currentRequest.split('@');
Expand All @@ -10,8 +12,8 @@ module.exports = new Promise((resolve, reject) => {
global,
url,
})
.then((remote) => {
resolve(remote);
.then(async (remote) => {
resolve(remote)
})
.catch((err) => reject(err));
});
46 changes: 21 additions & 25 deletions apps/3001-shop/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const NextFederationPlugin = require('@module-federation/nextjs-mf');
const {
promiseTemplate,
} = require('@module-federation/nextjs-mf/utils/build-utils');
const {createDelegatedModule} = require("@module-federation/utilities");
/**
* @type {import('@nrwl/next/plugins/with-nx').WithNxOptions}
**/
Expand All @@ -22,31 +23,24 @@ const nextConfig = {
name: 'shop',
filename: 'static/chunks/remoteEntry.js',
remotes: {

// shop: promiseTemplate('global@url', (resolve,reject) => {}),
// home: promiseTemplate(
// // can also be a string if it needs to be computed in scope
// `(resolve, reject) => {
// resolve("home_app@http://localhost:3000/_next/static/${
// isServer ? 'ssr' : 'chunks'
// }/remoteEntry.js");
// }`,
// (resolve,reject)=>{
// console.log('runing other promise');
// setTimeout(() => {
// console.log('resolving promise');
// resolve();
// } , 1000);
// }),
home: `home_app@http://localhost:3000/_next/static/${
isServer ? 'ssr' : 'chunks'
}/remoteEntry.js`,
shop: `shop@http://localhost:3001/_next/static/${
isServer ? 'ssr' : 'chunks'
}/remoteEntry.js`,
checkout: `checkout@http://localhost:3002/_next/static/${
isServer ? 'ssr' : 'chunks'
}/remoteEntry.js`,
// home: `home_app@http://localhost:3000/_next/static/${
// isServer ? 'ssr' : 'chunks'
// }/remoteEntry.js`,
// shop: `shop@http://localhost:3001/_next/static/${
// isServer ? 'ssr' : 'chunks'
// }/remoteEntry.js`,
// checkout: `checkout@http://localhost:3002/_next/static/${
// isServer ? 'ssr' : 'chunks'
// }/remoteEntry.js`,
home: createDelegatedModule(require.resolve('./remote-delegate.js'), {
remote: `home_app@http://localhost:3000/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
}),
shop: createDelegatedModule(require.resolve('./remote-delegate.js'), {
remote: `shop@http://localhost:3001/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
}),
checkout: createDelegatedModule(require.resolve('./remote-delegate.js'), {
remote: `checkout@http://localhost:3002/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
}),
},
exposes: {
'./useCustomRemoteHook': './components/useCustomRemoteHook',
Expand All @@ -58,7 +52,9 @@ const nextConfig = {
lodash: {},
},
extraOptions: {
verbose: true,
exposePages: true,
automaticAsyncBoundary: true,
enableImageLoaderFix: true,
enableUrlLoaderFix: true,
automaticPageStitching: true,
Expand Down
17 changes: 17 additions & 0 deletions apps/3001-shop/remote-delegate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { importDelegatedModule } from '@module-federation/utilities';

module.exports = new Promise((resolve, reject) => {
console.log('Delegate being called for', __resourceQuery);
const currentRequest = new URLSearchParams(__resourceQuery).get('remote');

const [global, url] = currentRequest.split('@');

importDelegatedModule({
global,
url,
})
.then(async (remote) => {
resolve(remote)
})
.catch((err) => reject(err));
});
19 changes: 10 additions & 9 deletions apps/3002-checkout/next.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const {withNx} = require('@nrwl/next/plugins/with-nx');

const NextFederationPlugin = require('@module-federation/nextjs-mf');
const {createDelegatedModule} = require("@module-federation/utilities");

/**
* @type {import('@nrwl/next/plugins/with-nx').WithNxOptions}
Expand All @@ -19,15 +20,15 @@ const nextConfig = {
name: 'checkout',
filename: 'static/chunks/remoteEntry.js',
remotes: {
home: `home_app@http://localhost:3000/_next/static/${
isServer ? 'ssr' : 'chunks'
}/remoteEntry.js`,
shop: `shop@http://localhost:3001/_next/static/${
isServer ? 'ssr' : 'chunks'
}/remoteEntry.js`,
checkout: `checkout@http://localhost:3002/_next/static/${
isServer ? 'ssr' : 'chunks'
}/remoteEntry.js`,
home: createDelegatedModule(require.resolve('./remote-delegate.js'), {
remote: `home_app@http://localhost:3000/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
}),
shop: createDelegatedModule(require.resolve('./remote-delegate.js'), {
remote: `shop@http://localhost:3001/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
}),
checkout: createDelegatedModule(require.resolve('./remote-delegate.js'), {
remote: `checkout@http://localhost:3002/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
}),
},
exposes: {
'./CheckoutTitle': './src/components/CheckoutTitle',
Expand Down
17 changes: 17 additions & 0 deletions apps/3002-checkout/remote-delegate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { importDelegatedModule } from '@module-federation/utilities';

module.exports = new Promise((resolve, reject) => {
console.log('Delegate being called for', __resourceQuery);
const currentRequest = new URLSearchParams(__resourceQuery).get('remote');

const [global, url] = currentRequest.split('@');

importDelegatedModule({
global,
url,
})
.then(async (remote) => {
resolve(remote)
})
.catch((err) => reject(err));
});
26 changes: 18 additions & 8 deletions packages/nextjs-mf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,12 @@ new NextFederationPlugin({
exposes: {},
shared: {},
extraOptions: {
exposePages: true, // `false` by default
enableImageLoaderFix: true, // `false` by default
enableUrlLoaderFix: true, // `false` by default
automaticAsyncBoundary: true, // `false` by default
skipSharingNextInternals: false // `false` by default
verbose: boolean, // `false` by default
exposePages: boolean, // `false` by default
enableImageLoaderFix: boolean, // `false` by default
enableUrlLoaderFix: boolean, // `false` by default
automaticAsyncBoundary: boolean, // `false` by default
skipSharingNextInternals: boolean // `false` by default
},
});
```
Expand Down Expand Up @@ -253,13 +254,13 @@ loading process of remote modules by delegating it to an internal file bundled b
This is done by exporting a promise in the delegate file that resolves to a remote/container interface.

A container interface is the low-level {get, init} API that remote entries expose to a consuming app.
In the browser, a remote container would be window.app1, and in Node, it would be global.__remote_scope__.app1.
In the browser, a remote container would be window.app1, and in Node, it would be `global.__remote_scope__.app1`.

To use delegate modules, a method for script loading must be implemented in the delegate file.
A common method is to use webpack's built-in __webpack_require__.l method, but any method can be used.
A common method is to use webpack's built-in `__webpack_require__.l` method, but any method can be used.
This method is exposed to the runtime and is the same method that webpack uses internally to load remotes.

Here's an example of using a delegate module with __webpack_require__.l:
Here's an example of using a delegate module with `__webpack_require__.l`:

<details>
<summary>See Example: (click) </summary>
Expand All @@ -270,7 +271,16 @@ the promise is resolved with the value of window[containerName].
If an error occurs while loading the script, a custom error object is created and the promise is rejected with this error.

```js
//next.config.js

const remotes = {
checkout: createDelegatedModule(require.resolve('./remote-delegate.js'), {
remote: `checkout@http://localhost:3002/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
}),
}


//remote-delegate.js
import { importDelegatedModule } from '@module-federation/utilities';

module.exports = new Promise((resolve, reject) => {
Expand Down
18 changes: 5 additions & 13 deletions packages/nextjs-mf/src/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export const generateRemoteTemplate = (url: string, global: any) => `new Promise
}).then(function () {
const proxy = {
get: ${global}.get,
init: function(shareScope, initScope) {
init: function(shareScope, initToken) {
const handler = {
get(target, prop) {
Expand All @@ -140,24 +140,16 @@ export const generateRemoteTemplate = (url: string, global: any) => `new Promise
return true
}
}
if (!${global}.__initialized) {
try {
${global}.init(new Proxy(shareScope, handler), initScope)
} catch (e) {
try {
${global}.init(new Proxy(shareScope, handler), initToken)
} catch (e) {
}
${global}.__initialized = true
}
${global}.__initialized = true
}
}
if (!${global}.__initialized) {
try {
proxy.init(__webpack_require__.S.default)
} catch (e) {
}
${global}.__initialized = true
}
return proxy
})`;
Expand Down
7 changes: 5 additions & 2 deletions packages/nextjs-mf/src/loaders/delegateLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export default function patchDefaultSharedLoader(
this: LoaderContext<Record<string, unknown>>,
content: string
) {

const {delegates} = this.getOptions() as Record<string, string>;

const resolvedDelegates = Object.values(delegates).map((delegate) => {
Expand All @@ -26,6 +25,10 @@ export default function patchDefaultSharedLoader(
}
})

if(content.includes('hasDelegateMarkers') || (this._compilation && this._compilation.name === 'ChildFederationPlugin')) {
return content
}


const requiredDelegates = resolvedDelegates.map((delegate) => {
return `require('${delegate}')`
Expand All @@ -34,7 +37,7 @@ export default function patchDefaultSharedLoader(
return [
'',
...requiredDelegates,
'',
'//hasDelegateMarkers',
content
].join("\n")
}
Expand Down
Loading

0 comments on commit 7655568

Please sign in to comment.