core: Breaking change to module sharing

BREAKING-CHANGE: Previously, we used to “rekey” all shared packages used in a host in order to prevent eager consumption issues. However, this caused unforeseen issues when trying to share a singleton package, as the package would end up being bundled multiple times per page.

As a result, we have had to stop rekeying shared modules in userland and only do so on internal Next packages themselves.

If you need to dangerously share a package using the old method, you can do so by using the following code:

             ```js
             const shared = {
               fakeLodash: {
                 import: "lodash",
                 shareKey: "lodash",
               }
             }
             ```

Please note that this method is now considered dangerous and should be used with caution.

BREAKING CHANGE: Previously, we used to “rekey” all shared packages used in a host in order to prevent eager consumption issues. However, this caused unforeseen issues when trying to share a singleton package, as the package would end up being bundled multiple times per page.

Fixing eager issues

To fix eager sharing issues, you need to ensure theres a async import BEFORE the first sync import of a shared module. This is common outside of next where we use import('./bootsrtap') in the entrypoint.

To do the same in next.js, theres a few options:

const page = import('../async-pages/checkout');

const Page = dynamic(() => import('../async-pages/checkout'));
Page.getInitialProps = async ctx => {
  const getInitialProps = (await page).default?.getInitialProps;
  if (getInitialProps) {
    return getInitialProps(ctx);
  }
  return {};
};

or any of the next data conventions.

const page = import('../async-pages/checkout');

const Page = dynamic(() => import('../async-pages/checkout'));
export const getServerSideProps = async ctx => {
  const getServerSideProps = (await page).getServerSideProps
  if (getServerSideProps) {
    return getServerSideProps(ctx);
  }
  return {};
};

You can also use the plugins built in “automatic async boundary”, which dynamic re-exports pages for you instead of manually like shown above. DO NOT use dynamic re-exports AND boundaryLoader, boundaryLoader does this automatically - if you do it as well - it will be double re-exported

{
  extraOptions: {
    automaticAsyncBoundary:true
  }
}

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 15 (6 by maintainers)

Most upvoted comments

So what is the new method to share a lib? With the lasted version I’m getting “Error: Shared module is not available for eager consumption: webpack/sharing/consume/default/@mui/material/@mui/material”:

shared: {
          '@mui/material': {
            singleton: true,
            requiredVersion: false,
          },
          '@mui/material/': {
            singleton: true,
            requiredVersion: false,
          },

In my case most of the libs are shared and are adding a lot of height to the remote components.

same.

Error: Shared module is not available for eager consumption:

also getting the same error doing

     'myModule': {
                 import: "myModule",
                 shareKey: "myModule",
               }

automaticAsyncBoundary looks to be resolved 👍 . Although I’m having trouble sharing react contexts over federated SSR, that may be a different issue?

Like this

https://github.com/module-federation/module-federation-examples/blob/master/nextjs-react/host-app/pages/_app.js

All pages need async imports before you use statically imported dependencies.

This is like the import(bootstrap) examples in all non next apps.

You need to async import your pages.

Take a look at automaticAsyncBoundary: true

You can also look at the example in mod fed examples repo.

There needs to be a async import above in the tree. BoundaryLoader tries to automatically do it. But manually you can import() your next page from another folder.