Build CommonJS and ESM from one package
This guide builds esm/ and cjs/ from the same src/, and publishes both through exports. It uses
buddy ts build, which runs tsc and marks cjs/ as CommonJS with
package.cjs.json.
-
Install the packages:
Terminal window pnpm add -D typescript repobuddy @repobuddy/typescript -
Enable the plugin. Add a
repobuddyproperty topackage.json, or create a.repobuddy.jsonwith the same content:{"repobuddy": {"plugins": ["@repobuddy/typescript"]}} -
Set
"type": "module"inpackage.json, so Node.js readsesm/*.jsas ESM. -
Create the base
tsconfig.json. It holds the ESM settings:{"extends": "@repobuddy/typescript/tsconfig/monorepo","compilerOptions": {"outDir": "esm","rootDir": "src"},"include": ["src"]} -
Create
tsconfig.esm.json.buddy ts build esmreads this file name:{"extends": "./tsconfig.json"} -
Create
tsconfig.cjs.json. Listmodules/buddy-commonjsafter the base config so itsmodule: CommonJSwins. SetoutDirtocjs, because the command copiespackage.jsoninto a folder named after the build type:{"extends": ["./tsconfig.json", "@repobuddy/typescript/tsconfig/modules/buddy-commonjs"],"compilerOptions": {"outDir": "cjs"}} -
Point
exportsat both builds and add a build script:{"exports": {".": {"import": {"types": "./esm/index.d.ts","default": "./esm/index.js"},"require": {"types": "./cjs/index.d.ts","default": "./cjs/index.js"}}},"files": ["cjs", "esm"],"scripts": {"build": "buddy ts build esm && buddy ts build cjs"}} -
Run the build:
Terminal window pnpm buildbuilding esm...build esm donebuilding cjs...copying package.json...build cjs done
Finished files
Section titled “Finished files”{ "name": "my-lib", "version": "1.0.0", "type": "module", "exports": { ".": { "import": { "types": "./esm/index.d.ts", "default": "./esm/index.js" }, "require": { "types": "./cjs/index.d.ts", "default": "./cjs/index.js" } } }, "files": ["cjs", "esm"], "scripts": { "build": "buddy ts build esm && buddy ts build cjs" }, "repobuddy": { "plugins": ["@repobuddy/typescript"] }}tsconfig.json, tsconfig.esm.json, and tsconfig.cjs.json are as in steps 4 to 6.
Verify
Section titled “Verify”-
Check that
cjs/package.jsonexists and contains{ "type": "commonjs" }. -
From another project that installs the package, load it both ways:
Terminal window node -e "console.log(require('my-lib'))"node --input-type=module -e "import * as m from 'my-lib'; console.log(m)"Both print the package’s exports.
Variations
Section titled “Variations”- Helpers from
tslib: addtsconfig.tslib.jsonthat extendstsconfig.cjs.jsonand sets"importHelpers": trueand"outDir": "tslib". Runbuddy ts build tslib. The package needstslibas a dependency.testcases/build-tsin this repository does this. - Another CommonJS build tool: if a bundler writes
cjs/, skipbuddy ts build cjsand runbuddy ts cpj cjs .after it. This repository’spackages/jestbundlescjs/index.jswith esbuild, emits only declarations withtsc -p tsconfig.cjs.json(emitDeclarationOnly), and then copies its ownpackage.cjs.jsontocjs/package.json.