# Shims Add compatibility between ESM and CommonJS module systems. ## Overview Shims provide small pieces of code that bridge the gap between CommonJS (CJS) and ECMAScript Modules (ESM), enabling cross-module-system compatibility. ## What Shims Provide ### ESM Output (when enabled) With `shims: true`, adds CommonJS variables to ESM: - `__dirname` - Current directory path - `__filename` - Current file path ### ESM Output (automatic) Always added when using `require` in ESM on Node.js: - `require` function via `createRequire(import.meta.url)` ### CJS Output (automatic) Always added to CommonJS output: - `import.meta.url` - `import.meta.dirname` - `import.meta.filename` ## Usage ### CLI ```bash tsdown --shims ``` ### Config File ```ts export default defineConfig({ entry: ['src/index.ts'], format: ['esm'], shims: true, }) ``` ## Generated Code ### ESM with Shims **Source:** ```ts console.log(__dirname) console.log(__filename) ``` **Output (shims: true):** ```js import { fileURLToPath } from 'node:url' import { dirname } from 'node:path' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) console.log(__dirname) console.log(__filename) ``` ### ESM with require **Source:** ```ts const mod = require('some-module') ``` **Output (automatic on Node.js):** ```js import { createRequire } from 'node:module' const require = createRequire(import.meta.url) const mod = require('some-module') ``` ### CJS with import.meta **Source:** ```ts console.log(import.meta.url) console.log(import.meta.dirname) ``` **Output (automatic):** ```js const import_meta = { url: require('url').pathToFileURL(__filename).toString(), dirname: __dirname, filename: __filename } console.log(import_meta.url) console.log(import_meta.dirname) ``` ## Common Patterns ### Node.js CLI Tool ```ts export default defineConfig({ entry: ['src/cli.ts'], format: ['esm'], platform: 'node', shims: true, // Add __dirname, __filename }) ``` ### Dual Format Library ```ts export default defineConfig({ entry: ['src/index.ts'], format: ['esm', 'cjs'], platform: 'node', shims: true, // ESM gets __dirname/__filename // CJS gets import.meta.* (automatic) }) ``` ### Server-Side Code ```ts export default defineConfig({ entry: ['src/server.ts'], format: ['esm'], platform: 'node', shims: true, external: [/.*/], // External all deps }) ``` ### File System Operations ```ts // Source code import { readFileSync } from 'fs' import { join } from 'path' // Read file relative to current module const content = readFileSync(join(__dirname, 'data.json'), 'utf-8') ``` ```ts // tsdown config export default defineConfig({ entry: ['src/index.ts'], format: ['esm'], shims: true, // Enables __dirname }) ``` ## When to Use Shims ### Use `shims: true` when: - ✅ Building Node.js tools/CLIs - ✅ Code uses `__dirname` or `__filename` - ✅ Need file system operations relative to module - ✅ Migrating from CommonJS to ESM - ✅ Need cross-format compatibility ### Don't need shims when: - ❌ Browser-only code - ❌ No file system operations - ❌ Using only `import.meta.url` - ❌ Pure ESM without CJS variables ## Performance Impact ### Runtime Overhead Shims add minimal runtime overhead: ```js // Added to output when shims enabled import { fileURLToPath } from 'node:url' import { dirname } from 'node:path' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) ``` ### Tree Shaking If `__dirname` or `__filename` are not used, they're automatically removed during bundling (no overhead). ## Platform Considerations ### Node.js Platform ```ts export default defineConfig({ platform: 'node', format: ['esm'], shims: true, // Recommended for Node.js }) ``` - `require` shim added automatically - `__dirname` and `__filename` available with `shims: true` ### Browser Platform ```ts export default defineConfig({ platform: 'browser', format: ['esm'], shims: false, // Not needed for browser }) ``` - Shims not needed (no Node.js variables) - Will cause warnings if Node.js APIs used ### Neutral Platform ```ts export default defineConfig({ platform: 'neutral', format: ['esm'], shims: false, // Avoid platform-specific code }) ``` - Avoid shims for maximum portability ## CLI Examples ```bash # Enable shims tsdown --shims # ESM with shims for Node.js tsdown --format esm --platform node --shims # Dual format with shims tsdown --format esm --format cjs --shims ``` ## Troubleshooting ### `__dirname is not defined` Enable shims: ```ts export default defineConfig({ shims: true, }) ``` ### `require is not defined` in ESM Automatic on Node.js platform. If not working: ```ts export default defineConfig({ platform: 'node', // Ensure Node.js platform }) ``` ### Import.meta not working in CJS Automatic - no configuration needed. If still failing, check output format: ```ts export default defineConfig({ format: ['cjs'], // Shims added automatically }) ``` ## Tips 1. **Enable for Node.js tools** - Use `shims: true` for CLIs and servers 2. **Skip for browsers** - Not needed for browser code 3. **No overhead if unused** - Automatically tree-shaken 4. **Automatic require shim** - No config needed for `require` in ESM 5. **CJS shims automatic** - `import.meta.*` always available in CJS ## Related Options - [Platform](option-platform.md) - Runtime environment - [Output Format](option-output-format.md) - Module formats - [Target](option-target.md) - Syntax transformations