thiskevinwang / thekevinwang-utterances

0 stars 0 forks source link

2021/03/26/micro-frontends-nextjs/ #5

Open utterances-bot opened 2 years ago

utterances-bot commented 2 years ago

Micro Frontends in NextJS with Webpack 5 | Kevin Wang's Blog

Webpack 5's Module Federation makes creating micro frontends straightforward. It is also available in NextJS 10+ via an experimental feature flag and it makes integrating micro frontends a breeze. You first build an external micro frontend and deploy it as a "federated module" to your destination of choice. Then you update some configs in your NextJS application and Webpack does the rest. It's kind of magic 🦄.

https://thekevinwang.com/2021/03/26/micro-frontends-nextjs/

cs1193 commented 2 years ago

Hey @Kevin,

I have been following your blog on NextJS MFE. However I have hit a dead end and would like some help.

I have 2 apps - one shell and other ranked-app

The shell app's next.config.js is

/**
 * @type {import('next').NextConfig}
 */
const nextConfig = {
  /* config options here */
  webpack: (config, options) => {
    const { ModuleFederationPlugin } = options.webpack.container;

    config.plugins.push(
      new ModuleFederationPlugin({
        name: 'webapp',
        remotes: {
          'rankedApp': 'rankedApp@http://localhost:3502/_next/static/chunks/remoteEntry.js'
        }
      })
    );

    config.cache = false;

    return config;
  }
};

module.exports = nextConfig;

and the ranked-app next config is

/**
 * @type {import('next').NextConfig}
 */
const nextConfig = {
  /* config options here */
  webpack: (config, options) => {
    const { ModuleFederationPlugin } = options.webpack.container;

    config.plugins.push(
      new ModuleFederationPlugin({
        name: 'rankedApp',
        library: {
          type: 'var',
          name: 'rankedApp'
        },
        filename: 'static/chunks/remoteEntry.js',
        exposes: {
          './Example': './src/components/Example'
        },
        remotes: {},
        shared: []
      })
    );

    config.cache = false;

    config.output.publicPath = 'http://localhost:3502/_next/';

    return config;
  }
};

module.exports = nextConfig;

However, when I attempt to import the Example component from ranked-app, the remoteEntry gets loaded from http://localhost:3502, but the request for chunk src_component_Example_tsx.js is relative to http://localhost:3501 interesting it ignores publicPath in ranked-app. Any pointers where I am going wrong could be nice to see.

import React, { FC, Fragment } from "react";
import dynamic from 'next/dynamic';

const RankedAppExample = dynamic(
  async () => {
    return await import("rankedApp/Example");
  },
  {
    ssr: false,
    loading: ({ error }) => {
      if (error) {
        return <Fragment>Error</Fragment>;
      }
      return <Fragment>Loading</Fragment>;
    }
  }
);

interface HomeProps {}

const Home: FC<HomeProps> = (props: HomeProps) => {
  return <Fragment>Home <RankedAppExample /></Fragment>;
};

export default Home;
bleugateau commented 1 year ago

@cs1193, I have the same problem have you find a solution ?

Have a great day