Files
stack/packages/mosaic/framework/skills/tsdown/references/option-shims.md
T
fargo 1a822493ba format: apply repo prettier (3.8.1) to the folded skills tree
963 markdown files reformatted with the repository's pinned prettier so
pnpm format:check covers the folded tree like every other repo file.

The formatter's embedded-language pass also normalized code fences
(TS semicolons, closed HTML tags in examples, lowercased CSS hex colors,
one renumbered list that skipped an index). Alphanumeric token deltas vs
the fold commit were audited file-by-file; all are formatter-equivalent
markup normalizations plus the four sanitized skills.
2026-08-19 14:37:17 -05:00

5.5 KiB

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

tsdown --shims

Config File

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm'],
  shims: true,
});

Generated Code

ESM with Shims

Source:

console.log(__dirname);
console.log(__filename);

Output (shims: true):

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:

const mod = require('some-module');

Output (automatic on Node.js):

import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);

const mod = require('some-module');

CJS with import.meta

Source:

console.log(import.meta.url);
console.log(import.meta.dirname);

Output (automatic):

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

export default defineConfig({
  entry: ['src/cli.ts'],
  format: ['esm'],
  platform: 'node',
  shims: true, // Add __dirname, __filename
});

Dual Format Library

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

export default defineConfig({
  entry: ['src/server.ts'],
  format: ['esm'],
  platform: 'node',
  shims: true,
  external: [/.*/], // External all deps
});

File System Operations

// 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');
// 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:

// 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

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

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

export default defineConfig({
  platform: 'neutral',
  format: ['esm'],
  shims: false, // Avoid platform-specific code
});
  • Avoid shims for maximum portability

CLI Examples

# 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:

export default defineConfig({
  shims: true,
});

require is not defined in ESM

Automatic on Node.js platform. If not working:

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:

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