Config File
Set up and configure Packem using configuration files
Config File
Packem supports configuration files to customize your build process. While many options can be set via CLI flags, configuration files provide a more maintainable and powerful way to configure complex builds.
Configuration File Discovery
Packem automatically discovers configuration files in the following order:
packem.config.tspackem.config.jspackem.config.mjspackem.config.cjs
TypeScript configuration files (packem.config.ts) are recommended as they provide type safety and autocomplete support.
Basic Configuration
TypeScript Configuration
// packem.config.ts
import { defineConfig } from '@visulima/packem/config'
export default defineConfig({
// Choose your transformer
transformer: 'esbuild',
// Rollup configuration
rollup: {
output: {
format: 'esm',
dir: 'dist'
},
sourcemap: true
}
})JavaScript Configuration
// packem.config.js
import { defineConfig } from '@visulima/packem/config'
export default defineConfig({
transformer: 'esbuild',
rollup: {
output: {
format: 'esm',
dir: 'dist'
}
}
})CommonJS Configuration
// packem.config.cjs
const { defineConfig } = require('@visulima/packem/config')
module.exports = defineConfig({
transformer: 'esbuild',
rollup: {
output: {
format: 'cjs',
dir: 'dist'
}
}
})Configuration Schema
The defineConfig function provides full TypeScript support and validation:
export default defineConfig({
// Entry points (optional - auto-detected from package.json)
entry?: string | string[] | Record<string, string>
// Transformer selection
transformer?: 'esbuild' | 'swc' | 'oxc' | 'sucrase' | 'typescript'
// Rollup configuration
rollup?: {
input?: InputOption
output?: OutputOptions | OutputOptions[]
plugins?: Plugin[]
external?: ExternalOption
// ... other Rollup options
}
// CSS configuration
css?: {
extract?: boolean
modules?: boolean | CssModulesOptions
loaders?: CssLoader[]
// ... other CSS options
}
// Transformer-specific options
esbuild?: EsbuildOptions
swc?: SwcOptions
oxc?: OxcOptions
sucrase?: SucraseOptions
typescript?: TypeScriptOptions
// Build hooks
hooks?: {
'build:before'?: (config) => void | Promise<void>
'build:after'?: (result) => void | Promise<void>
// ... other hooks
}
})Advanced Configuration
Conditional Configuration
Configure different options based on environment:
export default defineConfig({
transformer: process.env.NODE_ENV === 'development' ? 'esbuild' : 'swc',
rollup: {
output: {
format: 'esm',
dir: 'dist',
sourcemap: process.env.NODE_ENV === 'development'
},
plugins: [
// Development plugins
...(process.env.NODE_ENV === 'development' ? [devPlugin()] : []),
// Production plugins
...(process.env.NODE_ENV === 'production' ? [prodPlugin()] : [])
]
}
})Function-Based Configuration
Use a function for dynamic configuration:
export default defineConfig((env) => {
const isProduction = env === 'production'
return {
transformer: isProduction ? 'swc' : 'esbuild',
rollup: {
output: {
format: 'esm',
dir: 'dist',
sourcemap: !isProduction
}
},
css: {
extract: isProduction,
modules: true
}
}
})Async Configuration
Load configuration asynchronously:
export default defineConfig(async () => {
const packageJson = await import('./package.json')
return {
transformer: 'esbuild',
rollup: {
output: {
format: packageJson.type === 'module' ? 'esm' : 'cjs',
dir: 'dist'
}
}
}
})Multiple Configurations
Export an array of configurations for multiple builds:
export default defineConfig([
// ESM build
{
transformer: 'esbuild',
rollup: {
output: {
format: 'esm',
file: 'dist/index.mjs'
}
}
},
// CJS build
{
transformer: 'esbuild',
rollup: {
output: {
format: 'cjs',
file: 'dist/index.cjs'
}
}
},
// IIFE build for browsers
{
transformer: 'esbuild',
rollup: {
output: {
format: 'iife',
file: 'dist/index.global.js',
name: 'MyLibrary'
}
}
}
])Configuration Merging
Packem automatically merges configurations from multiple sources:
- Default configuration - Sensible defaults
- Configuration file - Your custom configuration
- CLI flags - Command-line overrides
// packem.config.ts
export default defineConfig({
transformer: 'esbuild',
rollup: {
output: {
dir: 'dist'
}
}
})# CLI flags override config file
packem build --transformer swc --outDir buildEnvironment Variables
Access environment variables in your configuration:
export default defineConfig({
transformer: process.env.PACKEM_TRANSFORMER || 'esbuild',
rollup: {
output: {
dir: process.env.PACKEM_OUTPUT_DIR || 'dist',
sourcemap: process.env.NODE_ENV !== 'production'
}
},
// Custom environment variables
define: {
'process.env.VERSION': JSON.stringify(process.env.npm_package_version),
'process.env.BUILD_TIME': JSON.stringify(new Date().toISOString())
}
})Loading from .env Files
You can load compile-time environment variables from .env files:
export default defineConfig({
// Path to the .env file (relative to project root or absolute)
envFile: '.env',
// Prefix to filter environment variables (default: 'PACKEM_')
// Only variables starting with this prefix will be loaded
envPrefix: 'PACKEM_',
// ...
})CLI Options:
You can also specify these via command-line flags:
# Load from .env file
packem build --env-file .env
# Custom prefix
packem build --env-file .env --env-prefix BUILD_
# CLI options override config file options
packem build --env-file .env.production --env-prefix PROD_How it works:
- Variables are loaded from the specified
.envfile - Only variables matching the
envPrefixare included (default:PACKEM_) - Variables are replaced at compile-time in your source code
- CLI
--env.*variables override.envfile variables
Example:
# .env file
PACKEM_API_URL=https://api.example.com
PACKEM_VERSION=1.0.0
OTHER_VAR=ignored # Not loaded (doesn't match prefix)// src/index.ts
export const apiUrl = process.env.PACKEM_API_URL;
export const version = process.env.PACKEM_VERSION;After building, these will be replaced with their actual values at compile-time.
Configuration Validation
Packem validates your configuration and provides helpful error messages:
export default defineConfig({
transformer: 'invalid', // ❌ TypeScript error
rollup: {
output: {
format: 'unknown' // ❌ TypeScript error
}
}
})Custom Configuration Location
Specify a custom configuration file location:
packem build --config ./configs/packem.config.tsPACKEM_CONFIG=./configs/packem.config.ts packem buildConfiguration Presets
Packem provides built-in presets for common use cases, and you can also create your own reusable configuration presets.
Built-in Presets
React Preset
The React preset configures Babel to handle React JSX transformation. Babel runs before your main transformer (esbuild/SWC/etc.), transforming JSX into JavaScript that the transformer can then process. TypeScript is handled by the transformer via parser plugins, not by Babel.
Quick Setup:
Use the add command to automatically configure React:
npx packem add reactThis will automatically set up the React preset and install all necessary dependencies.
Basic Usage:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: 'react',
transformer,
})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
}),
transformer,
})With React Compiler Annotation Mode:
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: {
compilationMode: 'annotation',
panicThreshold: 'critical_errors'
}
}),
transformer,
})Custom Options:
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,
plugins: [], // Additional Babel plugins
presets: [] // Additional Babel presets
}),
transformer,
})How it works:
- Babel (runs first): Transforms JSX → JS (handles JSX transformation with React Compiler if enabled)
- Transformer (esbuild/SWC/etc.): Processes the code and handles TypeScript transformation via parser plugins
- Rollup plugins: Can parse the code since it's pure JavaScript
React Preset Options:
compiler: Enable React Compiler optimizationboolean: Enable with default optionsobject: Configure compiler optionscompilationMode:"infer"(default) or"annotation"- In annotation mode, only files with"use memo"directive are processedpanicThreshold:"critical_errors"(default) or"all_errors"
plugins: Additional Babel plugins to includepresets: Additional Babel presets to include
Note: The React preset automatically excludes react and react-dom from unused dependency validation, as these are typically peer dependencies. TypeScript is handled by the transformer (esbuild/SWC/etc.) via parser plugins, not by Babel. This matches the approach used by @vitejs/plugin-react.
SolidJS Preset
The SolidJS preset configures Babel to handle SolidJS JSX transformation. Babel runs before your main transformer (esbuild/SWC/etc.), transforming JSX into JavaScript that the transformer can then process. TypeScript is handled by the transformer via parser plugins, not by Babel.
Quick Setup:
Use the add command to automatically configure SolidJS:
npx packem add solidThis will automatically set up the SolidJS preset and install all necessary dependencies.
Basic Usage:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: 'solid',
transformer,
})With Custom Solid Options:
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,
moduleName: 'solid-js/web'
}
}),
transformer,
})With Custom Babel Options:
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: 'dom'
},
env: {
targets: 'last 2 years'
},
typescript: true
}),
transformer,
})How it works:
- Babel (runs first): Transforms JSX → JS (handles JSX transformation with Solid preset)
- Transformer (esbuild/SWC/etc.): Processes the code and handles TypeScript transformation via parser plugins
- Rollup plugins: Can parse the code since it's pure JavaScript
Solid Preset Options:
solidOptions: Configure SolidJS-specific optionsmoduleName: Runtime module name (default:"solid-js/web")generate: Output mode -"dom"(default) or"ssr"for server-side renderinghydratable: Enable hydratable markers (default:false)delegateEvents: Enable automatic event delegation (default:true)wrapConditionals: Enable smart conditional detection (default:true)contextToCustomElements: Set render context on Custom Elements (default:true)builtIns: Array of Component exports to auto-import
env: Enable @babel/preset-env (default:true)boolean: Enable with default targets ("last 2 years")object: Configure with custom targets
plugins: Additional Babel plugins to includepresets: Additional Babel presets to include
Note: The Solid preset automatically excludes solid-js, solid-js/web, and solid-js/store from unused dependency validation, as these are typically peer dependencies. TypeScript is handled by the transformer (esbuild/SWC/etc.) via parser plugins, not by Babel.
Vue Preset
The Vue preset configures Rollup with unplugin-vue to handle Vue 3 Single File Components (SFCs). The plugin processes .vue files and compiles them for Rollup bundling.
Quick Setup:
Use the add command to automatically configure Vue:
npx packem add vueThis will automatically set up the Vue preset and install all necessary dependencies.
Basic Usage:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: 'vue',
transformer,
})With Custom Options:
import { defineConfig } from '@visulima/packem/config'
import { createVuePreset } from '@visulima/packem/config/preset/vue'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: createVuePreset({
pluginOptions: {
customElement: true,
include: [/\.vue$/],
exclude: [/\.vue\.test\.vue$/],
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('my-')
}
}
}
}),
transformer,
})How it works:
- Rollup Plugin (unplugin-vue): Processes
.vuefiles, extracts<script>,<template>, and<style>blocks - Transformer (esbuild/SWC/etc.): Processes the compiled JavaScript and handles TypeScript transformation
- CSS Processing: Styles are handled by Packem's CSS processing pipeline
Vue Preset Options:
pluginOptions: Configure the Vue plugin optionscustomElement: Enable custom elements mode (default:false)include: Include patterns for Vue files (default:[/\.vue$/])exclude: Exclude patterns for Vue filestemplate: Template compiler optionscompilerOptions: Vue template compiler optionsisCustomElement: Function to determine if a tag is a custom element
Note: The Vue preset automatically excludes vue from unused dependency validation, as it's typically a peer dependency.
Svelte Preset
The Svelte preset configures Rollup with rollup-plugin-svelte to handle Svelte components. The plugin processes .svelte files and compiles them for Rollup bundling.
Quick Setup:
Use the add command to automatically configure Svelte:
npx packem add svelteThis will automatically set up the Svelte preset and install all necessary dependencies.
Basic Usage:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: 'svelte',
transformer,
})With Custom Options:
import { defineConfig } from '@visulima/packem/config'
import { createSveltePreset } from '@visulima/packem/config/preset/svelte'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: createSveltePreset({
pluginOptions: {
compilerOptions: {
generate: 'ssr',
hydratable: true,
customElement: false
},
include: [/\.svelte$/],
exclude: [/\.svelte\.test\.svelte$/],
preprocess: {
// Preprocessor options
}
}
}),
transformer,
})How it works:
- Rollup Plugin (rollup-plugin-svelte): Processes
.sveltefiles, compiles components to JavaScript - Transformer (esbuild/SWC/etc.): Processes the compiled JavaScript and handles TypeScript transformation
- CSS Processing: Styles are extracted and handled by Packem's CSS processing pipeline
Svelte Preset Options:
pluginOptions: Configure the Svelte plugin optionscompilerOptions: Svelte compiler optionsgenerate: Output mode -"dom"(default) or"ssr"for server-side renderinghydratable: Enable hydratable markers (default:false)customElement: Compile components to custom elements (default:false)dev: Enable dev mode (default:false)
include: Include patterns for Svelte files (default:[/\.svelte$/])exclude: Exclude patterns for Svelte filespreprocess: Preprocessor options for Svelte components
Note: The Svelte preset automatically excludes svelte from unused dependency validation, as it's typically a peer dependency.
Custom Presets
Create reusable configuration presets:
// configs/presets.ts
export const libraryPreset = {
transformer: 'esbuild' as const,
rollup: {
output: {
format: 'esm' as const,
dir: 'dist'
},
sourcemap: true
},
hooks: {
'build:before': async () => {
console.log('Preset hook: Preparing library build')
}
}
}
export const cliPreset = {
transformer: 'esbuild' as const,
rollup: {
output: {
format: 'cjs' as const,
dir: 'bin'
}
}
}// packem.config.ts
import { defineConfig } from '@visulima/packem/config'
import { libraryPreset } from './configs/presets'
export default defineConfig({
...libraryPreset,
// Override specific options
rollup: {
...libraryPreset.rollup,
css: {
mode: 'extract'
}
},
// Hooks from preset are automatically merged
// You can add your own hooks or override preset hooks
hooks: {
'build:after': async () => {
console.log('User hook: Build completed')
}
// Preset's 'build:before' hook is still registered
}
})Hooks from presets are automatically merged with your configuration. If you define the same hook in both, your hook will take precedence.
Configuration Composition
Compose configurations from multiple sources:
import { defineConfig } from '@visulima/packem/config'
import { mergeConfig } from '@visulima/packem/utils'
import baseConfig from './base.config'
import cssConfig from './css.config'
export default defineConfig(
mergeConfig(
baseConfig,
cssConfig,
{
// Additional overrides
transformer: 'swc'
}
)
)IDE Support
TypeScript IntelliSense
Get full autocomplete and type checking in your configuration:
import { defineConfig } from '@visulima/packem/config'
export default defineConfig({
// TypeScript will provide autocomplete here
transformer: '|', // Shows: 'esbuild' | 'swc' | 'oxc' | 'sucrase' | 'typescript'
rollup: {
output: {
format: '|' // Shows: 'es' | 'cjs' | 'iife' | 'umd' | 'system'
}
}
})Configuration Schema
Import types for better IDE support:
import type { PackemConfig } from '@visulima/packem/config'
const config: PackemConfig = {
transformer: 'esbuild',
rollup: {
output: {
format: 'esm',
dir: 'dist'
}
}
}
export default defineConfig(config)Debugging Configuration
Enable debug mode to see the resolved configuration:
# Debug configuration resolution
PACKEM_DEBUG=1 packem build
# Debug specific areas
PACKEM_DEBUG=config,rollup packem buildOr programmatically:
export default defineConfig({
debug: true, // Enable debug logging
transformer: 'esbuild',
// ... rest of config
})Configuration Examples
React Library
export default defineConfig({
transformer: 'esbuild',
esbuild: {
jsx: 'automatic',
jsxImportSource: 'react'
},
rollup: {
external: ['react', 'react-dom'],
output: [
{ format: 'esm', file: 'dist/index.mjs' },
{ format: 'cjs', file: 'dist/index.cjs' }
]
}
})Node.js CLI Tool
export default defineConfig({
transformer: 'esbuild',
rollup: {
output: {
format: 'cjs',
file: 'bin/cli.js',
banner: '#!/usr/bin/env node'
}
}
})Full-Stack Library
export default defineConfig([
// Server build
{
entry: 'src/server.ts',
transformer: 'esbuild',
rollup: {
output: {
format: 'cjs',
file: 'dist/server.js'
},
external: ['express', 'mongoose']
}
},
// Client build
{
entry: 'src/client.ts',
transformer: 'esbuild',
rollup: {
output: {
format: 'esm',
file: 'dist/client.mjs'
}
},
css: {
extract: true,
modules: true
}
}
])Related Options
- Entry - Configure entry points
- Output Format - Control output formats
- Transformers - Choose and configure transformers
- Hooks - Build lifecycle hooks