Output Format

Configure output formats (ESM, CJS, IIFE) for your Packem builds

Output Format

Packem supports multiple output formats to ensure your library works across different JavaScript environments. The output format determines how your bundled code is structured and how it can be consumed by other applications.

Supported Formats

ESM (ES Modules)

Modern standard for JavaScript modules with import/export syntax.

export default defineConfig({
  rollup: {
    output: {
      format: 'esm',
      file: 'dist/index.mjs'
    }
  }
})

CJS (CommonJS)

Traditional Node.js module format with require/module.exports.

export default defineConfig({
  rollup: {
    output: {
      format: 'cjs',
      file: 'dist/index.cjs'
    }
  }
})

IIFE (Immediately Invoked Function Expression)

Browser-compatible format that creates a global variable.

export default defineConfig({
  rollup: {
    output: {
      format: 'iife',
      file: 'dist/index.global.js',
      name: 'MyLibrary' // Global variable name
    }
  }
})

UMD (Universal Module Definition)

Works in both browser and Node.js environments.

export default defineConfig({
  rollup: {
    output: {
      format: 'umd',
      file: 'dist/index.umd.js',
      name: 'MyLibrary'
    }
  }
})

Automatic Format Detection

Packem automatically determines output formats based on your package.json:

From Package Type

{
  "type": "module",
  "main": "./dist/index.js"
}

→ Generates ESM format

{
  "type": "commonjs",
  "main": "./dist/index.js"
}

→ Generates CJS format

From Export Conditions

{
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    }
  }
}

→ Generates both ESM and CJS formats

Multiple Output Formats

Generate multiple formats in a single build:

export default defineConfig({
  rollup: {
    output: [
      // ESM build
      {
        format: 'esm',
        file: 'dist/index.mjs'
      },
      // CJS build
      {
        format: 'cjs',
        file: 'dist/index.cjs'
      },
      // Browser build
      {
        format: 'iife',
        file: 'dist/index.global.js',
        name: 'MyLibrary'
      }
    ]
  }
})

Format-Specific Configuration

ESM Configuration

export default defineConfig({
  rollup: {
    output: {
      format: 'esm',
      file: 'dist/index.mjs',
      // ESM-specific options
      exports: 'named', // or 'default', 'auto'
      generatedCode: {
        preset: 'es2015'
      }
    }
  }
})

CJS Configuration

export default defineConfig({
  rollup: {
    output: {
      format: 'cjs',
      file: 'dist/index.cjs',
      // CJS-specific options
      exports: 'auto',
      esModule: false,
      interop: 'auto'
    }
  }
})

IIFE Configuration

export default defineConfig({
  rollup: {
    output: {
      format: 'iife',
      file: 'dist/index.global.js',
      name: 'MyLibrary',
      // IIFE-specific options
      globals: {
        'react': 'React',
        'react-dom': 'ReactDOM'
      },
      extend: true // Extend existing global
    }
  }
})

File Extensions

Packem uses appropriate file extensions based on format:

Automatic Extensions

export default defineConfig({
  rollup: {
    output: [
      { format: 'esm', dir: 'dist' }, // → .mjs
      { format: 'cjs', dir: 'dist' }, // → .cjs
      { format: 'iife', dir: 'dist' } // → .js
    ]
  }
})

Custom Extensions

export default defineConfig({
  rollup: {
    output: {
      format: 'esm',
      dir: 'dist',
      entryFileNames: '[name].esm.js' // Custom extension
    }
  }
})

Package.json Integration

Dual Package Setup

{
  "type": "module",
  "main": "./dist/index.cjs",
  "module": "./dist/index.mjs",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    }
  }
}
export default defineConfig({
  rollup: {
    output: [
      { format: 'esm', file: 'dist/index.mjs' },
      { format: 'cjs', file: 'dist/index.cjs' }
    ]
  }
})

Conditional Exports

{
  "exports": {
    ".": {
      "development": "./dist/index.development.js",
      "production": "./dist/index.production.js",
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs",
      "default": "./dist/index.js"
    }
  }
}

Runtime-Specific Formats

Node.js Optimized

export default defineConfig({
  rollup: {
    output: {
      format: 'cjs',
      file: 'dist/index.node.js',
      // Node.js optimizations
      preferConst: true,
      compact: true
    }
  }
})

Browser Optimized

export default defineConfig({
  rollup: {
    output: {
      format: 'iife',
      file: 'dist/index.browser.js',
      name: 'MyLibrary',
      // Browser optimizations
      sourcemap: true,
      compact: true
    }
  }
})

Edge Runtime

export default defineConfig({
  rollup: {
    output: {
      format: 'esm',
      file: 'dist/index.edge.mjs',
      // Edge runtime optimizations
      generatedCode: {
        preset: 'es2022'
      }
    }
  }
})

Advanced Configuration

Code Splitting

export default defineConfig({
  rollup: {
    output: {
      format: 'esm',
      dir: 'dist',
      // Enable code splitting
      manualChunks: {
        vendor: ['react', 'react-dom'],
        utils: ['lodash', 'date-fns']
      }
    }
  }
})

Dynamic Imports

export default defineConfig({
  rollup: {
    output: {
      format: 'esm',
      dir: 'dist',
      // Configure dynamic import format
      chunkFileNames: 'chunks/[name]-[hash].js',
      dynamicImportFunction: 'import'
    }
  }
})

Tree Shaking

export default defineConfig({
  rollup: {
    output: {
      format: 'esm',
      file: 'dist/index.mjs',
      // Preserve modules for better tree shaking
      preserveModules: true,
      preserveModulesRoot: 'src'
    }
  }
})

Format Validation

Packem validates that your package.json exports map matches the formats it produces. This runs automatically; configure it through the validation option rather than a manual hook:

import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'

export default defineConfig({
  transformer,
  validation: {
    packageJson: {
      exports: true,
    },
  },
})

See the validation docs for the full set of checks.

Interoperability

ESM/CJS Interop

export default defineConfig({
  cjsInterop: true, // Enable automatic interop
  
  rollup: {
    output: [
      {
        format: 'esm',
        file: 'dist/index.mjs',
        exports: 'named'
      },
      {
        format: 'cjs',
        file: 'dist/index.cjs',
        exports: 'auto',
        interop: 'auto'
      }
    ]
  }
})

Default Export Handling

// For libraries with default exports
export default defineConfig({
  rollup: {
    output: [
      {
        format: 'esm',
        file: 'dist/index.mjs',
        exports: 'default'
      },
      {
        format: 'cjs',
        file: 'dist/index.cjs',
        exports: 'default'
      }
    ]
  }
})

Framework-Specific Formats

React Library

export default defineConfig({
  rollup: {
    external: ['react', 'react-dom'],
    output: [
      {
        format: 'esm',
        file: 'dist/index.mjs',
        globals: {
          'react': 'React',
          'react-dom': 'ReactDOM'
        }
      },
      {
        format: 'cjs',
        file: 'dist/index.cjs'
      }
    ]
  }
})

Vue Library

export default defineConfig({
  rollup: {
    external: ['vue'],
    output: [
      {
        format: 'esm',
        file: 'dist/index.mjs'
      },
      {
        format: 'umd',
        file: 'dist/index.umd.js',
        name: 'MyVueLibrary',
        globals: {
          'vue': 'Vue'
        }
      }
    ]
  }
})

Troubleshooting

Format Mismatch

Ensure your package.json exports match your actual output formats.

{
  "exports": {
    ".": {
      "import": "./dist/index.mjs", // Must be ESM
      "require": "./dist/index.cjs"  // Must be CJS
    }
  }
}

Global Name Conflicts

For IIFE/UMD builds, ensure unique global names:

export default defineConfig({
  rollup: {
    output: {
      format: 'iife',
      name: 'MyUniqueLibraryName', // Avoid conflicts
      extend: false // Don't extend existing globals
    }
  }
})

External Dependencies

dependencies, peerDependencies, and Node built-ins are externalized by default. Use the top-level externals array to force-externalize extra packages, and rollup.resolveExternals to change classification:

import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'

export default defineConfig({
  transformer,
  externals: ['react', 'react-dom'],
})

See the externals option for the full classification controls (deps, peerDeps, exclude, …).

Performance Considerations

Format-Specific Optimizations

export default defineConfig({
  rollup: {
    output: [
      // Development build
      {
        format: 'esm',
        file: 'dist/index.development.mjs',
        sourcemap: true,
        compact: false
      },
      // Production build
      {
        format: 'esm',
        file: 'dist/index.production.mjs',
        sourcemap: false,
        compact: true
      }
    ]
  }
})

Bundle Size Optimization

export default defineConfig({
  rollup: {
    output: {
      format: 'esm',
      file: 'dist/index.mjs',
      // Optimize for size
      compact: true,
      generatedCode: {
        preset: 'es2015',
        arrowFunctions: true,
        constBindings: true,
        objectShorthand: true
      }
    }
  }
})

Support

Contribute to our work and keep us going

Community is the heart of open source. The success of our packages wouldn't be possible without the incredible contributions of users, testers, and developers who collaborate with us every day.Want to get involved? Here are some tips on how you can make a meaningful impact on our open source projects.

Ready to help us out?

Be sure to check out the package's contribution guidelines first. They'll walk you through the process on how to properly submit an issue or pull request to our repositories.

Submit a pull request

Found something to improve? Fork the repo, make your changes, and open a PR. We review every contribution and provide feedback to help you get merged.

Good first issues

Simple issues suited for people new to open source development, and often a good place to start working on a package.
View good first issues