New episode of JS Party!
@acemarke (web dev professor/historian, OSS Maintainer & engineer at Replay) joins us to talk about the shift from CommonJS to ESM
We discuss the history of module patterns in JS and the grueling effort to push the world’s biggest developer ecosystem forward
Get ready to go to school kids, this one’s deep!
@jsparty @acemarke Great discussion about the difficulties with #ESM and I can definitely relate. Ultimately I think a lot of this just comes down to the fact that migrating ecosystems is just hard. I wish there were a clear cause or solution, but there just isn't. I also suspect the "article that explains how to do this right" is impossible because there _isn't_ a single approach which makes every tool happy.
Actually the package format standard and tooling you want actually does exist in the #Angular ecosystem. It's called #APF, Angular Package Format, and it can be generated with `ng-packagr`.
https://angular.io/guide/angular-package-format
https://github.com/ng-packagr/ng-packagr
It's by no means perfect and relies heavily on constraints we enforce on Angular itself (TS versions, browser support, language levels, etc.) But this is a very powerful tool for when we need to make major changes to the Angular ecosystem, such as going ESM-only, which we landed successfully in v13 several years ago.
@jsparty @acemarke Honestly I would suggest a bit of a tough-love approach. Now that we have ESM and most tools support it, just don't publish anything non-standard in the package.
Libraries should just export JavaScript, with explicit file extensions, `exports`, and (optional) type definitions. It's up to applications to bundle and downlevel their transitive libraries, with them bearing the cost that represents.
Tools get a little more complicated, but frankly this is a reflection of the broken design of the JS ecosystem. Everything accepts source files and plugins, nothing composes. The solution here is to vastly limit the tools which do module resolution.
#Jest shouldn't be unique here, it's just #Node! Jest shouldn't be doing anything special with module resolution or even have a #TypeScript plugin. Users should build their TS first and then run Jest on the JS outputs. Unfortunately that just isn't the way the modern web tooling ecosystem is designed.
@jsparty @acemarke #TypeScript is a bit fiddly I agree, and I do think things could be better there. I also wish they would allow and rewrite `*.ts` extensions in imports, but I do see where they're coming from.
With ESM and Node being where they are today, I think it's absolutely reasonable to say "My library works in Node natively. Your tooling should support that and if it doesn't, that's on you." There's definitely pain to get there, but it is feasible and a solid end state.
It's a bit contradictory to your philosophy of "I want to make sure that my libraries are maximally compatible and usable in the widest array of environments I can feasibly support", but I think it is the best way to push an ecosystem of this scale in the right direction. Tool authors and users need to bear the burden of making their tools work with libraries, not the other way around.