Next.js的微观前端路由问题

发布于 2025-02-03 05:05:23 字数 5061 浏览 4 评论 0原文

我正在使用三个下一个项目(App1,app2,base)建立一个微观前端框架。 App1App2是远程应用程序,base是主机应用程序。

app1 next.config.js

const { withModuleFederation } = require('@module-federation/nextjs-mf');
module.exports = {
  webpack5: true,
  images: {
    domains: ['static.wikia.nocookie.net'],
  },
  webpack: (config, options) => {
    const { isServer } = options;
    const mfConf = {
      mergeRuntime: true,
      name: 'app1',
      library: {
        type: config.output.libraryTarget,
        name: 'app1',
      },
      filename: 'static/runtime/app1RemoteEntry.js',
      remotes: {},
      exposes: {
        './thanatos': './components/thanatos',
      },
    };
    config.cache = false;
    withModuleFederation(config, options, mfConf);
    if (!isServer) {
        config.output.publicPath = 'http://localhost:3001/_next/';
    }

    return config;
  },

  webpackDevMiddleware: (config) => {
    // Perform customizations to webpack dev middleware config
    // Important: return the modified config
    return config;
  },
};

app2 next.config.js

const { withModuleFederation } = require('@module-federation/nextjs-mf');
module.exports = {
  webpack5: true,
  images: {
    domains: ['static.wikia.nocookie.net'],
  },
  webpack: (config, options) => {
    const { isServer } = options;
    const mfConf = {
      mergeRuntime: true,
      name: 'app2',
      library: {
        type: config.output.libraryTarget,
        name: 'app2',
      },
      filename: 'static/runtime/app2RemoteEntry.js',
      remotes: {},
      exposes: {
        './zagreus': './components/zagreus',
      },
    };
    config.cache = false;
    withModuleFederation(config, options, mfConf);
    if (!isServer) {
        config.output.publicPath = 'http://localhost:3002/_next/';
    }

    return config;
  },

  webpackDevMiddleware: (config) => {
    // Perform customizations to webpack dev middleware config
    // Important: return the modified config
    return config;
  },
};

base next.config.js

const { withModuleFederation } = require('@module-federation/nextjs-mf');
const path = require('path');

// For SSR, resolve to disk path (or you can use code streaming if you have access)
// in production use the chunks
const ssrRemoteEntry = (app) =>
  process.env.NODE_ENV === 'production'
    ? path.join(
        `<remotes-path>/${app}/.next/server/chunks/static/runtime/remoteEntry.js`
      )
    : path.resolve(
        __dirname,
        `../${app}/.next/server/static/runtime/remoteEntry.js`
      );

module.exports = {
  webpack5: true,
  images: {
    domains: ['static.wikia.nocookie.net'],
  },
  webpack: (config, options) => {
    const { isServer } = options;
    const mfConf = {
      name: 'base',
      library: {
        type: config.output.libraryTarget,
        name: 'base',
      },
      remotes: {
        app1: isServer ? ssrRemoteEntry('app1') : 'app1',
        app2: isServer ? ssrRemoteEntry('app2') : 'app2',
      },
      exposes: {},
    };
    config.cache = false;
    withModuleFederation(config, options, mfConf);

    return config;
  },

  webpackDevMiddleware: (config) => {
    // Perform customizations to webpack dev middleware config
    // Important: return the modified config
    return config;
  },
};

base _document.js

import Document, { Html, Head, Main, NextScript } from 'next/document';
class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);
    return { ...initialProps };
  }

  render() {
    return (
      <Html>
        <script src="http://localhost:3001/_next/static/runtime/app1RemoteEntry.js" />
        <script src="http://localhost:3002/_next/static/runtime/app2RemoteEntry.js" />
        <Head>
          <link rel="icon" href="/favicon.ico" />
          <meta
            name="description"
            content="Demo for Microfrontends using Module Federation"
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

当我运行三个应用程序时,base应用程序我只能看到base的页面,但是当我单击其他两个按钮时,要导航到app1app2,浏览器显示空白页。 “在此处输入图像说明”

“在此处输入图像描述”

I am building a micro frontend framework with three Next.js projects (app1, app2, base). app1 and app2 are the remote application and base is the host application.

app1 next.config.js:

const { withModuleFederation } = require('@module-federation/nextjs-mf');
module.exports = {
  webpack5: true,
  images: {
    domains: ['static.wikia.nocookie.net'],
  },
  webpack: (config, options) => {
    const { isServer } = options;
    const mfConf = {
      mergeRuntime: true,
      name: 'app1',
      library: {
        type: config.output.libraryTarget,
        name: 'app1',
      },
      filename: 'static/runtime/app1RemoteEntry.js',
      remotes: {},
      exposes: {
        './thanatos': './components/thanatos',
      },
    };
    config.cache = false;
    withModuleFederation(config, options, mfConf);
    if (!isServer) {
        config.output.publicPath = 'http://localhost:3001/_next/';
    }

    return config;
  },

  webpackDevMiddleware: (config) => {
    // Perform customizations to webpack dev middleware config
    // Important: return the modified config
    return config;
  },
};

app2 next.config.js

const { withModuleFederation } = require('@module-federation/nextjs-mf');
module.exports = {
  webpack5: true,
  images: {
    domains: ['static.wikia.nocookie.net'],
  },
  webpack: (config, options) => {
    const { isServer } = options;
    const mfConf = {
      mergeRuntime: true,
      name: 'app2',
      library: {
        type: config.output.libraryTarget,
        name: 'app2',
      },
      filename: 'static/runtime/app2RemoteEntry.js',
      remotes: {},
      exposes: {
        './zagreus': './components/zagreus',
      },
    };
    config.cache = false;
    withModuleFederation(config, options, mfConf);
    if (!isServer) {
        config.output.publicPath = 'http://localhost:3002/_next/';
    }

    return config;
  },

  webpackDevMiddleware: (config) => {
    // Perform customizations to webpack dev middleware config
    // Important: return the modified config
    return config;
  },
};

base next.config.js

const { withModuleFederation } = require('@module-federation/nextjs-mf');
const path = require('path');

// For SSR, resolve to disk path (or you can use code streaming if you have access)
// in production use the chunks
const ssrRemoteEntry = (app) =>
  process.env.NODE_ENV === 'production'
    ? path.join(
        `<remotes-path>/${app}/.next/server/chunks/static/runtime/remoteEntry.js`
      )
    : path.resolve(
        __dirname,
        `../${app}/.next/server/static/runtime/remoteEntry.js`
      );

module.exports = {
  webpack5: true,
  images: {
    domains: ['static.wikia.nocookie.net'],
  },
  webpack: (config, options) => {
    const { isServer } = options;
    const mfConf = {
      name: 'base',
      library: {
        type: config.output.libraryTarget,
        name: 'base',
      },
      remotes: {
        app1: isServer ? ssrRemoteEntry('app1') : 'app1',
        app2: isServer ? ssrRemoteEntry('app2') : 'app2',
      },
      exposes: {},
    };
    config.cache = false;
    withModuleFederation(config, options, mfConf);

    return config;
  },

  webpackDevMiddleware: (config) => {
    // Perform customizations to webpack dev middleware config
    // Important: return the modified config
    return config;
  },
};

base _document.js

import Document, { Html, Head, Main, NextScript } from 'next/document';
class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);
    return { ...initialProps };
  }

  render() {
    return (
      <Html>
        <script src="http://localhost:3001/_next/static/runtime/app1RemoteEntry.js" />
        <script src="http://localhost:3002/_next/static/runtime/app2RemoteEntry.js" />
        <Head>
          <link rel="icon" href="/favicon.ico" />
          <meta
            name="description"
            content="Demo for Microfrontends using Module Federation"
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

When I run the three applications, on base application I can only see the page for base but when I click on the other two buttons want to navigate to app1 and app2, the browser shows the blank page.enter image description here

enter image description here

enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

惜醉颜 2025-02-10 05:05:23

我可能有解决方案。您需要在Next.config.js中执行的操作是将您的URL添加到.env文件中。从那里,您告诉基本应用程序导航到URL和路线。

这是我所做的事情的示例:

const { APP1_URL, APP2_URL } = process.env;

module.exports = {
   webpackDevMiddleware: (config) => {
      config.watchOptions = {
         poll: 1000,
         aggregateTimeout: 300,
      };

      return config;
   },
   output: "standalone",
   async rewrites() {
      return [
         {
            source: "/dashboard",
            destination: "/",
         },
         {
            source: "/app1",
            destination: `${APP1_URL}/app1`,
         },
         {
            source: "/app1/:path*",
            destination: `${APP1_URL}/app1/:path*`,
         },
         {
            source: "/app2",
            destination: `${APP2_URL}/app2`,
         },
         {
            source: "/app2/:path*",
            destination: `${APP2_URL}/app2/:path*`,
         },
      ];
   },
};

棘手的部分是回到您的基地。这是App1的Next.config.js的示例:

module.exports = {
   webpackDevMiddleware: (config) => {
      config.watchOptions = {
         poll: 1000,
         aggregateTimeout: 300,
      };

      return config;
   },
   basePath: "/app1",
   output: "standalone",
   async redirects() {
      return [
         {
            source: "/app1/dashboard",
            destination: "/",
            basePath: false,
            permanent: true,
         },
         {
            source: "/app1/app1",
            destination: "/app1",
            basePath: false,
            permanent: true,
         },
      ];
   },
};

注意WebPackDevmiddleware只是为了令人耳目一新。如果您不想要的话,您不需要它。

I may have the solution for you. What you need to do in the next.config.js is add your URLs to your .env file. From there, you tell your base app to navigate to the URL and route.

Here is a sample of what I have done:

const { APP1_URL, APP2_URL } = process.env;

module.exports = {
   webpackDevMiddleware: (config) => {
      config.watchOptions = {
         poll: 1000,
         aggregateTimeout: 300,
      };

      return config;
   },
   output: "standalone",
   async rewrites() {
      return [
         {
            source: "/dashboard",
            destination: "/",
         },
         {
            source: "/app1",
            destination: `${APP1_URL}/app1`,
         },
         {
            source: "/app1/:path*",
            destination: `${APP1_URL}/app1/:path*`,
         },
         {
            source: "/app2",
            destination: `${APP2_URL}/app2`,
         },
         {
            source: "/app2/:path*",
            destination: `${APP2_URL}/app2/:path*`,
         },
      ];
   },
};

The tricky part is getting back to your base. Here is a sample for App1's next.config.js:

module.exports = {
   webpackDevMiddleware: (config) => {
      config.watchOptions = {
         poll: 1000,
         aggregateTimeout: 300,
      };

      return config;
   },
   basePath: "/app1",
   output: "standalone",
   async redirects() {
      return [
         {
            source: "/app1/dashboard",
            destination: "/",
            basePath: false,
            permanent: true,
         },
         {
            source: "/app1/app1",
            destination: "/app1",
            basePath: false,
            permanent: true,
         },
      ];
   },
};

Note the webpackDevMiddleware is just for hot refreshing. You don't need it if you don't want.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文