Optimizer

Optimizer plugins are similar to transformers but they accept a bundle instead of a single asset. Optimizers are commonly used to implement minification, tree shaking/dead code elimination, and other size reduction techniques that need a full bundle to be effective. However, Optimizers can also be used for any type of bundle transformation, such as prepending license headers, converting inline bundles to base 64, etc.

Example

#

An optimizer implements one method: optimize. It receives the contents of a bundle and its source map, along with the bundle and the bundle graph, and returns transformed versions of the contents and source map. The contents are passed as bytes, and may be returned as bytes or a string. Multiple Optimizer plugins may run in series, and the result of each Optimizer is passed to the next. See below for more info about source maps.

import { Optimizer } from "@parcel/plugin";

export default new Optimizer({
async optimize({ contents, map }) {
let { code, sourceMap } = minify(contents, map);
return {
contents: code,
map: sourceMap,
};
},
});

See Native plugins for how to build native plugins and use them in a project. The rest of the examples on this page omit the setup code, and only show the optimize method.

Loading configuration

#

Configuration for an Optimizer plugin is specified in the user's .parcelrc. JavaScript plugins receive it as the config option of the optimize method, and native plugins receive it as JSON when they are created. See Configuration for details.

Conditional optimization

#

Optimizer plugins are always run by Parcel, even in development or when the --no-optimize option is specified. This is because Optimizers can be used for any kind of bundle transformation, not just compression. If your Optimizer plugin is performing minification or should generally only run in production builds, you should check whether optimization is enabled for the bundle's target using bundle.target.shouldOptimize, and return the original contents if it isn't.

import {Optimizer} from '@parcel/plugin';

export default new Optimizer({
async optimize({contents, map, bundle}) {
// Don't minify if shouldOptimize is false.
if (!bundle.target.shouldOptimize) {
return {contents, map};
}

let {code, sourceMap} = minify(contents, map);
return {
contents: code,
map: sourceMap
};
}
});

Binary content

#

The contents passed to an Optimizer are always bytes, for both source code and binary content. Decode them as UTF-8 to work with source code as a string. In JavaScript, the contents are a Uint8Array, which can be decoded using TextDecoder. The result can be returned as either a string or bytes.

import {Optimizer} from '@parcel/plugin';

export default new Optimizer({
async optimize({contents, map}) {
let code = new TextDecoder().decode(contents);
let optimized = minify(code);
return {contents: optimized, map};
}
});

Source maps

#

Source maps help developers when debugging compiled and bundled code in the browser by mapping locations in the compiled code back to the original source code. Optimizer plugins should transform the provided source map in addition to the contents of the bundle.

The optimizer receives the bundle's source map as JSON in the standard source map format, or nothing if the bundle doesn't have a source map. JavaScript plugins receive it as an object, and native plugins as JSON text. Optimizers should return the transformed source map along with the contents. In JavaScript, it may be returned as a JSON object, a JSON string, or a Uint8Array of UTF-8 encoded JSON. If an Optimizer doesn't return a source map, the bundle's source map is removed. See Source Maps for more details.

If an optimizer doesn't change the existing lines of the bundle, e.g. because it only appends a license comment to the end, it can return the source map it received unchanged.

Parcel takes care of inserting a reference to the source map into the bundle contents after all Optimizers have run, so Optimizers should not add a sourceMappingURL comment themselves.

import { Optimizer } from "@parcel/plugin";

export default new Optimizer({
async optimize({ contents, map }) {
let result = minify(new TextDecoder().decode(contents), map);
return {
contents: result.code,
map: result.map,
};
},
});

Relevant API

#

The API reference below covers JavaScript plugins. For native plugins, see the Rust, Go, and Swift SDKs.

OptimizerResult packages-v3/plugin/src/types.ts:791

type OptimizerResult = {
  readonly contents: Uint8Array;
  readonly map?: Uint8Array | null;

The source map for the optimized contents, as UTF-8 encoded JSON.

}
Referenced by:
Optimizer

Optimizer packages-v3/plugin/src/types.ts:801

config is the configuration given for the plugin in .parcelrc, if any.

type Optimizer<ConfigType> = {
  optimize(args: {
    bundle: Bundle;
    bundleGraph: BundleGraph;
    contents: Uint8Array;
    map: Uint8Array | null;
    config: ConfigType;
    options: PluginOptions;
  }): Async<OptimizerResult>;
Params:
  • args.map:

    The source map for the bundle, as UTF-8 encoded JSON.

}