fp-ts
fp-ts copied to clipboard
Add exports field to package.json in order to support moduleResolution node12/nodenext
🚀 Feature request
Current Behavior
When using "moduleResolution": "NodeNext",
in your tsconfig it expects an "exports": ...
field in package.json in order to resolve the package.
Otherwise:
Cannot find module 'fp-ts/Either' or its corresponding type declarations.ts(2307)
Desired Behavior
Importing to work.
Suggested Solution
Shove this in package.json:
"exports": {
".": {
"import": {
"types": "./es6/index.d.ts",
"default": "./es6/index.js"
},
"require": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
}
},
"./*": {
"import": {
"types": "./es6/*.d.ts",
"default": "./es6/*.js"
},
"require": {
"types": "./lib/*.d.ts",
"default": "./lib/*.js"
}
},
"./es6/*": {
"import": {
"types": "./es6/*.d.ts",
"default": "./es6/*.js"
}
},
"./lib/*": {
"require": {
"types": "./lib/*.d.ts",
"default": "./lib/*.js"
}
}
},
Tested it locally by putting that above "main"
like in the example as seen in the TS 4.7 link below, seems to do the job.
The "./es6/*"
or "./lib/*"
parts are only needed for backwards-compatibility with the old import paths.
Who does this impact? Who is this for?
People wanting to use fp-ts
with the new ECMAScript Module Support added with TypeScript 4.7.
Describe alternatives you've considered
Not using the new ECMAScript Module support feature. 🤷♂️ Most NPM packages aren't updated to support this yet.
Additional context
TS 4.7 link: https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#esm-nodejs Node.js link: https://nodejs.org/api/packages.html#package-entry-points
Your environment
Software | Version(s) |
---|---|
fp-ts | 2.12.1 |
TypeScript | 4.7.3 |
The above suggestion is mostly correct, but there's a caveat with the file extensions. Depending on the the value of the type
field in package.json
, Node will treat .js
files either as CJS or ESM, while it will always treat .cjs
file as the former and .mjs
files as the latter.
To make Node happy we have to either:
- Rename
./es6/index.js
to./es6/index.mjs
and./es6/*.js
to./es6/*.mjs
- Add
type: module
and rename./lib/index.js
to./lib/index.cjs
and./lib/*.js
to./lib/*.cjs
- Add a
package.json
inside./es6
withtype: module
(and for good measure do the equivalent in./lib
)
There's also the option of dropping CJS completely, adding type: module
in package.json
, and living a happier life.
I don't think the suggestion by @andreavaccari is currently applicable, since fp-ts
isn't building ECMAScript Modules.
My suggestion would allow a user using ESM to load the ES6 version of fp-ts
without issue. fp-ts
does not need to use ESM itself to be compatible.
Though, to be fair, I don't think there is much of a difference between ES6 and ESM files. I believe it's just the internal import statements requiring extensions. And the package.json
stuff with type: module
. But I feel that's another issue entirely.
Edit:
See https://github.com/viell-dev/fp-ts for a test fork.
Only change there is the addition of the exports
section in package.json
.
Updated my test fork to 2.12.3. (viell-dev/fp-ts)
Also I saw that #1525 also talks about exports
stuff.
Not sure what that means for 2.x ESM support.
Is it planned for 3.x and thus not a concern for 2.x?
@viell-dev in v3 I'm using
{
"exports": {
".": {
"require": "./lib/index.js",
"import": "./es6/index.js"
},
"./*": {
"require": "./lib/*.js",
"import": "./es6/*.js"
}
},
"types": "index.d.ts",
"typesVersions": {
"*": {
"*": [
"./types/*"
]
}
},
"sideEffects": false
}
So for backwards-compatibility in v2 would be
{
"exports": {
".": {
"require": "./lib/index.js",
"import": "./es6/index.js"
},
"./*": {
"require": "./lib/*.js",
"import": "./es6/*.js"
},
"./es6/*": {
"import": "./es6/*.js"
},
"./lib/*": {
"require": "./lib/*.js"
}
},
"types": "index.d.ts",
"typesVersions": {
"*": {
"*": [
"./types/*"
]
}
},
"sideEffects": false
}
Hi all, I've just released https://github.com/gcanti/fp-ts/releases/tag/2.13.0-rc.2 (install with npm i fp-ts@rc
), could you please try it out and let me know if everything is ok?
@gcanti I tried it and I'm getting: "Could not find a declaration file for module 'fp-ts/Option'."
After testing locally I've concluded that you will need to have the types
sections under exports
as well.
e.g.
{
"exports": {
".": {
"require": "./lib/index.js",
"import": "./es6/index.js",
"types": "./types/index.d.ts"
},
"./*": {
"require": "./lib/*.js",
"import": "./es6/*.js",
"types": "./types/*.d.ts"
},
"./es6/*": {
"import": "./es6/*.js",
"types": "./types/*.d.ts"
},
"./lib/*": {
"require": "./lib/*.js",
"types": "./types/*.d.ts"
}
},
}
Ok, thank you, going to release 2.13.0-rc.3
with the fix asap
going to release 2.13.0-rc.3 with the fix asap
done
Looks great. 👍🏻
Nice, thank you for your help @viell-dev
I saw that the changes got reverted in 2.13.1
due to #1799 and similar issues. So I'm using a fork for my use-cases since I have need of fp-ts
in projects where the types don't work without the exports
field.