Packager
Packager plugins are responsible for combining all of the assets in a bundle together into an output file. They also handle resolving URL references, bundle inlining, and generating source maps.
Example
#This example shows a Packager that concatenates all of the assets in a bundle together. The traverseAsset
method of a Bundle
object traverses all assets within the bundle in depth-first order. The getCode
method is called on each Asset
to retrieve its contents.
import {Packager} from '@parcel/plugin';
export default new Packager({
async package({bundle}) {
let promises = [];
bundle.traverseAssets(asset => {
promises.push(asset.getCode());
});
let contents = await Promise.all(promises);
return {
contents: contents.join('\n')
};
}
});
Loading configuration
#Loading configuration from the user’s project should be done in the loadConfig
method of a Packager plugin. See Loading configuration for details on how to do this.
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. In addition to combining code into a final bundle, Packagers are responsible for combining source maps from each asset into a source map for the bundle.
Parcel uses the @parcel/source-map
library for source map manipulation. See Source Maps for more details on how to use it.
The getSourceMapReference
function passed to Packager plugins can be used to insert a URL to the source map within the bundle contents. Parcel takes care of generating inline source maps when appropriate (e.g. following sourceMap
options in Target config).
import {Packager} from '@parcel/plugin';
import SourceMap from '@parcel/source-map';
import {countLines} from '@parcel/utils';
export default new Packager({
async package({bundle, options, getSourceMapReference}) {
let promises = [];
bundle.traverseAssets(asset => {
promises.push(Promise.all([
asset.getCode(),
asset.getMap()
]));
});
let assets = await Promise.all(promises);
let contents = '';
let map = new SourceMap(options.projectRoot);
let lineOffset = 0;
for (let [code, map] of assets) {
contents += code + '\n';
map.addSourceMap(map, lineOffset);
lineOffset += countLines(code) + 1;
}
contents += `\n//# sourceMappingURL=${await getSourceMapReference(map)}\n`;
return {contents, map};
}
});
URL references
#Transformer plugins may leave references to dependency IDs in the compiled code (see URL dependencies in the Transformer docs). Packagers should replace these references with the URL of the generated bundle. This can be done using the replaceURLReferences
function in @parcel/utils
.
import {Packager} from '@parcel/plugin';
import {replaceURLReferences} from '@parcel/utils';
export default new Packager({
async package({bundle, bundleGraph}) {
// ...
({contents, map} = replaceURLReferences({
bundle,
bundleGraph,
contents,
map
}));
return {contents, map};
}
});
Bundle inlining
#Parcel supports inlining the contents of one bundle within another. For example, the compiled contents of a CSS bundle could be inlined as a string within a JavaScript bundle. See Bundle inlining for details.
Bundle inlining is implemented in Packager plugins. A getInlineBundleContents
function is passed to Packagers, which can be called to retrieve the contents of an inline bundle.
Transformer plugins may leave references to dependency IDs in the compiled code (see URL dependencies in the Transformer docs). If these end up referring to an inline bundle, they should be replaced with that bundle's contents. This can be done using the replaceInlineReferences
function in @parcel/utils
.
import {Packager} from '@parcel/plugin';
import {replaceInlineReferences} from '@parcel/utils';
export default new Packager({
async package({bundle, bundleGraph, getInlineBundleContents}) {
// ...
({contents, map} = replaceInlineReferences({
bundle,
bundleGraph,
contents,
map,
getInlineBundleContents,
getInlineReplacement: (dependency, inlineType, contents) => ({
from: dependency.id,
to: contents
})
}));
return {contents, map};
}
});
Relevant API
#SymbolResolution parcel/packages/core/types/index.js:1184
Specifies a symbol in an asset
type SymbolResolution = {|
+asset: Asset,
The Asset which exports the symbol.
+exportSymbol: Symbol | string,
under which name the symbol is exported
+symbol: void | null | false | Symbol,
The identifier under which the symbol can be referenced.
+loc: ?SourceLocation,
The location of the specifier that lead to this result.
|}
Referenced by:
BundleGraph, ExportSymbolResolutionExportSymbolResolution parcel/packages/core/types/index.js:1198
type ExportSymbolResolution = {|
...SymbolResolution,
+exportAs: Symbol | string,
|}
Referenced by:
BundleGraphPackager parcel/packages/core/types/index.js:1584
type Packager<ConfigType> = {|
loadConfig?: ({|
config: Config,
options: PluginOptions,
logger: PluginLogger,
|}) => Promise<ConfigType> | ConfigType,
package({|
bundle: NamedBundle,
bundleGraph: BundleGraph<NamedBundle>,
options: PluginOptions,
logger: PluginLogger,
config: ConfigType,
getInlineBundleContents: (Bundle, BundleGraph<NamedBundle>) => Async<{|
contents: Blob
|}>,
getSourceMapReference: (map: ?SourceMap) => Async<?string>,
|}): Async<BundleResult>,
|}