build(package): generate esm output with exports #3337
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly:
Fixes #3335
This PR attempts to address #3335. Given there are a lot of possible ways to achieve cjs/esm compatible pkg support, I can see this PR is not feasible to this repo's convention and likely can be closed without merge. That's totally fine, however would like to kickstart an initial effort.
Among various approach, this PR nearly mimics recent redux-toolkit's approach (without bundling part) and my personal experiences when I dealt with RxJS (though it's not real esm - https://github.com/ReactiveX/rxjs/blob/master/package.json). Detailed exploration can be found at https://blog.isquaredsoftware.com/2023/08/esm-modernization-lessons/, but in crux this PR does these things
package.json
'stype
, so existing cjs-based scripts & assumptions (require..
) works as-isbuild/cjs
build/esm
. This usestsc-multi
(https://github.com/tommy351/tsc-multi), which is a wrapper to generate multiple target outputs with manually transforming extensions per each.build/esm
uses.mjs
extension to let node.js resolves this as esm explicitlygenerators
template to include.js
extension by defaultpackage.json
forimport
/require
and lastly let default resolves to esm.Quick local testing confirmed generated pkg can be imported in node.js with cjs / esm (
type:module
), also typescript definitions are being resolved. The caveat for type resolution is it falls back to cjs types always, but it won't be a huge concern since most of types should be equivalent between 2 build outputs. Below's manual testing from https://arethetypeswrong.github.io/ how imports are being resolved.One last thing to note is about conditional exports: conditional exports limits arbitaray imports (including cjs require) to subpath imports, so if anyone used subpath imports like
require('googleapi/somepath/imports')
explicitly it'll likely fail. I'm not certain this should be treated as major breaking - since the entrypoints reexports everything and individual api should be resolvable withput subpath - though.