Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"exports" config #20

Closed
ForbesLindesay opened this issue Apr 25, 2020 · 39 comments
Closed

"exports" config #20

ForbesLindesay opened this issue Apr 25, 2020 · 39 comments

Comments

@ForbesLindesay
Copy link
Member

Please comment on this issue if you are still experiencing issues wen upgrading to 2.2.1

@ljharb
Copy link

ljharb commented Apr 25, 2020

Repeating my comment from another issue:

If in fact every single possible require path in v2.1 is available in v2.2, then it’s not breaking.

This includes:

is-promise
is-promise/index
is-promise/index.js
is-promise/package
is-promise/package.json

Adding exports is intended (by the node modules group) to be a breaking change in almost every case. Adding ESM after that is what’s not supposed to have to be breaking.

@FritzTheDev
Copy link

I'm still running into issues with 2.2.1: "No Valid Exports main found for <path_to_module>" when I try running npx mrm lint-staged

I won't pretend to understand what the underlying issue is but I can confirm I'm on 2.2.1 at this point.

@ForbesLindesay
Copy link
Member Author

ForbesLindesay commented Apr 25, 2020

@rapdash mrm doesn't look like it has is-promise as a dependency

@RyanZim
Copy link
Contributor

RyanZim commented Apr 25, 2020

@rapdash What's the output of npm list is-promise?

@ForbesLindesay
Copy link
Member Author

@ljharb all those require paths are available.

@FritzTheDev
Copy link

Yarn Why gives me
yarn why v1.22.4
[1/4] 🤔 Why do we have the module "is-promise"...?
[2/4] 🚚 Initialising dependency graph...
[3/4] 🔍 Finding dependency...
[4/4] 🚡 Calculating file sizes...
=> Found "is-promise@2.2.1"
info Reasons this module exists

  • "lint-staged#listr" depends on it
  • Hoisted from "lint-staged#listr#is-promise"
  • Hoisted from "eslint#inquirer#run-async#is-promise"
    info Disk size without dependencies: "20KB"
    info Disk size with unique dependencies: "20KB"
    info Disk size with transitive dependencies: "20KB"
    info Number of shared dependencies: 0
    ✨ Done in 0.23s.

@ljharb
Copy link

ljharb commented Apr 25, 2020

@ForbesLindesay not in latest master - each of them would need to be an explicit key in the exports object. CJS resolution doesn’t apply to export paths.

@ForbesLindesay
Copy link
Member Author

Ah, now I understand, not having package.json on that list by default seems like a pretty bad default.

@RyanZim
Copy link
Contributor

RyanZim commented Apr 25, 2020

@ljharb I get that technically, adding exports removes those import paths. However, it's my understanding that SemVer applies to the documented API. No import path other than is-promise was documented; and in reality, it's highly unlikely that anyone is importing anything other than is-promise.

@FritzTheDev
Copy link

@ForbesLindesay Is that last message directed at me a typo or are you actually saying that
"is-promise" doesn't depend on "is-promise"?

@WhiteJamer
Copy link

I'm tried reinstall create-react-app with:
npm install -g --force create-react-app
and it fix them.

@ForbesLindesay
Copy link
Member Author

2.2.2 removes "exports" so should fix this.

@rapdash sorry, meant to say mrm doesn't depend on is-promise. Can you tell me if 2.2.2 fixes your problem.

@ljharb
Copy link

ljharb commented Apr 25, 2020

Everything reachable is part of the public api imo.

Either way, try requiring your package in node v13.0 and v13.1 and also v13.2. It takes a much more complex exports object to avoid breakage.

If you’re insistent on not reverting and saving it for a v3, I’ll be happy to make a PR in a few hours that exhaustively preserves back compat for all node versions.

@FritzTheDev
Copy link

@ForbesLindesay 2.2.2 did the trick! Thank you to everyone who moved so fast on this.

@RyanZim
Copy link
Contributor

RyanZim commented Apr 25, 2020

@ljharb Yeah, I can certainly see your side of the argument; not sure I 100% agree, but point taken. Will certainly keep that in mind when I add ESM to my own packages. BTW, feels like a blog post/gist about migrating a package from CJS to dual CJS/ESM might be useful to the community, if you're ever in the writing mood. 😀

@RyanZim
Copy link
Contributor

RyanZim commented Apr 25, 2020

@ForbesLindesay You're probably on it, but just in case you're not, https://github.com/then/is-promise/releases should have release notes for the new versions to note the removal of ESM support.

@ForbesLindesay
Copy link
Member Author

@ljharb I've reverted the "exports" bit as a temporary fix. Not being able to add an esm export as a non-breaking change is a pretty big pain point. This could have been resolved with a simple flag to indicate whether all files were importable. Until the situation improves significantly. I will abandon any attempts to support es modules.

@ljharb
Copy link

ljharb commented Apr 25, 2020

Note that you can import CJS, so the only reason anyone ever needs to take any steps to support ESM is if they’d have named exports, in which case that’s a simple wrapper .mjs file.

Adding “exports” is a good idea separate from ESM - it’s just not trivially nonbreaking. I’m still happy to add it for you in a PR in a few hours, if you’re interested.

@eemeli
Copy link

eemeli commented Apr 25, 2020

If adding "exports" to your package.json, including a mapping "./": "./" will allow all package paths to be exported.

@RyanZim
Copy link
Contributor

RyanZim commented Apr 25, 2020

the only reason anyone ever needs to take any steps to support ESM is if they’d have named exports

In the far-distant future, I do forsee tooling that will only work with ESM, that will allow some cool static analysis optimization stuff, but that's way out there.

@kopax
Copy link

kopax commented Apr 25, 2020

I agree with @RyanZim, ljharb I think a blog post explaining how to deal with ESM properly would be a benediction to everyone distributing packages for node. I've read quite a lot, and even after that, I am not sure what is the appropriate way to deal this properly.

@ForbesLindesay
Copy link
Member Author

@ljharb it would be much better, if you have the time, to update the node.js documentation to add a clear warning about the possible breaking change, preferably before the long, incredibly detailed section on the "Dual Package Hazard". If @eemeli's suggestion is accurate, perhaps a note about it could be added as an example. I read the documentation, and then made this change thinking it was pretty safe, that's the problem that needs fixing. This package can stay as is because I don't want to risk another release at this time.

@ForbesLindesay
Copy link
Member Author

some cool static analysis optimization stuff, but that's way out there.

This is exactly the kind of thing I had in mind. For example, I'm not sure how well Rollup handles CommonJS modules, it certainly didn't when it was first released.

@fisker
Copy link

fisker commented Apr 25, 2020

@ForbesLindesay Can you unpublish 2.2.0? So people won't install the wrong version?

@ForbesLindesay
Copy link
Member Author

@fisker done

@badmus306
Copy link

npm install -g --force create-react-app

This fixed it

@benwalio
Copy link

just wanted to add my 2c here, this was my call as requested -

npm list -g is-promise
/usr/local/lib
├─┬ create-react-app@3.4.1
│ └─┬ inquirer@7.0.4
│   └─┬ run-async@2.4.0
│     └── is-promise@2.2.0 
└── is-promise@2.2.2

npm install -g --force create-react-app

this fixed it for me

@ljharb
Copy link

ljharb commented Apr 25, 2020

@RyanZim given dynamic import, and how rarely dynamic/conditional requires are used, i don't think that's true, since you can already do identical static analysis right now with CJS and ESM.

@saparfriday
Copy link

macOS Catalina 10.15.3
Node v14.0.0
is-promise@2.2.2

Unknown error: Error [ERR_INVALID_PACKAGE_TARGET]: Invalid "exports" main target "index.js" defined in the package config /usr/local/lib/node_modules/@angular/cli/node_modules/is-promise/package.json

@ForbesLindesay
Copy link
Member Author

@SapaTech it looks like you still have the outdated is-promise. Can you try doing cat /usr/local/lib/node_modules/@angular/cli/node_modules/is-promise/package.json and checking that the version number is actually 2.2.2?

@gnorbsl
Copy link

gnorbsl commented Apr 26, 2020

Still have the issue @ForbesLindesay

$ cat /usr/lib/node_modules/@angular/cli/node_modules/is-promise/package.json
{
  "_from": "is-promise@^2.1.0",
  "_id": "is-promise@2.2.2",
  "_inBundle": false,
  "_integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==",
  "_location": "/@angular/cli/is-promise",
  "_phantomChildren": {},
  "_requested": {
    "type": "range",
    "registry": true,
    "raw": "is-promise@^2.1.0",
    "name": "is-promise",
    "escapedName": "is-promise",
    "rawSpec": "^2.1.0",
    "saveSpec": null,
    "fetchSpec": "^2.1.0"
  },
  "_requiredBy": [
    "/@angular/cli/run-async"
  ],
  "_resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
  "_shasum": "39ab959ccbf9a774cf079f7b40c7a26f763135f1",
  "_spec": "is-promise@^2.1.0",
  "_where": "/usr/lib/node_modules/@angular/cli/node_modules/run-async",
  "author": {
    "name": "ForbesLindesay"
  },
  "bugs": {
    "url": "https://github.com/then/is-promise/issues"
  },
  "bundleDependencies": false,
  "deprecated": false,
  "description": "Test whether an object looks like a promises-a+ promise",
  "devDependencies": {
    "better-assert": "^1.0.2",
    "mocha": "~1.7.4"
  },
  "files": [
    "index.js",
    "index.mjs"
  ],
  "homepage": "https://github.com/then/is-promise#readme",
  "license": "MIT",
  "main": "./index.js",
  "name": "is-promise",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/then/is-promise.git"
  },
  "scripts": {
    "test": "mocha -R spec"
  },
  "version": "2.2.2"
}

@ForbesLindesay
Copy link
Member Author

@gnorbsl It must be some kind of caching in angular then, since there is no exports listed in that package.json file, so it can't be causing the error message you're seeing.

@jeremylima
Copy link

jeremylima commented Apr 26, 2020

I have the same issue creating a new vue js project. I just installed the latest vue js client npm i -g @vue/cli and when creating a project vue create test-project I got this error:

internal/modules/cjs/loader.js:584
            if (e.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED') throw e;
                                                            ^

Error [ERR_INVALID_PACKAGE_TARGET]: Invalid "exports" main target "index.js" defined in the package config /usr/local/lib/node_modules/@vue/cli/node_modules/is-promise/package.json
    at resolveExportsTarget (internal/modules/cjs/loader.js:542:13)
    at resolveExportsTarget (internal/modules/cjs/loader.js:581:20)
    at applyExports (internal/modules/cjs/loader.js:455:14)
    at resolveExports (internal/modules/cjs/loader.js:508:23)
    at Function.Module._findPath (internal/modules/cjs/loader.js:632:31)
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:1001:27)
    at Function.Module._load (internal/modules/cjs/loader.js:884:27)
    at Module.require (internal/modules/cjs/loader.js:1074:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at Object.<anonymous> (/usr/local/lib/node_modules/@vue/cli/node_modules/run-async/index.js:3:17) {
  code: 'ERR_INVALID_PACKAGE_TARGET'
}
cat /usr/local/lib/node_modules/@vue/cli/node_modules/is-promise/package.json
{
  "_from": "is-promise@^2.1.0",
  "_id": "is-promise@2.2.0",
  "_inBundle": false,
  "_integrity": "sha512-N/4ZxZGjDLAWJQNtcq1/5AOiWTAAhDwnjlaGPaC2+p3pQ+Ka2Dl/EL29DppuoiZ8Xr1/p/9ywBGGzHRPoWKfGA==",
  "_location": "/@vue/cli/is-promise",
  "_phantomChildren": {},
  "_requested": {
    "type": "range",
    "registry": true,
    "raw": "is-promise@^2.1.0",
    "name": "is-promise",
    "escapedName": "is-promise",
    "rawSpec": "^2.1.0",
    "saveSpec": null,
    "fetchSpec": "^2.1.0"
  },
  "_requiredBy": [
    "/@vue/cli/listr",
    "/@vue/cli/lowdb",
    "/@vue/cli/run-async"
  ],
  "_resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.0.tgz",
  "_shasum": "3ebfc546cee7064c314686279cc9df7bc2724715",
  "_spec": "is-promise@^2.1.0",
  "_where": "/usr/local/lib/node_modules/@vue/cli/node_modules/lowdb",
  "author": {
    "name": "ForbesLindesay"
  },
  "bugs": {
    "url": "https://github.com/then/is-promise/issues"
  },
  "bundleDependencies": false,
  "deprecated": false,
  "description": "Test whether an object looks like a promises-a+ promise",
  "devDependencies": {
    "better-assert": "^1.0.2",
    "mocha": "^7.1.1"
  },
  "exports": {
    "import": "index.mjs",
    "require": "index.js"
  },
  "files": [
    "index.js"
  ],
  "homepage": "https://github.com/then/is-promise#readme",
  "license": "MIT",
  "main": "index.js",
  "name": "is-promise",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/then/is-promise.git"
  },
  "scripts": {
    "test": "mocha -R spec"
  },
  "type": "module",
  "version": "2.2.0"
}
npm list -g is-promise
/home/jeremy/.npm-global/lib
└─┬ @vue/cli@4.3.1
  ├─┬ @vue/cli-ui@4.3.1
  │ ├─┬ lowdb@1.0.0
  │ │ └── is-promise@2.2.2 
  │ └─┬ vue-cli-plugin-apollo@0.21.3
  │   └─┬ apollo@2.27.3
  │     └─┬ listr@0.14.3
  │       └── is-promise@2.2.2  deduped
  └─┬ inquirer@7.1.0
    └─┬ run-async@2.4.0
      └── is-promise@2.2.2  deduped

I tried npm install -g --force @vue/cli but still doesn't work.

nodejs version: v14.0.0
npm: 6.14.4

MylesBorins added a commit to MylesBorins/node that referenced this issue Apr 26, 2020
If package authors don't explicitly include all previously supported
entry points introducing package.exports will be a Semver-Major change.

Add a warning about this behavior and offer two potential solutions
for module authors.

Refs: then/is-promise#20
@MylesBorins
Copy link

I've gone ahead and opened a docs change for exports

nodejs/node#33074

FWIW the section just about the explicit note does mention that the interface will be broken, but I totally agree we should make this clearer / more obvious. A couple of people have gotten bit by the package.json one in the past. The biggest issue with creating any defaults, such as package.json, is that we would then need to introduce an explicit ignore if folks didn't want to include it. This would significantly complicate the parsing of the exports field.

Apologies that you got bit by this and thank you for taking new technology for a spin.

other may disagree but I think that adding a "./": "./" mapping is a very reasonable way to introduce exports as a Semver-Minor change (documented it in the PR), and removing it in a future Semver-Major is a great way to be more intentional about exposed API.

@RyanZim I can understand where you are coming from debating what parts of the interface are part of the "Contract" of an App. While introducing exports could technically be considered Semver-Minor I think practically there is no way to do it without the carve out I've mentioned before. Folks relying on internals sucks as a maintainer... but if you break someones workflow it is broken. I think that one could definitely have ground to stand on to say "we never supported this and if we broke you I'm sorry but thems the breaks"... but it is also easy to just revert the change and reland in a major, which is what it seems is happening here. Anyway, happy to debate Semver some other time, I don't even agree with myself half the time ¯_(ツ)_/¯

@bodograumann
Copy link

For problems with build failures due to caching, I sometimes have to do:

rm ./node_modules/.cache -rf

Please try that if you are still experiencing problems, even if you are 100% sure that you have only v2.2.2 installed.

@khaledosman
Copy link

khaledosman commented Apr 26, 2020

Ran into this issue when building an angular project after installing firebase via ng add @angular/fire

If you have the same issue, manually installing is-promise@2.2.2 fixed it for me via npm i is-promise@2.2.2

previous output of npm list is-promise

➜  craftnote git:(master) ✗ npm list is-promise
craftnote@0.0.0 /Users/khaledosman/Documents/github/craftnote
├─┬ firebase-tools@8.1.1
│ └─┬ cli-color@1.4.0
│   └─┬ memoizee@0.4.14
│     └── is-promise@2.2.2  deduped
├─┬ UNMET PEER DEPENDENCY inquirer@7.1.0
│ └─┬ run-async@2.4.0
│   └── is-promise@2.2.2  deduped
└── is-promise@2.2.2

npm ERR! peer dep missing: inquirer@^5.0.0 || ^6.0.0, required by inquirer-autocomplete-prompt@1.0.2

@joepie91
Copy link

joepie91 commented Apr 26, 2020

@RyanZim

In the far-distant future, I do forsee tooling that will only work with ESM, that will allow some cool static analysis optimization stuff, but that's way out there.

The static analysis thing is commonly mentioned, but as of yet I've seen exactly zero credible arguments as to how ESM code would be more statically analyzable. It's still the same code, just using different import/export syntax; top-level requires are equally statically analyzable, and dynamic requires are just as unanalyzable as dynamic imports. Far as I can tell, it literally doesn't matter.

Really the only reason why tooling would "only work with ESM", is because it's currently the hip thing, the introduction of it has caused an (IMO completely unnecessary and undesirable) ecosystem split, and the author doesn't want to support two module syntaxes; not because of any actual technical reason.

(And I say this as someone who's working on a fair bit of static analysis tooling.)

@ForbesLindesay
Copy link
Member Author

@joepie91 This is mostly true. There aren't any real issues that prevent statically analysing CommonJS, but it definitely requires two implementations, so there are going to be tools going forwards that don't support it.

If you are still having problems with this, you just need to clear your npm (or yarn) cache.

@then then locked as resolved and limited conversation to collaborators Apr 26, 2020
@ForbesLindesay
Copy link
Member Author

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests