# Next.js 这个插件为 Next.js 启用 Module Federation ## 支持 - next ^14 || ^13 || ^12 - 包含服务器端渲染(SSR)! 强烈推荐参考这个应用,它提供了 Next.js 与 Module Federation 结合的最佳实践: [module-federation 示例](https://github.com/module-federation/module-federation-examples) ## 该项目支持联合服务器端渲染(SSR) ## 默认共享内容 在底层,默认自动共享一些 Next 内部的内容 你不需要自己共享这些包,自行共享 Next 内部内容会引起错误。
查看 DEFAULT_SHARE_SCOPE: ```ts export const DEFAULT_SHARE_SCOPE: SharedObject = { 'next/dynamic': { requiredVersion: undefined, singleton: true, import: undefined, }, 'next/head': { requiredVersion: undefined, singleton: true, import: undefined, }, 'next/link': { requiredVersion: undefined, singleton: true, import: undefined, }, 'next/router': { requiredVersion: false, singleton: true, import: undefined, }, 'next/image': { requiredVersion: undefined, singleton: true, import: undefined, }, 'next/script': { requiredVersion: undefined, singleton: true, import: undefined, }, react: { singleton: true, requiredVersion: false, import: false, }, 'react/': { singleton: true, requiredVersion: false, import: false, }, 'react-dom/': { singleton: true, requiredVersion: false, import: false, }, 'react-dom': { singleton: true, requiredVersion: false, import: false, }, 'react/jsx-dev-runtime': { singleton: true, requiredVersion: false, }, 'react/jsx-runtime': { singleton: true, requiredVersion: false, }, 'styled-jsx': { singleton: true, import: undefined, version: require('styled-jsx/package.json').version, requiredVersion: '^' + require('styled-jsx/package.json').version, }, 'styled-jsx/style': { singleton: true, import: false, version: require('styled-jsx/package.json').version, requiredVersion: '^' + require('styled-jsx/package.json').version, }, 'styled-jsx/css': { singleton: true, import: undefined, version: require('styled-jsx/package.json').version, requiredVersion: '^' + require('styled-jsx/package.json').version, }, }; ```
## 要求 在这个插件中,设置了 `process.env.NEXT_PRIVATE_LOCAL_WEBPACK = 'true'`,但最好是在环境变量或命令行中设置。 "本地 Webpack" 意味着你必须将 webpack 安装为依赖项,并且 next 不会使用其捆绑的 webpack 副本,因为需要访问所有 webpack 内部 - 使用 `cross-env NEXT_PRIVATE_LOCAL_WEBPACK=true next dev` 或 `next build` - `npm install webpack` ## 使用方法 ```js import React, { lazy } from 'react'; const SampleComponent = lazy(() => import('next2/sampleComponent')); ``` 为了避免水合错误,使用 `React.lazy` 而不是 `next/dynamic` 来懒加载联合组件。 #### 在这里看到实现:[module-federation 示例](https://github.com/module-federation/module-federation-examples/tree/master/nextjs-v13/home/pages) 在页面级别安装异步边界后,可以执行以下操作: ```js const SomeHook = require('next2/someHook'); import SomeComponent from 'next2/someComponent'; ``` ## 演示 你可以在这里看到它的实际应用:[module-federation 示例](https://github.com/module-federation/module-federation-examples/tree/master/nextjs-ssr) ## 选项 这个插件的工作方式与 ModuleFederationPlugin 完全相同,按正常方式使用即可。 请注意,我们已经自动为你共享了 react 和 next 相关的内容。 NextFederationPlugin 还有一个可选参数 `extraOptions`,你可以用它来启用这个插件的额外功能: ```js new NextFederationPlugin({ name: '', filename: '', remotes: {}, exposes: {}, shared: {}, extraOptions: { debug: boolean, // `false` by default exposePages: boolean, // `false` by default enableImageLoaderFix: boolean, // `false` by default enableUrlLoaderFix: boolean, // `false` by default skipSharingNextInternals: boolean, // `false` by default }, }); ``` - `debug` – 启用调试模式。它将打印关于底层发生情况的额外信息。 - `exposePages` – 自动为你暴露所有的 Next.js 页面和它们的 `./pages-map`。 - `enableImageLoaderFix` – 给所有由 `nextjs-image-loader` 打包的资产添加公共主机名。例如,如果你从 `http://example.com` 提供 remoteEntry,则所有打包资产将在运行时获取此主机名。这类似于 HTML 中的 Base URL,但用于联合模块。 - `enableUrlLoaderFix` – 给所有由 `url-loader` 打包的资产添加公共主机名。 - `skipSharingNextInternals` – 禁用共享 Next 内部。如果你想自己共享 Next 内部或在非 next 应用中使用此插件,则可以使用它。 ## 演示 你可以在这里看到它的实际应用:[module-federation 演示](https://github.com/module-federation/module-federation-examples/pull/2147) ## 实现插件 1. 在你想要暴露模块的应用的 `next.config.js` 中使用 `NextFederationPlugin`。我们将这个应用称为 "next2"。 ```js // either from default const NextFederationPlugin = require('@module-federation/nextjs-mf'); module.exports = { webpack(config, options) { const { isServer } = options; config.plugins.push( new NextFederationPlugin({ name: 'next2', remotes: { next1: `next1@http://localhost:3001/_next/static/${ isServer ? 'ssr' : 'chunks' }/remoteEntry.js`, }, filename: 'static/chunks/remoteEntry.js', exposes: { './title': './components/exposedTitle.js', './checkout': './pages/checkout', }, shared: { // whatever else }, }), ); return config; }, }; ``` ```js // next.config.js const NextFederationPlugin = require('@module-federation/nextjs-mf'); module.exports = { webpack(config, options) { const { isServer } = options; config.plugins.push( new NextFederationPlugin({ name: 'next1', remotes: { next2: `next2@http://localhost:3000/_next/static/${ isServer ? 'ssr' : 'chunks' }/remoteEntry.js`, }, }), ); return config; }, }; ``` 4. 使用 react.lazy、低级 API 或从导入远程模 ```js import React, { lazy } from 'react'; const SampleComponent = lazy(() => window.next2.get('./sampleComponent').then((factory) => { return { default: factory() }; }), ); // or const SampleComponent = lazy(() => import('next2/sampleComponent')); //or import Sample from 'next2/sampleComponent'; ``` ## RuntimePlugins 要为 Module Federation 提供可扩展性和“中间件”,您可以参考 `@module-federation/enhanced/runtime` ```js // next.config.js new NextFederationPlugin({ runtimePlugins: [require.resolve('./path/to/myRuntimePlugin.js')], }); ```