Plugin API for Parcel bundler - provides base classes for creating Parcel plugins including transformers, resolvers, bundlers, namers, runtimes, packagers, optimizers, compressors, reporters, and validators
67
The Bundler plugin controls how assets are grouped into bundles and optimizes the bundle graph for performance, caching, and loading strategies. Bundlers determine the overall structure of the build output.
Base class for creating bundle generation plugins.
/**
* Base class for bundle generation plugins
* @template T - Configuration type for this bundler
*/
export declare class Bundler<T> {
constructor(opts: BundlerOpts<T>);
}
/**
* Bundler plugin configuration interface
* @template ConfigType - Type of configuration returned by loadConfig
*/
interface BundlerOpts<ConfigType> {
/** Load configuration for this bundler */
loadConfig?: (args: {
config: Config;
options: PluginOptions;
logger: PluginLogger;
tracer: PluginTracer;
}) => Promise<ConfigType> | ConfigType;
/** Create bundles from the asset graph (required) */
bundle(args: {
bundleGraph: MutableBundleGraph;
config: ConfigType;
options: PluginOptions;
logger: PluginLogger;
tracer: PluginTracer;
}): Promise<void>;
/** Optimize the bundle graph (required) */
optimize(args: {
bundleGraph: MutableBundleGraph;
config: ConfigType;
options: PluginOptions;
logger: PluginLogger;
}): Promise<void>;
}Usage Example:
import { Bundler } from "@parcel/plugin";
export default new Bundler({
// Load bundler configuration
loadConfig({config}) {
return {
minBundleSize: config.minBundleSize || 1000,
maxBundleSize: config.maxBundleSize || 100000,
splitChunks: config.splitChunks !== false
};
},
// Create bundles from assets (required)
async bundle({bundleGraph, config, logger}) {
// Get all assets
const assets = bundleGraph.getAssets();
// Create entry bundles
for (const entry of bundleGraph.getEntryAssets()) {
const bundle = bundleGraph.createBundle({
entryAsset: entry,
target: entry.env.context,
type: getOutputType(entry.type)
});
bundleGraph.addAssetToBundle(entry, bundle);
}
// Group related assets into shared bundles
if (config.splitChunks) {
await this.createSharedBundles(bundleGraph, config);
}
},
// Optimize bundle graph (required)
async optimize({bundleGraph, config, logger}) {
// Remove empty bundles
for (const bundle of bundleGraph.getBundles()) {
if (bundleGraph.getBundleAssets(bundle).length === 0) {
bundleGraph.removeBundle(bundle);
}
}
// Merge small bundles
await this.mergeSmallBundles(bundleGraph, config);
// Optimize bundle dependencies
await this.optimizeBundleDependencies(bundleGraph);
}
});/**
* Mutable bundle graph for creating and modifying bundles
*/
interface MutableBundleGraph {
/** Get all assets in the graph */
getAssets(): Array<Asset>;
/** Get entry assets */
getEntryAssets(): Array<Asset>;
/** Get all bundles */
getBundles(): Array<Bundle>;
/** Create a new bundle */
createBundle(options: CreateBundleOptions): Bundle;
/** Remove a bundle */
removeBundle(bundle: Bundle): void;
/** Add an asset to a bundle */
addAssetToBundle(asset: Asset, bundle: Bundle): void;
/** Remove an asset from a bundle */
removeAssetFromBundle(asset: Asset, bundle: Bundle): void;
/** Get assets in a specific bundle */
getBundleAssets(bundle: Bundle): Array<Asset>;
/** Create a dependency between bundles */
createBundleDependency(from: Bundle, to: Bundle): void;
/** Get bundles that depend on the given bundle */
getBundleDependents(bundle: Bundle): Array<Bundle>;
/** Get bundles that the given bundle depends on */
getBundleDependencies(bundle: Bundle): Array<Bundle>;
}
/**
* Options for creating a new bundle
*/
interface CreateBundleOptions {
/** Entry asset for the bundle */
entryAsset?: Asset;
/** Bundle target */
target: Target;
/** Bundle output type */
type: string;
/** Whether this bundle needs a stable name */
needsStableName?: boolean;
/** Bundle behavior */
bundleBehavior?: BundleBehavior;
/** Bundle priority */
priority?: BundlePriority;
/** Environment for this bundle */
env?: EnvironmentOptions;
}
/**
* Bundle priority levels
*/
type BundlePriority = "sync" | "parallel" | "lazy";/**
* A bundle in the bundle graph
*/
interface Bundle {
/** Bundle ID */
id: string;
/** Bundle type */
type: string;
/** Target environment */
target: Target;
/** Entry asset if this is an entry bundle */
entryAsset?: Asset;
/** Main entry asset */
mainEntryAsset?: Asset;
/** Bundle file path */
filePath?: FilePath;
/** Bundle name */
name?: string;
/** Bundle display name */
displayName?: string;
/** Bundle statistics */
stats: BundleStats;
/** Environment for this bundle */
env: Environment;
/** Whether this bundle needs a stable name */
needsStableName: boolean;
/** Bundle behavior */
bundleBehavior?: BundleBehavior;
/** Bundle metadata */
meta: Record<string, any>;
}
/**
* Bundle statistics
*/
interface BundleStats {
/** Bundle size in bytes */
size: number;
/** Time to create bundle */
time: number;
}Entry Point Bundling:
// Create a bundle for each entry point
for (const entry of bundleGraph.getEntryAssets()) {
const bundle = bundleGraph.createBundle({
entryAsset: entry,
target: entry.target,
type: getOutputType(entry.type),
needsStableName: true
});
bundleGraph.addAssetToBundle(entry, bundle);
}Code Splitting:
// Create shared bundles for common dependencies
const sharedAssets = findSharedAssets(bundleGraph);
if (sharedAssets.length > 0) {
const sharedBundle = bundleGraph.createBundle({
target: primaryTarget,
type: 'js',
bundleBehavior: 'inline'
});
for (const asset of sharedAssets) {
bundleGraph.addAssetToBundle(asset, sharedBundle);
}
}Size-based Optimization:
// Merge small bundles to reduce HTTP requests
const smallBundles = bundleGraph.getBundles().filter(bundle =>
bundle.stats.size < config.minBundleSize
);
for (const smallBundle of smallBundles) {
const targetBundle = findMergeTarget(smallBundle, bundleGraph);
if (targetBundle) {
mergeBundles(smallBundle, targetBundle, bundleGraph);
}
}Install with Tessl CLI
npx tessl i tessl/npm-parcel--plugindocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10