webpack: Resolve module (mjs) incorrectly when using Module Federation Plugin

Bug report

What is the current behavior?

When using swr/infinite with swr>1.1.2 dependency and sharing it with Module Federation (SharePlugin)

    new webpack.container.ModuleFederationPlugin({
      shared: ['swr'],
    }),

We encountered this error:
with-mf

If the current behavior is a bug, please provide the steps to reproduce.

I created this repo that reproduces the issue: https://github.com/tzachbon/swr-mf-error

All you have to do is to use SWR >= 1.2.0 and add it to the shared array in the Module Federation Plugin. In the change log here: https://github.com/vercel/swr/compare/1.1.2...1.2.0 I found a few things that might be the reason.

In my code, I try to import swr/infinite, which now has exports field in its package json:

  "exports": "./dist/index.mjs",

In the swr package json, the exports field now has a filename that ends with mjsextension:

    "./infinite": {
      "import": "./infinite/dist/index.mjs",
      "module": "./infinite/dist/index.esm.js",
      "require": "./infinite/dist/index.js",
      "types": "./infinite/dist/infinite/index.d.ts"
    },

When I manually changed the filename to .js it worked.

What is the expected behavior?

To resolve it like .js

Other relevant information: webpack version: 5.74.0 Node.js version: 16.15.0 Operating System: MacBook Pro (16-inch, 2021) Additional tools: swr: 1.3.0

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 8
  • Comments: 22 (9 by maintainers)

Most upvoted comments

You can skip this issue by also sharing any submodule of swr changing this:

new webpack.container.ModuleFederationPlugin({
    shared: ['swr'],
}),  

to this

new webpack.container.ModuleFederationPlugin({
    shared: ['swr/'],
}),  

Yeah, looks like a bug, someone wants to send a PR?

I’ve been able to figure out that the issue is in the detection of exportsType of a shared module when passing through from another shared module, it comes back as default-with-named instead of dynamic, which then means that interopDefaultAccessUsed never gets set to true, and compatGetDefaultExport never gets added to the build. What I can’t figure out is why it breaks only when coming in through another shared module. If imported as a first-level shared module, this doesn’t happen, the file is correctly typed as dynamic.

Just gonna add a few keywords here for google, because it took me WEEKS to find this issue:

graphql-tag default export import TypeError: graphql_tag__WEBPACK_IMPORTED_MODULE_0__ is not a function

You can skip this issue by also sharing any submodule of swr changing this:

new webpack.container.ModuleFederationPlugin({
    shared: ['swr'],
}),  

to this

new webpack.container.ModuleFederationPlugin({
    shared: ['swr/'],
}),  

Thanks! It does work but isn’t it a workaround for an existing bug with the resolution?

Add some addition infomration: The esm assets of swr ("import" condition from "exports" field in package.json) is picked up by webpack correctly, but it seems still act like commonjs module with module federation plugin.

If I removed the import export condition then everything works well. But it’s still picking up the "module" condition from "exports", which uses exact same esm format like mjs assets does. I think webpack should treat the "module" and "import" condition similarly?

I’m certainly no expert in how everything weaves together but if this is a question of resolution and it appears to be triggered by shared according to the bug replication by @hangboss1761 I would say a good starting place is here (The link will open the GitHub dev editor)

Relative path in code: webpack/webpack/lib/sharing/ProvideSharedPlugin.js

I don’t have time to take a deep dive at the moment but hopefully, that helps @tzachbon

Later I can take a look, ran into this I believe after adding the exports field to my package, and the ESM was resolved but then it appeared to not see exports I’ll blame that piece on my resolution. Upon inspection, the exports object just didn’t exist in the generated Module, once again probably my configuration but if that helps there you go.

However, I resolved it by setting it back to my UMD build via an explicit path. The trailing slash did not work with my scoped package.

If the aforementioned behavior is connected then, it looks like the path came from the ConsumeSharedPlugin.

Thanks! It does work but isn’t it a workaround for an existing bug with the resolution?

@tzachbon Correct, this issue still needs to be addressed.

@keropodium Thanks! I checked, it resolved the issue! cc @tzachbon