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

Real ESM support

Open samhh opened this issue 2 years ago • 9 comments

In a fully ESM project:

import { sum } from "fp-ts-std/Array";
         ^^^
SyntaxError: Named export 'sum' not found. The requested module 'fp-ts-std/Array' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'fp-ts-std/Array';
const { sum } = pkg;

    at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:190:5)

Node.js v18.16.0

And then with that change:

(node:55013) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/path/to/repo/.yarn/__virtual__/fp-ts-std-virtual-e76da617af/4/.yarn/berry/cache/fp-ts-std-npm-0.17.1-8c0fa4fe44-8.zip/node_modules/fp-ts-std/dist/esm/Array.js:1
import { constant, pipe, flow, flip } from "fp-ts/function";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at internalCompileFunction (node:internal/vm:73:18)
    at wrapSafe (node:internal/modules/cjs/loader:1176:20)
    at Module._compile (node:internal/modules/cjs/loader:1218:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at require$$0.Module._extensions..js (/path/to/repo/.pnp.cjs:9101:33)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at require$$0.Module._load (/path/to/repo/.pnp.cjs:8920:22)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:169:29)
    at ModuleJob.run (node:internal/modules/esm/module_job:194:25)

Node.js v18.16.0

Related: #113

samhh avatar Jun 30 '23 11:06 samhh

Should be resolved in the esm branch, however that's blocked by docs-ts: https://github.com/gcanti/docs-ts/issues/59#issuecomment-1614600958

samhh avatar Jun 30 '23 12:06 samhh

Actually in different projects I'm seeing different results. One works, the other complains about the fp-ts imports. :unamused:

samhh avatar Jun 30 '23 12:06 samhh

I think 0.18.0-beta.3 is the first to work fully with both proper ESM and CJS.

Depending on the consuming project different packaging issues can surface, most of which don't reveal themselves when building here.

The latest surprise is that tsc requires the consuming project to be ESM to read a package's exports field, hence the return of the typesVersions hack.

samhh avatar Jul 04 '23 16:07 samhh

Nope, spoke too soon, the fp-ts imports need updating. :rage:

samhh avatar Jul 04 '23 16:07 samhh

Webpack:

ERROR in ./node_modules/fp-ts-std/dist/esm/URL.js 2:0-34
Module not found: Error: Can't resolve 'fp-ts/Either' in '/path/to/repo/node_modules/fp-ts-std/dist/esm'
Did you mean 'Either.js'?
BREAKING CHANGE: The request 'fp-ts/Either' failed to resolve only because it was resolved as fully specified
(probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.

Similar in a Node REPL:

> await import('fp-ts-std/Array')
Uncaught:
Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import '/path/to/repo/node_modules/fp-ts/function' is not supported resolving ES modules imported from /path/to/repo/node_modules/fp-ts-std/dist/esm/Array.js
Did you mean to import fp-ts/lib/function.js?
    at new NodeError (node:internal/errors:399:5)
    at finalizeResolution (node:internal/modules/esm/resolve:319:17)
    at moduleResolve (node:internal/modules/esm/resolve:945:10)
    at defaultResolve (node:internal/modules/esm/resolve:1153:11)
    at nextResolve (node:internal/modules/esm/loader:163:28)
    at ESMLoader.resolve (node:internal/modules/esm/loader:838:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:424:18)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:77:40)
    at link (node:internal/modules/esm/module_job:76:36) {
  code: 'ERR_UNSUPPORTED_DIR_IMPORT',
  url: 'file:///path/to/repo/node_modules/fp-ts/function'
}

From debugging in the REPL it looks like the imports need to be from lib, not es6.

samhh avatar Jul 04 '23 16:07 samhh

^ Fixed in 0.18.0-beta.4, however there's been some significant bundle bloat in a CJS project.

samhh avatar Jul 04 '23 17:07 samhh

I'm interpreting this to mean that fp-ts-std effectively can't be ESM until fp-ts et al are.

Perhaps the bundle bloat could be resolved with some clever bundler.

samhh avatar Jul 05 '23 10:07 samhh

The bundle bloat mostly goes away if the bundler is configured to rewrite fp-ts/lib imports to fp-ts/es6 (e.g. Webpack's resolve.alias). It doesn't entirely solve it however, and expecting non-ESM bundle-sensitive consumers to do this is a big ask.

samhh avatar Jul 05 '23 12:07 samhh

The status quo makes the package effectively entirely broken for ESM projects as the subpath exports prevent you from manually importing from /cjs. Curiously if you import a CJS module which in turn imports fp-ts-std it resolves correctly.

samhh avatar Nov 06 '23 16:11 samhh