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

Compile to both ESM and CJS #114

Merged
merged 3 commits into from
Nov 26, 2021
Merged

Conversation

ekosz
Copy link
Contributor

@ekosz ekosz commented Nov 3, 2021

When trying to use the new Redlock library I noticed it was able to run
in NodeJS, but failed in Jest. Looks like that was because Jest (like
many tools right now) doesn't yet support native ESM modules yet.
I think its awesome Redlock is outputting native ESM, but while the
world is still converting to ESM I think it's nice to duel output to CJS
as well.

This updates the building of the library to support both ESM and CJS
clients. During the build process it now builds the library twice, once
with the main tsconfig.json file and again with a new
tsconfig.cjs.json file. Finally, it runs a new tools/fixup bash
script to insert some build specific package.json files that add the
correct "type" attribute to the folder. The final dist tree structure
looks like:

dist
├── cjs
│   ├── index.js
│   ├── index.js.map
│   ├── index.test.js
│   ├── index.test.js.map
│   └── package.json
├── esm
│   ├── index.js
│   ├── index.js.map
│   ├── index.test.js
│   ├── index.test.js.map
│   └── package.json
├── index.d.ts
└── index.test.d.ts

The rest of the change is updating the package.json file to point to
these new files.

  • "main" - Old entry point. Points to CJS index.js
  • "module" - Deprecated entry point (but many clients still use it).
    Points to ESM index.js
  • "types" - Entry point for typescript types. Points to top level
    index.d.ts
  • "exports" - New entry point router for Node14+. Points require
    statements to the CJS index.js and import statements to the ESM
    index.js

I mostly followed this blog post for the technique. I also tested locally to make sure require, import, and typescript types still all resolved correctly.

I know this is a bigger change, so very happy to respond to feedback / drop this PR if you don't feel like this is the correct direction for the project.

When trying to use the new Redlock library I noticed it was able to run
in NodeJS, but failed in Jest. Looks like that was because Jest (like
many tools right now) doesn't yet support native ESM modules yet.
I think its awesome Redlock is outputting native ESM, but while the
world is still converting to ESM I think its nice to duel output to CJS
as well.

This updates the building of the library to support both ESM and CJS
clients. During the build process it now builds the library twice, once
with the main `tsconfig.json` file and again with a new
`tsconfig.cjs.json` file. Finally, it runs a new `tools/fixup` bash
script to insert some build specific `package.json` files that add the
correct "type" attribute to the folder. The final dist tree structure
looks like:

```
dist
├── cjs
│   ├── index.js
│   ├── index.js.map
│   ├── index.test.js
│   ├── index.test.js.map
│   └── package.json
├── esm
│   ├── index.js
│   ├── index.js.map
│   ├── index.test.js
│   ├── index.test.js.map
│   └── package.json
├── index.d.ts
└── index.test.d.ts
```

The rest of the change is updating the `package.json` file to point to
these new files.

* "main" - Old entry point. Points to CJS index.js
* "module" - Deprecated entry point (but many clients still use it).
  Points to ESM index.js
* "types" - Entry point for typescript types. Points to top level
  index.d.ts
* "exports" - New entry point router for Node14+. Points require
  statements to the CJS index.js and import statements to the ESM
  index.js
@Dakuan Dakuan mentioned this pull request Nov 4, 2021
@ekosz
Copy link
Contributor Author

ekosz commented Nov 9, 2021

@mike-marcacci Following up here. Do you have any interest in this direction?

@mike-marcacci
Copy link
Owner

mike-marcacci commented Nov 11, 2021

Hi @ekosz, sorry for the slowness here. I've been weighing this issue for a bit now, and have been debating between:

  • ...leaving this package as-is and only publishing ES modules. This impacts the usability of this library in other projects, which is definitely problematic but also keeps this build process simple and helps push the ecosystem forward (to hopefully avoid a python 3 type situation).
  • ...switching back to commonjs only (proposed in Publish as CommonJS module #100). This improves the usability of this library and keeps the build process simple, but is counterproductive to the larger push.
  • ...adopting your approach here, which balances usability and forward-progress at the (minor) expense of more complexity here and increased published package size.

At this point I'm definitely preferring your approach here, at least for all of version 5. Perhaps in a future major version we can drop commonjs if dependent projects are ready. I think this is really well thought out, and I think this is probably the cleanest implementation of duplicate builds that I've seen (especially with the package.json trick).

I do want to finish up some outstanding changes to #101, and then I'll experiment with your PR locally. Thanks a bunch for the contribution!

@mike-marcacci mike-marcacci merged commit a48e563 into mike-marcacci:main Nov 26, 2021
@ekosz ekosz deleted the EK/duel-outputs branch January 19, 2022 23:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants