Plugins
Configure and extend Packem with Rollup plugins
Plugins
Packem leverages Rollup's powerful plugin ecosystem to extend functionality. You can use any Rollup plugin or create custom plugins to handle specific build requirements.
Basic Plugin Usage
Adding Plugins
import { defineConfig } from '@visulima/packem'
import { nodeResolve } from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
export default defineConfig({
rollup: {
plugins: [
nodeResolve(),
commonjs()
]
}
})Built-in Plugins
Packem includes several plugins by default:
export default defineConfig({
// These are enabled automatically
autoPlugins: {
nodeResolve: true,
commonjs: true,
json: true,
typescript: true // If using TypeScript
}
})Common Plugins
Node Resolution
import { nodeResolve } from '@rollup/plugin-node-resolve'
export default defineConfig({
rollup: {
plugins: [
nodeResolve({
preferBuiltins: true,
browser: false,
exportConditions: ['node']
})
]
}
})CommonJS Support
import commonjs from '@rollup/plugin-commonjs'
export default defineConfig({
rollup: {
plugins: [
commonjs({
include: ['node_modules/**'],
exclude: ['node_modules/some-esm-package/**']
})
]
}
})JSON Import
import json from '@rollup/plugin-json'
export default defineConfig({
rollup: {
plugins: [
json({
compact: true,
namedExports: true
})
]
}
})Replace Variables
import replace from '@rollup/plugin-replace'
export default defineConfig({
rollup: {
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
'__VERSION__': JSON.stringify(process.env.npm_package_version),
preventAssignment: true
})
]
}
})Framework Plugins
React
Quick Setup (Recommended):
Use the add command to automatically configure React:
npx packem add reactThis will:
- Add
preset: 'react'to your config - Install React, React DOM, and Babel dependencies
- Automatically detect TypeScript and add
@types/reactand@types/react-domif TypeScript is installed - Prompt you to add TypeScript if not already installed
Manual Configuration:
Packem provides a built-in React preset that configures Babel for React JSX transformation:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: 'react', // Automatically configures Babel for 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 // Enable React Compiler optimization
}),
transformer,
})Manual Babel Configuration:
If you need more control, you can configure Babel manually:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
transformer,
externals: ['react', 'react-dom'],
rollup: {
babel: {
presets: [
['@babel/preset-react', { runtime: 'automatic' }]
// Note: TypeScript is handled by the transformer via parser plugins
// Babel only needs to parse TypeScript syntax, not transform it
],
plugins: [
// Add custom Babel plugins here
]
}
}
})Note: When using Babel with React, Babel runs before your main transformer (esbuild/SWC/etc.), transforming JSX into JavaScript. TypeScript is handled by the transformer via parser plugins, not by Babel. This ensures that Rollup plugins can properly parse the code.
SolidJS
Quick Setup (Recommended):
Use the add command to automatically configure SolidJS:
npx packem add solidThis will:
- Add
preset: 'solid'to your config - Install SolidJS and Babel dependencies
Manual Configuration:
Packem provides a built-in Solid preset that configures Babel for SolidJS JSX transformation:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: 'solid', // Automatically configures Babel for SolidJS
transformer,
})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,
})Manual Babel Configuration:
If you need more control, you can configure Babel manually:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
transformer,
externals: ['solid-js', 'solid-js/web', 'solid-js/store'],
rollup: {
babel: {
presets: [
['babel-preset-solid', { generate: 'dom' }],
['@babel/preset-env', { bugfixes: true, targets: 'last 2 years' }]
// Note: TypeScript is handled by the transformer via parser plugins
// Babel only needs to parse TypeScript syntax, not transform it
],
plugins: [
// Add custom Babel plugins here
]
}
}
})Note: When using Babel with SolidJS, Babel runs before your main transformer (esbuild/SWC/etc.), transforming JSX into JavaScript. TypeScript is handled by the transformer via parser plugins, not by Babel. This ensures that Rollup plugins can properly parse the code.
Vue
import Vue from 'unplugin-vue/rollup'
export default defineConfig({
rollup: {
plugins: [
Vue({
include: [/\.vue$/],
customElement: false
})
]
}
})Note: For Vue 3 projects, you can also use the Vue preset instead of manually configuring the plugin:
export default defineConfig({
preset: 'vue'
})Svelte
import svelte from 'rollup-plugin-svelte'
export default defineConfig({
rollup: {
plugins: [
svelte({
compilerOptions: {
hydratable: true
}
})
]
}
})Note: For Svelte projects, you can also use the Svelte preset instead of manually configuring the plugin:
export default defineConfig({
preset: 'svelte'
})Asset Plugins
Copy Files
import copy from 'rollup-plugin-copy'
export default defineConfig({
rollup: {
plugins: [
copy({
targets: [
{ src: 'src/assets/*', dest: 'dist/assets' },
{ src: 'public/favicon.ico', dest: 'dist' }
]
})
]
}
})Image Processing
import image from '@rollup/plugin-image'
export default defineConfig({
rollup: {
plugins: [
image({
include: ['**/*.png', '**/*.jpg', '**/*.jpeg', '**/*.gif'],
limit: 8192 // Inline images smaller than 8KB
})
]
}
})URL Assets
import url from '@rollup/plugin-url'
export default defineConfig({
rollup: {
plugins: [
url({
limit: 10 * 1024, // 10KB
include: ['**/*.svg', '**/*.png', '**/*.jpg'],
emitFiles: true
})
]
}
})Data URI imports (?data-uri)
Inline files as data URIs at import sites. SVG files are encoded as tiny, human-readable data URIs; other file types are base64-encoded.
import { defineConfig } from '@visulima/packem/config'
import { dataUriPlugin } from '@visulima/packem-rollup/plugins'
export default defineConfig({
rollup: {
plugins: [
dataUriPlugin({
// Optional: when using output in an <img srcset="..."> attribute
// spaces are encoded as %20 to be srcset-safe
srcset: false
})
]
}
})Usage examples:
// SVG ? tiny data URI (not base64), whitespace-collapsed
import icon from './assets/icon.svg?data-uri'
// Any other file ? base64 data URI with appropriate mime type
import txt from './assets/readme.txt?data-uri'Notes:
- Only imports ending with
?data-uriare transformed; regular imports are unaffected. - SVGs are encoded as
data:image/svg+xml,....(tiny URI). Others asdata:<mime>;base64,.... - For
srcsetattributes, enable{ srcset: true }to encode spaces as%20.
Development Plugins
Live Reload
import livereload from 'rollup-plugin-livereload'
export default defineConfig({
rollup: {
plugins: [
...(process.env.NODE_ENV === 'development' ? [
livereload({
watch: 'dist',
port: 35729
})
] : [])
]
}
})Serve Files
import serve from 'rollup-plugin-serve'
export default defineConfig({
rollup: {
plugins: [
...(process.env.NODE_ENV === 'development' ? [
serve({
open: true,
contentBase: 'dist',
port: 3000
})
] : [])
]
}
})Analysis Plugins
Bundle Analyzer
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
rollup: {
plugins: [
visualizer({
filename: 'dist/stats.html',
open: true,
gzipSize: true
})
]
}
})Bundle Size
import bundleSize from 'rollup-plugin-bundle-size'
export default defineConfig({
rollup: {
plugins: [
bundleSize()
]
}
})License Check
import license from 'rollup-plugin-license'
export default defineConfig({
rollup: {
plugins: [
license({
sourcemap: true,
banner: {
commentStyle: 'regular',
content: {
file: path.join(__dirname, 'LICENSE')
}
},
thirdParty: {
output: path.join(__dirname, 'dist', 'dependencies.txt')
}
})
]
}
})Custom Plugins
Simple Plugin
function customPlugin() {
return {
name: 'custom-plugin',
buildStart() {
console.log('Build started!')
},
transform(code, id) {
if (id.endsWith('.custom')) {
return `export default ${JSON.stringify(code)}`
}
return null
},
generateBundle() {
console.log('Bundle generated!')
}
}
}
export default defineConfig({
rollup: {
plugins: [
customPlugin()
]
}
})Advanced Plugin
function advancedPlugin(options = {}) {
const { include = '**/*.js', exclude = 'node_modules/**' } = options
return {
name: 'advanced-plugin',
buildStart(opts) {
// Plugin initialization
this.addWatchFile('config.json')
},
resolveId(id, importer) {
// Custom module resolution
if (id === 'virtual:my-module') {
return id
}
return null
},
load(id) {
// Load custom modules
if (id === 'virtual:my-module') {
return 'export const msg = "Hello from virtual module"'
}
return null
},
transform(code, id) {
// Transform code
if (include.test && include.test(id) && !exclude.test(id)) {
return {
code: code.replace(/OLD_SYNTAX/g, 'NEW_SYNTAX'),
map: null
}
}
return null
}
}
}Plugin Configuration
Conditional Plugins
export default defineConfig({
rollup: {
plugins: [
// Always included
nodeResolve(),
commonjs(),
// Development only
...(process.env.NODE_ENV === 'development' ? [
serve({ contentBase: 'dist' }),
livereload()
] : []),
// Production only
...(process.env.NODE_ENV === 'production' ? [
terser(),
visualizer()
] : [])
]
}
})Plugin Options
export default defineConfig({
rollup: {
plugins: [
nodeResolve({
// Prefer built-in Node.js modules
preferBuiltins: true,
// Include/exclude packages
include: ['node_modules/**'],
exclude: ['node_modules/problematic-package/**'],
// Custom conditions
exportConditions: ['node', 'import'],
// Browser compatibility
browser: false
})
]
}
})Plugin Ordering
export default defineConfig({
rollup: {
plugins: [
// 1. Module resolution
nodeResolve(),
// 2. Format conversion
commonjs(),
// 3. Code transformation
typescript(),
// Babel is configured via rollup.babel option or React preset
// See React section above for examples
// 4. Asset processing
postcss(),
image(),
// 5. Development tools
...(isDev ? [serve(), livereload()] : []),
// 6. Production optimization
...(isProd ? [terser(), visualizer()] : [])
]
}
})Plugin Ecosystem
Essential Plugins
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
import { nodeResolve } from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import replace from '@rollup/plugin-replace'
import json from '@rollup/plugin-json'
export default defineConfig({
transformer,
rollup: {
// Babel is configured via rollup.babel option (not as a plugin)
// For React, use preset: 'react' instead
babel: {
presets: ['@babel/preset-env'],
plugins: []
},
plugins: [
nodeResolve(),
commonjs(),
replace({ preventAssignment: true }),
json()
]
}
})CSS Plugins
import postcss from 'rollup-plugin-postcss'
import autoprefixer from 'autoprefixer'
import cssnano from 'cssnano'
export default defineConfig({
rollup: {
plugins: [
postcss({
extract: true,
minimize: true,
plugins: [
autoprefixer(),
cssnano()
]
})
]
}
})Testing Plugins
import istanbul from 'rollup-plugin-istanbul'
export default defineConfig({
rollup: {
plugins: [
...(process.env.NODE_ENV === 'test' ? [
istanbul({
exclude: ['test/**/*', 'node_modules/**/*']
})
] : [])
]
}
})Plugin Development
Plugin Template
interface PluginOptions {
include?: string | RegExp | (string | RegExp)[]
exclude?: string | RegExp | (string | RegExp)[]
[key: string]: any
}
function myPlugin(options: PluginOptions = {}): Plugin {
const filter = createFilter(options.include, options.exclude)
return {
name: 'my-plugin',
buildStart(opts) {
// Initialize plugin
},
resolveId(id, importer) {
// Resolve imports
return null
},
load(id) {
// Load modules
return null
},
transform(code, id) {
if (!filter(id)) return null
// Transform code
return {
code: transformedCode,
map: sourceMap
}
},
generateBundle(opts, bundle) {
// Process bundle
},
writeBundle(opts, bundle) {
// After bundle written
}
}
}Plugin Testing
import { rollup } from 'rollup'
import myPlugin from './my-plugin'
async function testPlugin() {
const bundle = await rollup({
input: 'test/fixtures/input.js',
plugins: [
myPlugin({
// Test options
})
]
})
const { output } = await bundle.generate({
format: 'esm'
})
console.log(output[0].code)
}Troubleshooting
Plugin Conflicts
Some plugins may conflict with each other. Check plugin documentation for compatibility.
export default defineConfig({
rollup: {
plugins: [
// Order matters - resolve conflicts by reordering
nodeResolve(),
commonjs(),
// Avoid duplicate functionality
// Note: When using Babel with React preset, Babel handles JSX transformation
// TypeScript is handled by the transformer (esbuild/SWC) via parser plugins
]
}
})Plugin Errors
export default defineConfig({
rollup: {
onwarn(warning, warn) {
// Handle plugin warnings
if (warning.plugin === 'problematic-plugin') {
return // Ignore warnings from this plugin
}
warn(warning)
}
}
})Performance Issues
export default defineConfig({
rollup: {
plugins: [
// Use plugin caching
somePlugin({
cache: true
}),
// Limit plugin scope
anotherPlugin({
include: 'src/**',
exclude: 'node_modules/**'
})
]
}
})Related Options
- Rollup - Rollup configuration
- Transform - Code transformation
- Assets - Asset handling
- External - External dependencies