Skip to content

Remove 'import' from default Package Exports conditions - #36584

Closed
huntie wants to merge 1 commit into
react:mainfrom
huntie:export-D44303559
Closed

Remove 'import' from default Package Exports conditions#36584
huntie wants to merge 1 commit into
react:mainfrom
huntie:export-D44303559

Conversation

@huntie

@huntiehuntie commented Mar 22, 2023

Copy link
Copy Markdown
Collaborator

Summary:
The Exports RFC had assumed that supporting the "import" condition was a syntax-only difference, given we are not in a Node.js environment — and so was worthwhile to support for maximal ecosystem compatibility.

image

This assumption is similar to --moduleResolution bundler in TypeScript 5.0:

bundlers and runtimes that include a range of Node-like resolution features and ESM syntax, but do not enforce the strict resolution rules that accompany ES modules in Node or in the browser
-- microsoft/TypeScript#51669 (comment)

However, @robhogan has rightly pointed out that we should not do this!

  • ESM (once transpiled) is not simply a stricter subset of in-scope features supported by CJS. For example, it supports top-level async, which would be breaking at runtime.
  • We recently made the same change for our Jest environment:

As such, we are erring on the side of correctness and supporting only ['require', 'react-native'] in our defaults. At runtime, all code run by React Native is anticipated to be CommonJS. "exports" will instead allow React Native to correctly select the CommonJS versions of modules from all npm packages.

  • Metro will require future extended behaviour in order to dynamically set 'import' based on how the module is imported/require()d. For now this is not in scope.

Changelog:
[General][Changed] - Default condition set for experimental Package Exports is now ['require', 'react-native']

Metro changelog: [Experimental] Package Exports unstable_conditionNames now defaults to ['require']

Differential Revision: D44303559

@facebook-github-botfacebook-github-bot added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Facebook Partner: Facebook Partner fb-exported labels Mar 22, 2023
@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D44303559

@analysis-bot

analysis-bot commented Mar 22, 2023

Copy link
Copy Markdown
PlatformEngineArchSize (bytes)Diff
androidhermesarm64-v8a8,520,044+0
androidhermesarmeabi-v7a7,835,942+0
androidhermesx868,999,858+0
androidhermesx86_648,855,178+0
androidjscarm64-v8a9,141,421+0
androidjscarmeabi-v7a8,333,361+0
androidjscx869,195,916+0
androidjscx86_649,454,039+0

Base commit: 0443c2a
Branch: main

huntie added a commit to huntie/metro that referenced this pull request Mar 23, 2023
Summary:
X-link: react/react-native#36584
The [Exports RFC](https://github.com/react-native-community/discussions-and-proposals/blob/main/proposals/0534-metro-package-exports-support.md) had assumed that supporting the `"import"` condition was a syntax-only difference, given we are not in a Node.js environment — and so was worthwhile to support for maximal ecosystem compatibility.
{F915841105}
This assumption is similar to [`--moduleResolution bundler` in TypeScript 5.0](microsoft/TypeScript#51669):
> bundlers and runtimes that include a range of Node-like resolution features and ESM syntax, but do not enforce the strict resolution rules that accompany ES modules in Node or in the browser
> -- microsoft/TypeScript#51669 (comment)
However, robhogan has rightly pointed out that **we should not do this!**
- ESM (once transpiled) is **not** simply a stricter subset of in-scope features supported by CJS. For example, it supports top-level async, which would be breaking at runtime.
- We recently made the same change for our Jest environment:
- react/react-native@681d7f8
As such, we are erring on the side of correctness and supporting only `['require', 'react-native']` in our defaults. At runtime, all code run by React Native is anticipated to be CommonJS. `"exports"` will instead allow React Native to correctly select the CommonJS versions of modules from all npm packages.
Changelog:
[Change][General] Default condition set for experimental Package Exports is now `['require', 'react-native']`
Metro changelog: [Experimental] Package Exports `unstable_conditionNames` now defaults to `['require']`
Differential Revision: D44303559
fbshipit-source-id: 703561b16d0afc7723b763cdfd61236b46202f50
huntie added a commit to huntie/metro that referenced this pull request Mar 23, 2023
Summary:
Pull Request resolved: react#955
X-link: react/react-native#36584
Changelog:
[General][Changed] - Default condition set for experimental Package Exports is now `['require', 'react-native']`
The [Exports RFC](https://github.com/react-native-community/discussions-and-proposals/blob/main/proposals/0534-metro-package-exports-support.md) had assumed that supporting the `"import"` condition was a syntax-only difference, given we are not in a Node.js environment — and so was worthwhile to support for maximal ecosystem compatibility.
{F915841105}
This assumption is similar to [`--moduleResolution bundler` in TypeScript 5.0](microsoft/TypeScript#51669):
> bundlers and runtimes that include a range of Node-like resolution features and ESM syntax, but do not enforce the strict resolution rules that accompany ES modules in Node or in the browser
> -- microsoft/TypeScript#51669 (comment)
However, robhogan has rightly pointed out that **we should not do this!**
- ESM (once transpiled) is **not** simply a stricter subset of in-scope features supported by CJS. For example, it supports top-level async, which would be breaking at runtime.
- We recently made the same change for our Jest environment:
- react/react-native@681d7f8
As such, we are erring on the side of correctness and supporting only `['require', 'react-native']` in our defaults. At runtime, all code run by React Native is anticipated to be CommonJS. `"exports"` will instead allow React Native to correctly select the CommonJS versions of modules from all npm packages.
Metro changelog: [Experimental] Package Exports `unstable_conditionNames` now defaults to `['require']`
Differential Revision: D44303559
fbshipit-source-id: fd32e5664679fa6d8fe8c6dca8c3d4b43d867589
@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D44303559

Summary:
X-link: react/metro#955
Pull Request resolved: #36584
Changelog:
[General][Changed] - Default condition set for experimental Package Exports is now `['require', 'react-native']`
The [Exports RFC](https://github.com/react-native-community/discussions-and-proposals/blob/main/proposals/0534-metro-package-exports-support.md) had assumed that supporting the `"import"` condition was a syntax-only difference, given we are not in a Node.js environment — and so was worthwhile to support for maximal ecosystem compatibility.
{F915841105}
This assumption is similar to [`--moduleResolution bundler` in TypeScript 5.0](microsoft/TypeScript#51669):
> bundlers and runtimes that include a range of Node-like resolution features and ESM syntax, but do not enforce the strict resolution rules that accompany ES modules in Node or in the browser
> -- microsoft/TypeScript#51669 (comment)
However, robhogan has rightly pointed out that **we should not do this!**
- ESM (once transpiled) is **not** simply a stricter subset of in-scope features supported by CJS. For example, it supports top-level async, which would be breaking at runtime.
- We recently made the same change for our Jest environment:
- 681d7f8
As such, we are erring on the side of correctness and supporting only `['require', 'react-native']` in our defaults. At runtime, all code run by React Native is anticipated to be CommonJS. `"exports"` will instead allow React Native to correctly select the CommonJS versions of modules from all npm packages.
Metro changelog: [Experimental] Package Exports `unstable_conditionNames` now defaults to `['require']`
Reviewed By: robhogan
Differential Revision: D44303559
fbshipit-source-id: 1198de4e629e23f1c7a36e5d1d23d2013203d3db
@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D44303559

huntie added a commit to huntie/metro that referenced this pull request Mar 23, 2023
Summary:
Pull Request resolved: react#955
X-link: react/react-native#36584
Changelog:
[General][Changed] - Default condition set for experimental Package Exports is now `['require', 'react-native']`
The [Exports RFC](https://github.com/react-native-community/discussions-and-proposals/blob/main/proposals/0534-metro-package-exports-support.md) had assumed that supporting the `"import"` condition was a syntax-only difference, given we are not in a Node.js environment — and so was worthwhile to support for maximal ecosystem compatibility.
{F915841105}
This assumption is similar to [`--moduleResolution bundler` in TypeScript 5.0](microsoft/TypeScript#51669):
> bundlers and runtimes that include a range of Node-like resolution features and ESM syntax, but do not enforce the strict resolution rules that accompany ES modules in Node or in the browser
> -- microsoft/TypeScript#51669 (comment)
However, robhogan has rightly pointed out that **we should not do this!**
- ESM (once transpiled) is **not** simply a stricter subset of in-scope features supported by CJS. For example, it supports top-level async, which would be breaking at runtime.
- We recently made the same change for our Jest environment:
- react/react-native@681d7f8
As such, we are erring on the side of correctness and supporting only `['require', 'react-native']` in our defaults. At runtime, all code run by React Native is anticipated to be CommonJS. `"exports"` will instead allow React Native to correctly select the CommonJS versions of modules from all npm packages.
Metro changelog: [Experimental] Package Exports `unstable_conditionNames` now defaults to `['require']`
Reviewed By: robhogan
Differential Revision: D44303559
fbshipit-source-id: 0d7395ad0a44019ef4b2cad0b43d78dcecc5ecd0
facebook-github-bot pushed a commit to react/metro that referenced this pull request Mar 23, 2023
Summary:
Pull Request resolved: #955
X-link: react/react-native#36584
Changelog:
[General][Changed] - Default condition set for experimental Package Exports is now `['require', 'react-native']`
The [Exports RFC](https://github.com/react-native-community/discussions-and-proposals/blob/main/proposals/0534-metro-package-exports-support.md) had assumed that supporting the `"import"` condition was a syntax-only difference, given we are not in a Node.js environment — and so was worthwhile to support for maximal ecosystem compatibility.
{F915841105}
This assumption is similar to [`--moduleResolution bundler` in TypeScript 5.0](microsoft/TypeScript#51669):
> bundlers and runtimes that include a range of Node-like resolution features and ESM syntax, but do not enforce the strict resolution rules that accompany ES modules in Node or in the browser
> -- microsoft/TypeScript#51669 (comment)
However, robhogan has rightly pointed out that **we should not do this!**
- ESM (once transpiled) is **not** simply a stricter subset of in-scope features supported by CJS. For example, it supports top-level async, which would be breaking at runtime.
- We recently made the same change for our Jest environment:
- react/react-native@681d7f8
As such, we are erring on the side of correctness and supporting only `['require', 'react-native']` in our defaults. At runtime, all code run by React Native is anticipated to be CommonJS. `"exports"` will instead allow React Native to correctly select the CommonJS versions of modules from all npm packages.
Metro changelog: [Experimental] Package Exports `unstable_conditionNames` now defaults to `['require']`
Reviewed By: robhogan
Differential Revision: D44303559
fbshipit-source-id: 0077e547e7775e53d1e4e9c3a9d01347f4fb7d4a
@facebook-github-botfacebook-github-bot added the Merged This PR has been merged. label Mar 23, 2023
@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request has been merged in 308838c.

cipolleschi pushed a commit that referenced this pull request Mar 31, 2023
Summary:
X-link: react/metro#955
Pull Request resolved: #36584
Changelog:
[General][Changed] - Default condition set for experimental Package Exports is now `['require', 'react-native']`
The [Exports RFC](https://github.com/react-native-community/discussions-and-proposals/blob/main/proposals/0534-metro-package-exports-support.md) had assumed that supporting the `"import"` condition was a syntax-only difference, given we are not in a Node.js environment — and so was worthwhile to support for maximal ecosystem compatibility.
{F915841105}
This assumption is similar to [`--moduleResolution bundler` in TypeScript 5.0](microsoft/TypeScript#51669):
> bundlers and runtimes that include a range of Node-like resolution features and ESM syntax, but do not enforce the strict resolution rules that accompany ES modules in Node or in the browser
> -- microsoft/TypeScript#51669 (comment)
However, robhogan has rightly pointed out that **we should not do this!**
- ESM (once transpiled) is **not** simply a stricter subset of in-scope features supported by CJS. For example, it supports top-level async, which would be breaking at runtime.
- We recently made the same change for our Jest environment:
- 681d7f8
As such, we are erring on the side of correctness and supporting only `['require', 'react-native']` in our defaults. At runtime, all code run by React Native is anticipated to be CommonJS. `"exports"` will instead allow React Native to correctly select the CommonJS versions of modules from all npm packages.
Metro changelog: [Experimental] Package Exports `unstable_conditionNames` now defaults to `['require']`
Reviewed By: robhogan
Differential Revision: D44303559
fbshipit-source-id: 0077e547e7775e53d1e4e9c3a9d01347f4fb7d4a
@huntie

Copy link
Copy Markdown
CollaboratorAuthor

Counterexample for this is packages which (somewhat incorrectly) specify "import" but not a "default" condition match 🫤: https://github.com/ipfs/js-ipfs-unixfs/blob/master/packages/ipfs-unixfs-importer/package.json. These cases won't work better out-of-the-box.

@robhogan

robhogan commented Apr 7, 2023

Copy link
Copy Markdown
Collaborator

That’s sort of unfortunate - but that’s an example of a package which only distributes ESM (see index.js), so there is simply no way to require it - Node JS won’t let you either. There could legally be top level await in there, etc - it’s proper ESM (and the fact that it’s set up that way might be an indication that the authors don’t want to be constrained by CJS).

Node would let you await import() it from CommonJS, so to complete* the work here we ought to allow that from Metro - in that case, the conditions would include import but not require, and we’d be able to resolve it.

[*] - To complete the resolver work, that is - unfortunately there’s a whole can of worms here as to how Metro should deal with ESM. We can (do) YOLO transform it to CJS and turn all its imports into requires, which isn’t semantically sound and will break on ESM->ESM dependencies like this one. Not transforming it isn’t an option because Hermes doesn’t support ESM. There might be a pragmatic “as close to correct as possible” path we can walk here but I’m not sure exactly where that is. Such is the state of ESM in JS today. One to chew over/discuss on Tuesday!

facebook-github-bot pushed a commit that referenced this pull request Apr 14, 2023
Summary:
Pull Request resolved: #36902
Reverts #36584.
Since we've come across example packages (typically targeting Node.js) which only distribute ESM, we believe it's more helpful to return to asserting the `"import"` condition by default, for maximum compatibility. The above issue and comments outline the pros/cons.
Changelog:
[General][Changed] - Default condition set for experimental Package Exports is now ['require', 'import', 'react-native']
Metro changelog: [Experimental] Package Exports unstable_conditionNames now defaults to ['require', 'import']
Reviewed By: robhogan
Differential Revision: D44962143
fbshipit-source-id: 004172388916c902469b49cfc920ebe13c62c430
facebook-github-bot pushed a commit to react/metro that referenced this pull request Apr 14, 2023
Summary:
X-link: react/react-native#36902
Reverts react/react-native#36584.
Since we've come across example packages (typically targeting Node.js) which only distribute ESM, we believe it's more helpful to return to asserting the `"import"` condition by default, for maximum compatibility. The above issue and comments outline the pros/cons.
Changelog:
[General][Changed] - Default condition set for experimental Package Exports is now ['require', 'import', 'react-native']
Metro changelog: [Experimental] Package Exports unstable_conditionNames now defaults to ['require', 'import']
Reviewed By: robhogan
Differential Revision: D44962143
fbshipit-source-id: 004172388916c902469b49cfc920ebe13c62c430
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA SignedThis label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.fb-exportedMergedThis PR has been merged.p: FacebookPartner: FacebookPartner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@huntie@facebook-github-bot@analysis-bot@robhogan