fp-ts icon indicating copy to clipboard operation
fp-ts copied to clipboard

Add exports field to package.json in order to support moduleResolution node12/nodenext

Open viell-dev opened this issue 2 years ago • 1 comments

🚀 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

viell-dev avatar Jun 15 '22 13:06 viell-dev

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:

  1. Rename ./es6/index.js to ./es6/index.mjs and ./es6/*.js to ./es6/*.mjs
  2. Add type: module and rename ./lib/index.js to ./lib/index.cjs and ./lib/*.js to ./lib/*.cjs
  3. Add a package.json inside ./es6 with type: 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.

andreavaccari avatar Jun 29 '22 16:06 andreavaccari

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.

viell-dev avatar Aug 15 '22 12:08 viell-dev

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 avatar Aug 31 '22 07:08 viell-dev

@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
}

gcanti avatar Sep 08 '22 08:09 gcanti

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 avatar Sep 15 '22 08:09 gcanti

@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"
    }
  },
}

viell-dev avatar Sep 17 '22 08:09 viell-dev

Ok, thank you, going to release 2.13.0-rc.3 with the fix asap

gcanti avatar Sep 17 '22 08:09 gcanti

going to release 2.13.0-rc.3 with the fix asap

done

gcanti avatar Sep 17 '22 09:09 gcanti

Looks great. 👍🏻

viell-dev avatar Sep 17 '22 11:09 viell-dev

Nice, thank you for your help @viell-dev

gcanti avatar Sep 17 '22 11:09 gcanti

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.

viell-dev avatar Oct 31 '22 12:10 viell-dev