Configuration

Complete guide to configuring Packem for your project needs

Configuration

Learn how to configure Packem to meet your specific project requirements with detailed examples and best practices.

Configuration File

Packem uses a packem.config.ts file for configuration. This file should be placed in your project root.

Basic Configuration

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

export default defineConfig({
  transformer,
  sourcemap: true,
  declaration: true
})

Configuration Options

Core Options

transformer

Specify which transformer to use for code compilation:

// esbuild (default, fastest)
import esbuild from '@visulima/packem/transformer/esbuild'

// swc (Rust-powered)
import swc from '@visulima/packem/transformer/swc'

// OXC (experimental)
import oxc from '@visulima/packem/transformer/oxc'

// sucrase (lightweight)
import sucrase from '@visulima/packem/transformer/sucrase'

export default defineConfig({
  transformer: esbuild // or swc, oxc, sucrase
})

sourcemap

Control source map generation:

export default defineConfig({
  sourcemap: true,        // Generate source maps
  sourcemap: false,       // No source maps
  sourcemap: 'inline',    // Inline source maps
  sourcemap: 'hidden'     // Hidden source maps
})

declaration

Generate TypeScript declaration files:

export default defineConfig({
  declaration: true,      // Generate .d.ts files
  declaration: false,     // Skip declaration generation
  declaration: 'compatible', // Generate compatible declarations
  declaration: 'node16'   // Generate node16 declarations
})

minify

Control code minification:

export default defineConfig({
  minify: true,           // Enable minification
  minify: false,          // Disable minification
})

Entry Points

Automatic Detection

Packem automatically detects entry points from your package.json:

{
  "exports": {
    ".": "./src/index.ts",
    "./utils": "./src/utils.ts"
  }
}

Manual Configuration

Override automatic detection:

export default defineConfig({
  entries: [
    'src/index.ts',
    'src/cli.ts',
    'src/utils.ts'
  ]
})

Entry Objects

Use objects for more control:

export default defineConfig({
  entries: [
    {
      input: 'src/index.ts',
      outDir: 'dist'
    },
    {
      input: 'src/cli.ts',
      outDir: 'dist/bin'
    }
  ]
})

Rollup Configuration

Packem is built on Rollup, so you can use any Rollup options:

export default defineConfig({
  rollup: {
    external: ['react', 'react-dom'],
    output: {
      banner: '/* My Library v1.0.0 */',
      footer: '/* End of bundle */'
    },
    plugins: [
      // Additional Rollup plugins
    ],
    watch: {
      include: 'src/**',
      exclude: 'node_modules/**'
    }
  }
})

CSS Configuration

Quick Setup:

Use the add command to interactively configure CSS loaders:

npx packem add css

This will:

  • Prompt you to select a main CSS loader (PostCSS, Lightning CSS, or Tailwind CSS)
  • Ask about additional loaders (Sass, Less, Stylus)
  • Optionally configure CSS minification
  • Install all necessary dependencies
  • Update your packem.config.ts automatically

Manual Configuration:

import postcssLoader from '@visulima/packem/css/loader/postcss'
import sassLoader from '@visulima/packem/css/loader/sass'
import lessLoader from '@visulima/packem/css/loader/less'
import stylusLoader from '@visulima/packem/css/loader/stylus'
import sourceMapLoader from '@visulima/packem/css/loader/sourcemap'
import cssnanoMinifier from '@visulima/packem/css/minifier/cssnano'
import lightningcssMinifier from '@visulima/packem/css/minifier/lightningcss'

export default defineConfig({
  rollup: {
    css: {
      mode: 'extract', // or 'inject'
      loaders: [postcssLoader, sassLoader, lessLoader, stylusLoader, sourceMapLoader],
      minifier: cssnanoMinifier
    }
  }
})

Native Modules Configuration

Configure native Node.js addon (.node files) handling:

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

export default defineConfig({
  transformer,

  rollup: {
    nativeModules: {
      nativesDirectory: 'natives' // Custom directory name
    }
  }
})

The native modules plugin automatically:

  • Detects .node file imports
  • Copies native modules to the output directory
  • Generates appropriate require() statements
  • Handles name collisions and platform-specific files

Options:

  • nativesDirectory: Directory name for native modules (default: 'natives')

After bundling, the .node file will be copied to dist/natives/ and the import will be automatically rewritten to load from the correct location at runtime.

[!NOTE]

  • Native modules are platform and architecture-specific. Make sure to distribute the correct .node files for your target platforms.
  • This only works with direct .node imports. If you're using packages that dynamically load native modules via bindings or node-pre-gyp, you'll need to handle them separately.

Handling dependencies with native modules

If you're using packages with native modules (like chokidar which depends on fsevents):

  • If in dependencies/peerDependencies: ✅ Works automatically - these are externalized (not bundled)
  • If in devDependencies: ⚠️ Will be bundled. If they use bindings() or node-pre-gyp patterns, move them to dependencies instead, or use optionalDependencies if they're optional.

Example - if you have chokidar in devDependencies and get build errors, move it to dependencies:

{
    "dependencies": {
        "chokidar": "^3.0.0"
    }
}

This externalizes it (users will need to install it), avoiding the need to bundle its native modules.

Advanced Configurations

Multi-Format Builds

Build multiple output formats by configuring package.json properly:

{
  "type": "module",
  "main": "./dist/index.cjs",
  "module": "./dist/index.js",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js",
      "require": "./dist/index.cjs"
    }
  }
}

Environment-Specific Config

const isDev = process.env.NODE_ENV === 'development'

export default defineConfig({
  sourcemap: isDev,
  minify: !isDev,
  declaration: !isDev,
  rollup: {
    watch: isDev ? {
      include: 'src/**'
    } : undefined
  }
})

Conditional Configuration

import esbuildTransformer from '@visulima/packem/transformer/esbuild'
import swcTransformer from '@visulima/packem/transformer/swc'

export default defineConfig({
  transformer: process.env.TRANSFORMER === 'swc'
    ? swcTransformer
    : esbuildTransformer,

  externals: process.env.BUNDLE_DEPS
    ? []
    : ['react', 'react-dom']
})

Library-Specific Configurations

React Library

Quick Setup (Recommended):

Use the add command to automatically configure React:

npx packem add react

This will:

  • Add preset: 'react' to your config
  • Install React, React DOM, and Babel dependencies
  • Automatically detect TypeScript and add @types/react and @types/react-dom if TypeScript is installed
  • Prompt you to add TypeScript if not already installed

Manual Configuration:

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

export default defineConfig({
  preset: 'react', // Automatically configures Babel for React
  transformer,
  sourcemap: true,
  declaration: true,
  externals: ['react', 'react-dom'],
  rollup: {
    css: {
      mode: 'extract'
    }
  }
})

With React Compiler:

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

export default defineConfig({
  preset: createReactPreset({
    compiler: true // Enable React Compiler optimization
  }),
  transformer,
  sourcemap: true,
  declaration: true,
  externals: ['react', 'react-dom'],
  rollup: {
    css: {
      mode: 'extract'
    }
  }
})

Manual Configuration:

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

export default defineConfig({
  transformer,
  sourcemap: true,
  declaration: true,
  externals: ['react', 'react-dom'],
  rollup: {
    babel: {
      presets: [
        ['@babel/preset-react', { runtime: 'automatic' }],
        ['@babel/preset-typescript', { allExtensions: true, isTSX: true }]
      ]
    },
    css: {
      mode: 'extract'
    }
  }
})

SolidJS Library

Quick Setup (Recommended):

Use the add command to automatically configure SolidJS:

npx packem add solid

This will:

  • Add preset: 'solid' to your config
  • Install SolidJS and Babel dependencies

Manual Configuration:

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

export default defineConfig({
  preset: 'solid', // Automatically configures Babel for SolidJS
  transformer,
  sourcemap: true,
  declaration: true,
  externals: ['solid-js', 'solid-js/web', 'solid-js/store'],
  rollup: {
    css: {
      mode: 'extract'
    }
  }
})

With SSR Support:

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

export default defineConfig({
  preset: createSolidPreset({
    solidOptions: {
      generate: 'ssr',
      hydratable: true
    }
  }),
  transformer,
  sourcemap: true,
  declaration: true,
  externals: ['solid-js', 'solid-js/web', 'solid-js/store'],
  rollup: {
    css: {
      mode: 'extract'
    }
  }
})

Manual Configuration:

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

export default defineConfig({
  transformer,
  sourcemap: true,
  declaration: true,
  externals: ['solid-js', 'solid-js/web', 'solid-js/store'],
  rollup: {
    babel: {
      presets: [
        ['babel-preset-solid', { generate: 'dom' }],
        ['@babel/preset-typescript', { allExtensions: true, isTSX: true }],
        ['@babel/preset-env', { bugfixes: true, targets: 'last 2 years' }]
      ]
    },
    css: {
      mode: 'extract'
    }
  }
})

Node.js Library

export default defineConfig({
  transformer,
  runtime: 'node',
  externals: (id) => !id.startsWith('.') && !id.startsWith('/')
})

CLI Tool

export default defineConfig({
  entries: [
    {
      input: 'src/cli.ts',
      executable: true
    }
  ],
  externals: ['fs', 'path', 'process']
})

Browser Library

export default defineConfig({
  transformer,
  runtime: 'browser',
  minify: true
})

Configuration Patterns

Shared Configuration

Create reusable configuration:

// config/base.ts
export const baseConfig = {
  transformer,
  sourcemap: true,
  declaration: true
}

// packem.config.ts
import { baseConfig } from './config/base'

export default defineConfig({
  ...baseConfig,
  // Project-specific overrides
})

Factory Functions

// config/factory.ts
export function createConfig(options: {
  target: 'node' | 'browser'
  format: string[]
}) {
  return defineConfig({
    transformer,
    format: options.format,
    target: options.target,
    rollup: {
      external: options.target === 'node'
        ? (id) => !id.startsWith('.')
        : []
    }
  })
}

// packem.config.ts
import { createConfig } from './config/factory'

export default createConfig({
  target: 'node',
  format: ['cjs', 'esm']
})

Plugin System

// plugins/banner.ts
export function bannerPlugin(text: string) {
  return {
    rollup: {
      output: {
        banner: text
      }
    }
  }
}

// packem.config.ts
export default defineConfig({
  transformer,
  ...bannerPlugin('/* My Library */'),
})

TypeScript Integration

Type Checking

Enable type checking during build:

export default defineConfig({
  transformer: typescript, // Use TypeScript compiler
  declaration: true,
  rollup: {
    typescript: {
      check: true,        // Enable type checking
      verbosity: 2,       // Detailed output
      clean: true         // Clean previous declarations
    }
  }
})

Path Mapping

Support TypeScript path mapping:

// tsconfig.json
{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"],
      "@utils/*": ["./src/utils/*"]
    }
  }
}

// packem.config.ts
export default defineConfig({
  transformer,
  rollup: {
    typescript: {
      tsconfig: './tsconfig.json'
    }
  }
})

Debugging Configuration

Verbose Output

export default defineConfig({
  transformer,
  rollup: {
    verbose: true,
    logLevel: 'debug'
  }
})

Bundle Analysis

import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  transformer,
  rollup: {
    plugins: [
      visualizer({
        filename: 'dist/stats.html',
        open: true
      })
    ]
  }
})

Best Practices

Performance Optimization

export default defineConfig({
  transformer: esbuild, // Fastest transformer
  sourcemap: false,     // Disable in production
  declaration: {
    isolated: true      // Faster declarations
  },
  rollup: {
    treeshake: true,    // Enable tree shaking
    external: [         // Externalize dependencies
      'react',
      'react-dom'
    ]
  }
})

Development Experience

const isDev = process.env.NODE_ENV === 'development'

export default defineConfig({
  sourcemap: isDev ? true : false,
  declaration: !isDev,
  rollup: {
    watch: isDev ? {
      include: 'src/**',
      clearScreen: false
    } : undefined
  }
})

Always test your configuration with both development and production builds to ensure everything works correctly.

Common Issues

External Dependencies

Make sure to externalize peer dependencies:

export default defineConfig({
  rollup: {
    external: ['react', 'react-dom', 'lodash']
  }
})

CSS Processing

Configure CSS loaders properly:

export default defineConfig({
  rollup: {
    css: {
      extract: true,  // Extract CSS to separate files
      modules: true   // Enable CSS modules
    }
  }
})

Declaration Generation

Ensure TypeScript configuration is correct:

// tsconfig.json
{
  "compilerOptions": {
    "declaration": true,
    "declarationMap": true,
    "outDir": "dist"
  }
}

This configuration guide provides a comprehensive foundation for setting up Packem in any project scenario.

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