Skip to content

Commit

Permalink
feat(nextjs-mf): add support for Next.js App Router
Browse files Browse the repository at this point in the history
  • Loading branch information
prasannamestha committed Jan 21, 2024
1 parent 73eb07e commit 99b2cff
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 80 deletions.
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,11 @@
"eslint-plugin-react-hooks": "4.6.0",
"eslint-plugin-simple-import-sort": "10.0.0",
"form-data": "4.0.0",
"graceful-fs": "^4.2.9",
"highlight.js": "10.7.3",
"html-webpack-plugin": "5.6.0",
"husky": "8.0.3",
"inquirer": "9.2.12",
"inquirer": "8.2.6",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"jest-environment-node": "29.7.0",
Expand All @@ -193,8 +194,10 @@
"qwik-nx": "1.1.1",
"qwik-speak": "0.19.0",
"react-refresh": "0.14.0",
"rimraf": "^3.0.2",
"rollup-plugin-copy": "3.5.0",
"stopword": "2.0.8",
"strip-ansi": "^6.0.0",
"swc-loader": "0.2.3",
"tailwindcss": "3.4.0",
"ts-jest": "29.1.1",
Expand All @@ -210,13 +213,10 @@
"vitest": "0.32.4",
"vitest-fetch-mock": "^0.2.2",
"vue-tsc": "1.8.27",
"wast-loader": "^1.11.5",
"webpack": "^5.88.2",
"webpack-virtual-modules": "0.6.1",
"whatwg-fetch": "^3.6.2",
"graceful-fs": "^4.2.9",
"rimraf": "^3.0.2",
"strip-ansi": "^6.0.0",
"wast-loader": "^1.11.5"
"whatwg-fetch": "^3.6.2"
},
"config": {
"commitizen": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ class FederationRuntimePlugin {
// TODO: maybe set this variable as constant is better https://github.com/webpack/webpack/blob/main/lib/config/defaults.js#L176
entryItem.import = ['./src'];
}
if (!entryItem.import.includes(entryFilePath)) {
if (
!entryItem.import.includes(entryFilePath) &&
entryItem.layer !== 'rsc' // TODO: remove this when adding support for RSC
) {
entryItem.import.unshift(entryFilePath);
}
});
Expand Down
27 changes: 21 additions & 6 deletions packages/nextjs-mf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ This plugin enables Module Federation on Next.js

## Supports

- next ^13 || ^12(?)
- next ^14 || ^13 || ^12(?)
- SSR included!
- App router included (experimental)

I highly recommend referencing this application which takes advantage of the best capabilities:
https://github.com/module-federation/module-federation-examples
Expand Down Expand Up @@ -144,6 +145,20 @@ const SomeHook = require('next2/someHook');
import SomeComponent from 'next2/someComponent';
```

## Usage in Next.js App Router

In order to use module federation in projects with app router, you must pass `next/navigation` as a shared dependency. This will disable sharing default dependencies (`DEFAULT_SHARE_SCOPE`).

```js
new NextFederationPlugin({
name: '',
filename: '',
remotes: {},
exposes: {},
shared: ['next/navigation'], // This is important!
});
```

## Demo

You can see it in action here: https://github.com/module-federation/module-federation-examples/tree/master/nextjs-ssr
Expand Down Expand Up @@ -257,16 +272,16 @@ const SampleComponent = lazy(() => import('next2/sampleComponent'));

import Sample from 'next2/sampleComponent';
```
## RuntimePlugins

## RuntimePlugins

To provide extensibility and "middleware" for federation, you can refer to `@module-federation/runtime`

```js
// next.config.js
new NextFederationPlugin({
runtimePlugins: [
require.resolve('./path/to/myRuntimePlugin.js')
]
})
runtimePlugins: [require.resolve('./path/to/myRuntimePlugin.js')],
});
```

## Utilities
Expand Down
3 changes: 2 additions & 1 deletion packages/nextjs-mf/src/plugins/NextFederationPlugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ export class NextFederationPlugin {
compiler: Compiler,
isServer: boolean,
): ModuleFederationPluginOptions {
const defaultShared = retrieveDefaultShared(isServer);
const defaultShared = retrieveDefaultShared(isServer, this._options.shared);

const noop = this.getNoopPath();
return {
...this._options,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { retrieveDefaultShared } from './next-fragments';

describe('retrieveDefaultShared', () => {
it('should return empty object if "next/navigation" is shared', () => {
const defaultShared = retrieveDefaultShared(false, ['next/navigation']);
expect(defaultShared).toMatchObject({});
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { container, Compiler } from 'webpack';
import type {
ModuleFederationPluginOptions,
Shared,
SharedObject,
} from '@module-federation/utilities';
import {
Expand All @@ -15,12 +16,23 @@ import { hasLoader, injectRuleLoader } from '../../loaders/helpers';
* @param {boolean} isServer - Boolean indicating if the code is running on the server.
* @returns {SharedObject} The default share scope based on the environment.
*/
export const retrieveDefaultShared = (isServer: boolean): SharedObject => {
export const retrieveDefaultShared = (
isServer: boolean,
shared?: Shared,
): SharedObject => {
// If the code is running on the server, treat some Next.js internals as import false to make them external
// This is because they will be provided by the server environment and not by the remote container
if (isServer) {
return DEFAULT_SHARE_SCOPE;
}

if (Array.isArray(shared)) {
if (shared.includes('next/navigation')) {
// Disable default shared scope for Next.js app router.
// This is needed to prevent errors related to react-dom
return {};
}
}
// If the code is running on the client/browser, always bundle Next.js internals
return DEFAULT_SHARE_SCOPE_BROWSER;
};
Expand Down Expand Up @@ -58,7 +70,7 @@ export const applyPathFixes = (compiler: Compiler, options: any) => {
if (rule?.oneOf) {
//@ts-ignore
rule.oneOf.forEach((oneOfRule) => {
if (hasLoader(oneOfRule, 'react-refresh-utils')) {
if (hasLoader(oneOfRule, 'react-refresh-utils') && oneOfRule.exclude) {
oneOfRule.exclude = [oneOfRule.exclude, /universe\/packages/];
}
});
Expand Down
Loading

0 comments on commit 99b2cff

Please sign in to comment.