metro icon indicating copy to clipboard operation
metro copied to clipboard

Feature: support new package.json exports field

Open jsamr opened this issue 3 years ago β€’ 7 comments

exports field is a new standard which adoption will inevitably grow further as the ecosystem switches to full ESM as NodeJS 10 reaches EOL. It's probably best to support it before things break. Features:

  • Export submodules with sub-path exports;
  • Specific exports for both CJS and ESM modules.

Example of subpath exports from NodeJS docs:

{
  "type": "module",
  "name": "es-module-package",
  "main": "./main.js",
  "exports": {
    ".": "./main.js",
    "./submodule": "./src/submodule.js"
  }
}

The consumer of the library can now use:

import submodule from 'es-module-package/submodule';
// Loads ./node_modules/es-module-package/src/submodule.js

jsamr avatar Apr 28 '21 18:04 jsamr

Is there any plan to support this any time soon?

kamleshchandnani avatar Jun 23 '21 13:06 kamleshchandnani

Any workarounds?

alamothe avatar Mar 01 '22 04:03 alamothe

Here's a workaround I used. In https://github.com/tinyplex/tinybase, I omit the "main" field in my package.json to prefer "exports".

To get this to work with Metro, I added a "react-native" field that points to the file. It's apparently not documented, but this is used as a higher-priority location than "main". "browser" is another option you might prefer.

Works a charm in https://github.com/tinyplex/tinybase/issues/17:

image

jamesgpearce avatar Apr 15 '22 07:04 jamesgpearce

@robhogan any plans to support this? or we can enable it if it's behind some flag?

kamleshchandnani avatar May 16 '22 15:05 kamleshchandnani

Without this feature it basically makes impossible to use most of ESM modules out there with react-native.

pleerock avatar Aug 19 '22 16:08 pleerock

Hi all πŸ‘‹, happy to share that exports field support is on our roadmap for the second half of 2022. We haven't scheduled this work immediately, but once we have progress I will make sure to post an update here.

huntie avatar Aug 24 '22 17:08 huntie

That's good news. @huntie hopefully this can get bumped up in priority. Lots of popular packages are beginning to drop commonjs support. Without full ESM support in metro react-native users are stuck on increasingly old/broken/insecure versions of packages.

evelant avatar Sep 07 '22 02:09 evelant

Hey Folks πŸ‘‹ Since we are in the seccond half of 2022 already do we have an estimation when this feature will arrive or is there any workaround already ?

Tjerk-Haaye-Henricus avatar Oct 17 '22 12:10 Tjerk-Haaye-Henricus

Update:

  • We've been working on the design for this feature β€” now shared at https://github.com/react-native-community/discussions-and-proposals/pull/534. The details tacked in this proposal are essential for us to align on building the right thing and making implementation as swift and correct as possible.
  • Implementation hasn't yet begun β€”Β this may kick off in the next month.

Workarounds for apps remain possible by configuring resolver.resolveRequest (configuring as documented). This will allow you to set overrides for specific import paths, to patch "exports" functionality on a case-by-case basis.

huntie avatar Oct 17 '22 16:10 huntie

Wow thats great, thanks for your answer πŸ™ I'm glad to have a workaround. I will try it immediately πŸ€“

Tjerk-Haaye-Henricus avatar Oct 17 '22 16:10 Tjerk-Haaye-Henricus

We ran into this issue while using fp-ts-std. Our current workaround within a monorepo setup is this:

// packages/app/metro.config.js

const path = require('path')
const { createMetroConfiguration } = require('expo-yarn-workspaces')

module.exports = (() => {
  const workspaceRoot = path.resolve(__dirname, '../..')
  const config = createMetroConfiguration(__dirname)

  const { resolver } = config

  config.resolver = {
    ...resolver,
    extraNodeModules: new Proxy(resolver.extraNodeModules, {
      get: (target, name) => (name === 'fp-ts-std' ? path.resolve(workspaceRoot, `node_modules/${name}/dist/esm`) : undefined)
    })
  }

  return config
})()

david-zacharias avatar Oct 18 '22 11:10 david-zacharias

Also missing is subpath imports, which was added in Node v14.6.0, v12.19.0.

matthew-dean avatar Nov 22 '22 20:11 matthew-dean

All bundlers will always be behind nodejs itself. Makes me wonder why nodejs can't bundle JS itself.

pke avatar Dec 01 '22 10:12 pke

Any updates? This is painful for JS library authors.

paulmillr avatar Feb 14 '23 22:02 paulmillr

Yes I can give an update! πŸ˜… The implementation is well underway β€”Β the most recent batch of commits starts with 38b96f872a92d0f0650c9af0250c8dc5599a6e62.

We're planning to ship Package Exports in the next Metro release, and β€”Β fingers crossed β€” in time for React Native 0.72. For this launch, the feature will be disabled by default and marked "unstable", enabled by the resolver option unstable_enablePackageExports.

Furthermore, this will be accompanied by a blog post on the React Native blog. I'll be writing up an explanation of the feature, plus instructions and gotchas for app developers and package maintainers who want to enable the feature today.

After this, we're aiming to stabilise Package Exports for React Native 0.73 (pending other priorities).

huntie avatar Feb 17 '23 11:02 huntie

Great news, it is in beta now! 😍

https://reactnative.dev/blog/2023/06/21/0.72-metro-package-exports-symlinks#new-metro-features

image

Albert-Gao avatar Jun 28 '23 01:06 Albert-Gao