Oh BTW, This post was 100% human written with no AI assistance whatsoever. All typos and bad grammar are my own. Enjoy :)
I doubt you remember, but back at the time I wrote a piece about Hybrid NPM package through TypeScript Compiler (TSC), which explained how you can leverage TSC to produce 2 artifact types (ESM and CJS) from a single source code.
I thought it was pretty clever. Hell, I still do 😉
Recently though, I came across one of Matt Pocock’s TS course lessons (which I highly recommend on btw) that suggested a more elegant way to achieve that. In this post I will migrate to that way and explain what I do so your AI agent won’t get left behind ;)
Note: It would be best if you go over the Hybrid NPM package through TypeScript Compiler (TSC) article, so you will get the context of what I’m about to write on.
I have this package in my Pedalboard monorepo, called @pedalboard/media-loader (that you should totally check out if you’re a React dev struggling with media loading performance), which has a build process that generates 2 types of artifacts - ESM and CJS. In order to support that I’ve created 2 different tsconfig.json
files and in the build script I’m running them both.
It looks something like this:
"build": "tsc --project tsconfig.esm.json & tsc --project tsconfig.cjs.json",
Although there is nothing wrong with it, it kinda requires this plumbing in the package.json
file and all-in-all feels a bit of a brute-force-primitive. Fortunately there is a more elegant way to achieve that using the references config.
Here is how:
Both the tsconfig.esm.json
and tsconfig.cjs.json
are in the root dir of the package, and to them I will add the “main” config file - tsconfig.json
, and its content looks like this:
{
"references": [
{
"path": "./tsconfig.esm.json"
},
{
"path": "./tsconfig.cjs.json"
}
],
"files": []
}
Let’s go over it real quick - it has a references
array which has 2 paths defined in it, one for each config file, and it has an empty array for the files
config, to ensure that the tsconfig.json
does not enforce any type checking, but rather leaves that to the referenced projects.
Now we need to change the build script. Instead of what we have, we now write this:
"build": "tsc -b",
Notice the -b
param, which tells TSC to run it in build mode, thus taking into consideration the different references in the main tsconfig.json
file. In other words, without the -b
param, it won’t work as we expect it to.
And that is it!
When we run our build script now, TSC will run both configurations and create both ESM and CJS artifacts.
There is a lot more you can do with the project references like cache type check results (for faster builds) or define dependencies between projects, but in this case what we have is enough.
The code is available on Github @pedalboard/media-loader
Be seeing you
Photo by Trnava University on Unsplash
Top comments (0)