Namer
Namer plugins determine the output filename for a bundle. Namers run in a pipeline until one of them returns a result. Returned file paths should be relative to the target distDir
. See Targets for details about this.
Overriding names for specific bundles
#A common use case for a Namer plugin is to override Parcel’s default naming scheme for specific bundles. Namers may return null
when they don't handle a bundle to allow the next namer in the pipeline to handle it instead. See Namers in the Parcel configuration docs for details on how this works.
This example places all png
and jpg
files into an images
folder with the same name as their original filename.
import {Namer} from '@parcel/plugin';
import path from 'path';
export default new Namer({
name({bundle}) {
if (bundle.type === 'png' || bundle.type === 'jpg') {
let filePath = bundle.getMainEntry().filePath;
return `images/${path.basename(filePath)}`;
}
// Allow the next namer to handle this bundle.
return null;
}
});
Content hashing
#Including a hash of a bundle’s contents is an important optimization for production builds that enables browsers to cache loaded files indefinitely. When the contents of a bundle changes, so does its filename, which acts as a cache invalidation mechanism. See the Content hashing docs for details about this.
At the point bundles are being named, the final contents is not yet known, so Parcel provides a hashReference
property on each Bundle
object. This is an opaque placeholder value that will later on be replaced with the actual hash when writing the final bundles. Use this in returned bundle names to include a content hash.
Make sure to check the bundle.needsStableName
property before including a hash. When this is true
, a dependency is expecting the filename of the bundle to remain consistent over time. For example, service workers require their URLs never to change, and users expect visible URLs like HTML pages to be human readable and remain consistent.
import {Namer} from '@parcel/plugin';
export default new Namer({
name({bundle}) {
let name = yourNamingFunction(bundle);
if (!bundle.needsStableName) {
name += "." + bundle.hashReference;
}
return name + "." + bundle.type;
}
});
Targets
#Namer plugins should also respect the Target
associated with a bundle. Targets allow users to configure the output filenames of entry bundles in package.json
. If a bundle is in an entry bundle group and contains the entry asset, Namer plugins should use bundle.target.distEntry
as the output filename when available.
import {Namer} from '@parcel/plugin';
export default new Namer({
name({bundle, bundleGraph}) {
let bundleGroup = bundleGraph
.getBundleGroupsContainingBundle(bundle)[0];
let isEntry = bundleGraph.isEntryBundleGroup(bundleGroup);
let bundleGroupBundles = bundleGraph
.getBundlesInBundleGroup(bundleGroup);
let mainBundle = bundleGroupBundles.find(b =>
b.getEntryAssets()
.some(a => a.id === bundleGroup.entryAssetId),
);
if (
isEntry &&
bundle.id === mainBundle.id &&
bundle.target?.distEntry
) {
return bundle.target.distEntry;
}
// ...
}
});
Loading configuration
#Loading configuration from the user’s project should be done in the loadConfig
method of a Namer plugin. See Loading configuration for details on how to do this.
Relevant API
#Namer parcel/packages/core/types/index.js:1519
type Namer<ConfigType> = {|
loadConfig?: ({|
config: Config,
options: PluginOptions,
logger: PluginLogger,
|}) => Promise<ConfigType> | ConfigType,
name({|
bundle: Bundle,
bundleGraph: BundleGraph<Bundle>,
config: ConfigType,
options: PluginOptions,
logger: PluginLogger,
|}): Async<?FilePath>,
Return a filename/-path for bundle
or nullish to leave it to the next namer plugin.
|}