Download Game! Currently 78 players and visitors. Last logged in:RobinhoodGrizztJanoQumni

Blitzer's Blog >> 72559

Back to blogs index
Posted: 16 Sep 2026 16:25 [ permalink ]
To distribute a dual-format library (CommonJS for older Node.js setups and ESM
for modern Node/bundlers/browsers) complete with TypeScript definition files,
the easiest and fastest tool is tsup. It is powered by esbuild under the hood
but automatically handles the complex type-declaration (.d.ts) generation that
esbuild skips.
Here is how to set up a zero-configuration build pipeline that takes your
generated registry-sdk.ts and spits out production-ready CJS and ESM bundles.
 1. Install the build tools
   Install tsup and typescript as development dependencies in your registry
project (or wherever the SDK is being generated).
   npm install -D tsup typescript

 2. Configure the package exports
   To ensure consumer projects seamlessly load the correct version whether
they use require() or import, you must configure the exports map in the
consumer-facing package.json.
   If you are publishing this SDK as its own NPM package, this goes in the
SDK's package.json. If it's part of a monorepo workspace, add it to the
specific workspace package.
   {
  "name": "@mesh/registry-sdk",
  "version": "1.0.0",
  "main": "./dist/registry-sdk.js",
  "module": "./dist/registry-sdk.mjs",
  "types": "./dist/registry-sdk.d.ts",
  "exports": {
    ".": {
      "import": {
        "types": "./dist/registry-sdk.d.ts",
        "default": "./dist/registry-sdk.mjs"
      },
      "require": {
        "types": "./dist/registry-sdk.d.ts",
        "default": "./dist/registry-sdk.js"
      }
    }
  }
}

 3. Create the build pipeline
   Add these scripts to your package.json. We will chain your generator script
and the bundler together into a single command.
   "scripts": {
  "generate": "node harness/generate-sdk.js",
  "build:sdk": "npm run generate && tsup dist/registry-sdk.ts --format cjs,esm
--dts --clean"
}

   What these flags do:
   * --format cjs,esm: Tells esbuild to output both module formats.
   * --dts: Triggers the TypeScript compiler to emit a single, clean .d.ts
type definition file.
   * --clean: Wipes the output directory before building to prevent stale
artifacts.
 4. Run the pipeline
   Execute the pipeline from your terminal:
   npm run build:sdk

   You will see output similar to this, executed in milliseconds:
   [SDK Gen] Fetching routine specifications from http://localhost:3377...
[SDK Gen] Generated 2 routine signatures at .../dist/registry-sdk.ts

CLI build target: node16
CLI clean: true
CJS dist/registry-sdk.js      2.12 KB
ESM dist/registry-sdk.mjs     1.98 KB
DTS dist/registry-sdk.d.ts    1.15 KB
CLI Build success in 45ms

The Resulting Artifacts
Your dist/ directory now contains a universally compatible SDK:
 * registry-sdk.mjs: The ESM build. If a user runs import { RoutineRegistryClie
nt } from '@mesh/registry-sdk', Node or Webpack uses this file.
 * registry-sdk.js: The CJS build. If a user runs const { RoutineRegistryClient
 } = require('@mesh/registry-sdk'), Node uses this.
 * registry-sdk.d.ts: The types. VS Code and TypeScript will automatically
read this to provide autocomplete for .calculateTax() and .formatLog().