Imagine a package.json that looks like this:
{
"name": "my-package",
"type": "module",
"exports": {
".": {
"source": "./src/index.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
}
}
We're using exports
to define a single entrypoint, my-package
. my-package
can be accessed in one of three ways:
- Via a ESM
import
->./dist/index.js
- Via
require
->./dist/index.cjs
- Some other MYSTERIOUS WAY ->
./src/index.ts
In this way, you can see that we're letting CJS users and ESM users access built versions of the package. But what the hell is that source
thing?
Well, for those who want to, you can directly access the source file that created both the cjs and esm file. This is via a custom condition.
You can use custom conditions in exports
in package.json
. You can call them anything you like. By convention, we're calling this one source
- and it points to the source file.
This custom condition won't be used by the app/package consuming my-package
unless we opt in. We do that in the tsconfig.json
:
{
"compilerOptions": {
"customConditions": ["source"]
}
}
And, perhaps, in our vite.config.ts
:
export default {
resolve: {
conditions: ['source']
}
}
Now, both the types and the Vite app will target the source, not the transpiled output. This is useful because any changes in my-package
will automatically propagate through any apps.
But, it's also opt-in - so you can publish this package as-is without any issues.