Closed ForbesLindesay closed 4 years ago
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.
I'm still running into issues with 2.2.1: "No Valid Exports main found for 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.
@Rapdash mrm doesn't look like it has is-promise as a dependency
@Rapdash What's the output of npm list is-promise
?
@ljharb all those require paths are available.
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
@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.
Ah, now I understand, not having package.json
on that list by default seems like a pretty bad default.
@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
.
@ForbesLindesay Is that last message directed at me a typo or are you actually saying that "is-promise" doesn't depend on "is-promise"?
I'm tried reinstall create-react-app with:
npm install -g --force create-react-app
and it fix them.
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.
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.
@ForbesLindesay 2.2.2 did the trick! Thank you to everyone who moved so fast on this.
@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. :grinning:
@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.
@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.
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.
If adding "exports"
to your package.json, including a mapping "./": "./"
will allow all package paths to be exported.
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.
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.
@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.
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.
@ForbesLindesay Can you unpublish 2.2.0
? So people won't install the wrong version?
@fisker done
npm install -g --force create-react-app
This fixed it
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
@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.
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
@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?
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"
}
@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.
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
I've gone ahead and opened a docs change for exports
https://github.com/nodejs/node/pull/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 Β―_(γ)_/Β―
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.
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
@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 import
s. 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.)
@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.
Please comment on this issue if you are still experiencing issues wen upgrading to 2.2.1