nanoevents: Importing error in React Native starting from nanoevents 3.0 version

Because .cjs source extension is not very commonly used and React Native do not know it and interprets as part of filename.

error: bundling failed: Error: While trying to resolve module `nanoevents` from file `.../src/api/ws/client.js`, the package `.../node_modules/nanoevents/package.json` was successfully found. However, this package itself specifies a `main` module field that could not be resolved (`.../node_modules/nanoevents/index.cjs`. Indeed, none of these files exist:

  * .../node_modules/nanoevents/index.cjs(.native|.android.js|.native.js|.js|.android.json|.native.json|.json|.android.ts|.native.ts|.ts|.android.tsx|.native.tsx|.tsx)
  * .../node_modules/nanoevents/index.cjs/index(.native|.android.js|.native.js|.js|.android.json|.native.json|.json|.android.ts|.native.ts|.ts|.android.tsx|.native.tsx|.tsx)

Workarounds:

  1. import {createNanoEvents} from 'nanoevents/index'
  2. add .cjs extension to metro.config.js:
const {getDefaultValues} = require('metro-config/src/defaults')
const {resolver: {sourceExts}} = getDefaultValues()

module.exports = {
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: false,
      },
    }),
  },
  resolver: {
    sourceExts: [...sourceExts, 'cjs'],
  },
}

But it will be nice nanoevents package do not cause the error and works without need an additional configuration.

  1. Use index.cjs.js file name instead
  2. Or add react-native field to package.json with index.js value

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 18 (12 by maintainers)

Commits related to this issue

Most upvoted comments

@ai @farwayer @TrySound I would be curious to learn from you if you think package.json should be included in all pkg.exports fields or whether this is a “bug” in react-native: https://github.com/react-native-community/cli/issues/1168

@farwayer thanks for fact that React Native overwrite resolverMainFields.

I simplify React Native support with native ESM and without extra files https://github.com/ai/dual-publish/commit/9d8b0733a7bab937cddac4c7e537f12648a41cde

New Dual Publish and Nano Events versions were published.

@ai fix “csj” in metro issue

Use index.cjs.js file name instead

We need .cjs name, because otherwise, Node.js will load it as ES module.

nanoevents is first package I ran into this problem with React Native. Does all other packagers know about .cjs?

Most of the npm packages do not provide ESM for Node.js. Most of the packages provide ESM for webpack only, which does not follow the spec.

If it is standard extension than of course it is better to add support of this to metro bundler.

Yeap, it is part of Node.js standard.

Because .cjs source extension is not very commonly used and React Native do not know it and interprets as part of filename.

Yes, we should start by creating an issue in the metro builder. Can you do it since I am less familiar with the React Native ecosystem?

I do not like “it is your tool” problem answer in the issue. You have a real problem and we need a solution.

Right now I see this solution:

  1. Put ESM file to index.mjs instead of index.js
  2. Put CJS files to index.js instead of index.cjs
  3. Remove type: 'module' from package.json
  4. Use Conditional Exports to load index.mjs on require('nanoevents/index.js').

Unfortunately, we need to support all kind of ESM environments:

  1. Node.js
  2. Webpack, Parcel, Rollup
  3. Loading ESM files to the browsers without bundler by jsDelivr

Unfortunately the index.js → index.mjs fix will force all CDN users to manually add index.mjs to the URLs. I will think about the better solution today and, if I will not find the best solution, I will think about who we should suffer in the situation.