Transformer
Transformer plugins transform a single asset to compile it, discover dependencies, or convert it to a different format. Many transformers are wrappers around other tools such as compilers and preprocessors, and are responsible for integrating them with Parcel.
Transformers can be written in JavaScript, or as native plugins in Rust, Go, or Swift. Choose a language above any example to switch the examples and API names throughout the page.
Transforming assets
#A transformer implements one method: transformtransformTransformtransform(_:options:). It receives an asset, which represents a file. The transformer reads the asset's content, along with any associated source map (see below), transforms it in some way, and sets the compiled result back on the asset.
import { Transformer } from "@parcel/plugin";
export default new Transformer({
async transform({ asset }) {
// Retrieve the asset's source code and source map.
let source = asset.getCode();
let sourceMap = asset.getMap();
// Run it through some compiler, and set the results
// on the asset.
let { code, map } = compile(source, sourceMap);
asset.setCode(code, map);
},
});
use parcel_plugin::{Asset, Diagnostic, Options, Plugin, register_plugin};
struct MyTransformer;
impl Plugin for MyTransformer {
fn new(_config: &[u8]) -> Result<Self, Diagnostic> {
Ok(MyTransformer)
}
fn transform(&self, asset: &mut Asset, _options: &Options) -> Result<(), Diagnostic> {
// Retrieve the asset's source code and source map.
let source = asset.content()?;
let source_map = asset.source_map();
// Run it through some compiler, and set the results
// on the asset.
let (code, map) = compile(&source, source_map.as_deref());
asset.set_content_with_map(code, map);
Ok(())
}
}
register_plugin!(MyTransformer);
package main
import parcel "github.com/parcel-bundler/parcel/plugin-go/v3"
type MyTransformer struct{}
func (t *MyTransformer) Transform(asset *parcel.Asset, _ *parcel.Options) error {
// Retrieve the asset's source code and source map.
source, err := asset.Content()
if err != nil {
return err
}
sourceMap := asset.SourceMap()
// Run it through some compiler, and set the results
// on the asset.
code, m := compile(source, sourceMap)
asset.SetContentWithMap(code, m)
return nil
}
func init() {
parcel.RegisterPlugin(func(config []byte) (any, error) {
return &MyTransformer{}, nil
})
}
func main() {}
import ParcelPlugin
struct MyTransformer: Transformer {
init(config: NoConfig) {}
func transform(_ asset: Asset, options: Options) async throws {
// Retrieve the asset's source code and source map.
let source = try asset.content()
let sourceMap = asset.sourceMap
// Run it through some compiler, and set the results
// on the asset.
let (code, map) = compile(source, sourceMap)
asset.setContent(code, sourceMap: map)
}
}
#parcelPlugin(MyTransformer.self)
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 transform method.
Loading configuration
#Configuration for a Transformer plugin is specified in the user's .parcelrc. JavaScript plugins receive it as the config option of the transform method, and native plugins receive it as JSON when they are created. See Configuration for details.
import { Transformer } from "@parcel/plugin";
export default new Transformer({
async transform({ asset, config }) {
let prefix = config?.prefix ?? "";
asset.setCode(prefix + asset.getCode());
},
});
struct MyTransformer {
prefix: String,
}
impl Plugin for MyTransformer {
fn new(config: &[u8]) -> Result<Self, Diagnostic> {
// `config` is empty if none was provided.
let prefix = if config.is_empty() {
String::new()
} else {
let config: serde_json::Value =
serde_json::from_slice(config).map_err(|e| Diagnostic::new(e.to_string()))?;
config["prefix"].as_str().unwrap_or_default().to_owned()
};
Ok(MyTransformer { prefix })
}
fn transform(&self, asset: &mut Asset, _options: &Options) -> Result<(), Diagnostic> {
asset.set_content(format!("{}{}", self.prefix, asset.content()?));
Ok(())
}
}
type MyTransformer struct {
Prefix string `json:"prefix"`
}
func (t *MyTransformer) Transform(asset *parcel.Asset, _ *parcel.Options) error {
content, err := asset.Content()
if err != nil {
return err
}
asset.SetContent(t.Prefix + content)
return nil
}
func init() {
parcel.RegisterPlugin(func(config []byte) (any, error) {
t := &MyTransformer{}
// `config` is empty if none was provided.
if len(config) > 0 {
if err := json.Unmarshal(config, t); err != nil {
return nil, err
}
}
return t, nil
})
}
struct MyTransformer: Transformer {
// Decoded from the plugin's config using JSONDecoder.
struct Config: Decodable {
var prefix: String?
}
let prefix: String
init(config: Config) {
prefix = config.prefix ?? ""
}
func transform(_ asset: Asset, options: Options) async throws {
asset.setContent(prefix + (try asset.content()))
}
}
Note: Parcel rebuilds an asset when a file its transformer read changes. Files that JavaScript plugins read with the fs module (e.g. a config file loaded by the compiler it wraps) are tracked automatically. Native plugins must read files through the Options object instead (see File system). Use resolve()asset.resolve()asset.Resolve()asset.resolve(_:from:) to resolve other files the same way Parcel resolves dependencies. See Invalidation for details.
Changing the asset type
#Transformers may transform an asset from one format to another, for example from TypeScript to JavaScript. To do this, set the asset's type to the new file type (e.g. js) with asset.typeasset.set_type()asset.SetType()asset.type. The asset will then be processed by the pipeline matching the new type. See Transformers in the Parcel configuration docs for details.
import {Transformer} from '@parcel/plugin';
export default new Transformer({
async transform({asset}) {
let code = asset.getCode();
let result = compile(code);
asset.type = 'js';
asset.setCode(result);
}
});
impl Plugin for MyTransformer {
fn transform(&self, asset: &mut Asset, _options: &Options) -> Result<(), Diagnostic> {
let code = asset.content()?;
let result = compile(&code);
asset.set_type("js");
asset.set_content(result);
Ok(())
}
}
func (t *MyTransformer) Transform(asset *parcel.Asset, _ *parcel.Options) error {
code, err := asset.Content()
if err != nil {
return err
}
result := compile(code)
asset.SetType("js")
asset.SetContent(result)
return nil
}
struct MyTransformer: Transformer {
func transform(_ asset: Asset, options: Options) async throws {
let code = try asset.content()
let result = compile(code)
asset.type = "js"
asset.setContent(result)
}
}
The environment
#Assets are associated with a target, available as asset.targetasset.target()asset.Target()asset.target, which describes the environment the asset should be compiled for. The same asset may be processed multiple times with different targets, for example, when building for both browsers and Node. If possible, Transformer plugins should take the target into account when compiling code to ensure that the result works in and is optimized for the target. See Targets for details.
import {Transformer} from '@parcel/plugin';
export default new Transformer({
async transform({asset}) {
let code = asset.getCode();
let result = asset.target.isBrowser()
? compileForBrowser(code, asset.target.engines.browsers)
: compileForNode(code, asset.target.engines.node);
asset.setCode(result);
}
});
impl Plugin for MyTransformer {
fn transform(&self, asset: &mut Asset, _options: &Options) -> Result<(), Diagnostic> {
let code = asset.content()?;
let target = asset.target();
let result = match target.environment() {
Environment::Node => compile_for_node(&code, target.engines().node),
_ => compile_for_browser(&code, target.engines().browsers),
};
asset.set_content(result);
Ok(())
}
}
func (t *MyTransformer) Transform(asset *parcel.Asset, _ *parcel.Options) error {
code, err := asset.Content()
if err != nil {
return err
}
target := asset.Target()
var result string
if target.Environment() == parcel.EnvironmentNode {
result = compileForNode(code, target.Engines().Node)
} else {
result = compileForBrowser(code, target.Engines().Browsers)
}
asset.SetContent(result)
return nil
}
struct MyTransformer: Transformer {
func transform(_ asset: Asset, options: Options) async throws {
let code = try asset.content()
let target = asset.target
let result = target.environment == .node
? compileForNode(code, target.engines.node)
: compileForBrowser(code, target.engines.browsers)
asset.setContent(result)
}
}
In JavaScript, see the Target API docs for details on the available properties. In native plugins, the target provides the environment, output format, source type, engines, public URL, and dist directory. JavaScript plugins receive the target's browsers as a browserslist query, while native plugins receive the minimum version of each browser that the query resolves to.
Adding dependencies
#In addition to transforming the contents of an asset, Transformer plugins are also responsible for discovering dependencies in the code so that they may also be processed by Parcel. Some transformers don’t need to worry about this, because another transformer will run afterward and do it (e.g. the default JavaScript transformer). If you’re adding support for a new language that doesn’t compile to one of the existing languages supported by Parcel, or otherwise introduces dependencies outside the compiled code, you’ll need to add them to the asset.
Dependencies can be added to an asset using asset.addDependency()asset.add_dependency()asset.AddDependency()asset.addDependency(). The only required option is the specifier, which is a string describing the location of the dependency. The specifier type describes how the specifier should be interpreted, and defaults to ESM. See Dependency resolution for details.
import {Transformer} from '@parcel/plugin';
export default new Transformer({
async transform({asset}) {
let code = asset.getCode();
let deps = code.matchAll(/import "(.*?)"/g);
for (let [, specifier] of deps) {
asset.addDependency({
specifier,
specifierType: 'esm'
});
}
}
});
impl Plugin for MyTransformer {
fn transform(&self, asset: &mut Asset, _options: &Options) -> Result<(), Diagnostic> {
let code = asset.content()?;
let deps = Regex::new(r#"import "(.*?)""#).unwrap();
for (_, [specifier]) in deps.captures_iter(&code).map(|c| c.extract()) {
asset.add_dependency(
DependencyOptions::new(specifier).specifier_type(SpecifierType::Esm),
)?;
}
Ok(())
}
}
var deps = regexp.MustCompile(`import "(.*?)"`)
func (t *MyTransformer) Transform(asset *parcel.Asset, _ *parcel.Options) error {
code, err := asset.Content()
if err != nil {
return err
}
for _, match := range deps.FindAllStringSubmatch(code, -1) {
err := asset.AddDependency(parcel.DependencyOptions{
Specifier: match[1],
SpecifierType: parcel.SpecifierTypeESM,
})
if err != nil {
return err
}
}
return nil
}
struct MyTransformer: Transformer {
func transform(_ asset: Asset, options: Options) async throws {
let code = try asset.content()
for match in code.matches(of: /import "(.*?)"/) {
try asset.addDependency(String(match.1), specifierType: .esm)
}
}
}
Influencing bundling
#The way a dependency is specified can influence how it is bundled. By default, dependencies are bundled together into the same output file. The priority of a dependency can specify that it should be loaded lazily or in parallel with the asset that depends on it. For example, dynamic import() in JavaScript loads dependencies with lazy priority. See Code splitting.
The bundle behavior further controls how a dependency is bundled. For example, dependencies may be separated into a new bundle but inlined into the parent by setting the bundle behavior to inline. See Bundle inlining.
See DependencyOptions for more details on each of the available options.
URL dependencies
#In some languages, dependencies reference other files by URL. In the compiled code, these URL references will need to be updated to point to the final bundle names. However, when an asset is being transformed, bundle names will not yet be known. Placeholders solve this, but they are currently only supported in JavaScript plugins.
addDependency returns a unique placeholder string for the dependency. This can be placed in the transformed asset content as a placeholder for the final bundle URL, and it will be replaced later during packaging once the URL is known.
As a shortcut, the addURLDependency method creates a dependency with specifierType and importType set to url, and priority set to lazy (to create a separate bundle).
import {Transformer} from '@parcel/plugin';
export default new Transformer({
async transform({asset}) {
let code = asset.getCode();
let result = code.replace(/import "(.*?)"/g, (m, dep) => {
// Replace the original specifier with a placeholder.
// This will be replaced later with the final
// bundle URL.
let placeholder = asset.addURLDependency(dep);
return `import "${placeholder}"`;
});
asset.setCode(result);
}
});
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. Transformer plugins should add a source map to assets when transforming their content if possible. Since assets may be processed by multiple Transformers, you should also transform the existing source map included with the asset in addition to its content.
Source maps are passed to and from plugins as JSON in the standard source map format (version 3), so they can usually be passed to and from other tools directly. JavaScript plugins receive them as plain objects, and native plugins as JSON strings. asset.getMap()asset.source_map()asset.SourceMap()asset.sourceMap returns the asset's current source map, or nothing if it doesn't have one, and asset.setCode(code, map)asset.set_content_with_map()asset.SetContentWithMap()asset.setContent(_:sourceMap:) sets new content along with a source map. See Source Maps for more details.
import { Transformer } from "@parcel/plugin";
export default new Transformer({
async transform({ asset }) {
let source = asset.getCode();
let sourceMap = asset.getMap();
// Pass the input source map to the compiler, and set
// the returned source map on the asset.
let result = compile(source, sourceMap);
asset.setCode(result.code, result.map);
},
});
impl Plugin for MyTransformer {
fn transform(&self, asset: &mut Asset, _options: &Options) -> Result<(), Diagnostic> {
let source = asset.content()?;
let source_map = asset.source_map();
// Pass the input source map to the compiler, and set
// the returned source map on the asset.
let result = compile(&source, source_map.as_deref());
asset.set_content_with_map(result.code, result.map);
Ok(())
}
}
func (t *MyTransformer) Transform(asset *parcel.Asset, _ *parcel.Options) error {
source, err := asset.Content()
if err != nil {
return err
}
sourceMap := asset.SourceMap()
// Pass the input source map to the compiler, and set
// the returned source map on the asset.
result := compile(source, sourceMap)
asset.SetContentWithMap(result.Code, result.Map)
return nil
}
struct MyTransformer: Transformer {
func transform(_ asset: Asset, options: Options) async throws {
let source = try asset.content()
let sourceMap = asset.sourceMap
// Pass the input source map to the compiler, and set
// the returned source map on the asset.
let result = compile(source, sourceMap)
asset.setContent(result.code, sourceMap: result.map)
}
}
Binary data
#In addition to textual source code, Transformers can handle binary content. asset.getBuffer()asset.content_bytes()asset.ContentBytes()asset.contentBytes() returns the contents of the asset as bytes, and asset.setBuffer()asset.set_content_bytes()asset.SetContentBytes()asset.setContent(_:) replaces them. In JavaScript, bytes are represented as a Uint8Array (or a Buffer).
import {Transformer} from '@parcel/plugin';
export default new Transformer({
async transform({asset}) {
let buffer = asset.getBuffer();
let result = transform(buffer);
asset.setBuffer(result);
}
});
impl Plugin for MyTransformer {
fn transform(&self, asset: &mut Asset, _options: &Options) -> Result<(), Diagnostic> {
let buffer = asset.content_bytes()?;
let result = transform(&buffer);
asset.set_content_bytes(&result);
Ok(())
}
}
func (t *MyTransformer) Transform(asset *parcel.Asset, _ *parcel.Options) error {
buffer, err := asset.ContentBytes()
if err != nil {
return err
}
result := transform(buffer)
asset.SetContentBytes(result)
return nil
}
struct MyTransformer: Transformer {
func transform(_ asset: Asset, options: Options) async throws {
let buffer = try asset.contentBytes()
let result = transform(buffer)
asset.setContent(result)
}
}
Query parameters
#An asset may be referenced by a dependency with query parameters. These specify options for the transformer to use when compiling or transforming the asset. For example, the Parcel image transformer uses query parameters to allow users to specify the width, height, and format to convert images to. The same asset may be compiled multiple times with different query parameters. Read the query from asset.urlasset.query()asset.Query()asset.query. In JavaScript, it is part of the asset's URL. Native plugins receive it as a string, without the leading ?.
import {Transformer} from '@parcel/plugin';
export default new Transformer({
async transform({asset}) {
let query = new URL(asset.url).searchParams;
let buffer = asset.getBuffer();
let result = resize(
buffer,
query.get('width'),
query.get('height')
);
asset.setBuffer(result);
}
});
impl Plugin for MyTransformer {
fn transform(&self, asset: &mut Asset, _options: &Options) -> Result<(), Diagnostic> {
let query: HashMap<_, _> = form_urlencoded::parse(asset.query().as_bytes()).collect();
let buffer = asset.content_bytes()?;
let result = resize(
&buffer,
query.get("width"),
query.get("height"),
);
asset.set_content_bytes(&result);
Ok(())
}
}
func (t *MyTransformer) Transform(asset *parcel.Asset, _ *parcel.Options) error {
query, err := url.ParseQuery(asset.Query())
if err != nil {
return err
}
buffer, err := asset.ContentBytes()
if err != nil {
return err
}
result := resize(
buffer,
query.Get("width"),
query.Get("height"),
)
asset.SetContentBytes(result)
return nil
}
struct MyTransformer: Transformer {
func transform(_ asset: Asset, options: Options) async throws {
let query = URLComponents(string: "?" + asset.query)?.queryItems ?? []
let buffer = try asset.contentBytes()
let result = resize(
buffer,
width: query.first { $0.name == "width" }?.value,
height: query.first { $0.name == "height" }?.value
)
asset.setContent(result)
}
}
Custom content
#Normally, an asset's content is a string or bytes. Native transformers can also store a custom value as the content of an asset, e.g. an AST, using asset.set_custom_content()asset.SetCustomContent()asset.setCustomContent(_:). This avoids converting the value back to code after each transformer, and lets the plugin control how the asset is packaged into a bundle. Custom content is not supported in JavaScript plugins.
The value must implement AssetContent, which has:
- A stable type id, unique to the plugin. Parcel uses it to group assets when packaging, and includes it in bundle ids, so it must not change between builds. In Go, the id is derived from the name of the type, or from its
ContentTypeNamemethod if it has one. - A
readReadread()method, which returns the content as a string or bytes when Parcel or another plugin needs it before packaging. - A
packagePackagepackage(_:in:options:)method, which is called to produce the final contents of a bundle that contains the asset. It receives the bundle graph and the bundle, so it can find the other assets in the bundle and the bundles they reference.
use parcel_plugin::{AssetContent, Bundle, BundleGraph, ContentBuffer, Diagnostic, Options};
struct MyContent {
ast: Ast,
}
impl AssetContent for MyContent {
const TYPE_ID: [u8; 16] = parcel_plugin::type_id!("MyContent");
fn read(&self) -> Result<ContentBuffer, Diagnostic> {
Ok(ContentBuffer::String(self.ast.to_code()))
}
fn package(
&self,
bundle_graph: &BundleGraph,
bundle: &Bundle,
_options: &Options,
) -> Result<ContentBuffer, Diagnostic> {
// Generate the final code, e.g. using the bundle graph
// to find the bundles it references.
Ok(ContentBuffer::String(self.ast.generate(bundle_graph, bundle)))
}
}
impl Plugin for MyTransformer {
fn transform(&self, asset: &mut Asset, _options: &Options) -> Result<(), Diagnostic> {
let ast = parse(&asset.content()?);
asset.set_custom_content(MyContent { ast });
Ok(())
}
}
type MyContent struct {
AST *AST
}
func (c *MyContent) Read() (parcel.Content, error) {
return parcel.StringContent(c.AST.ToCode()), nil
}
func (c *MyContent) Package(bundleGraph *parcel.BundleGraph, bundle *parcel.Bundle, _ *parcel.Options) (parcel.Content, error) {
// Generate the final code, e.g. using the bundle graph
// to find the bundles it references.
return parcel.StringContent(c.AST.Generate(bundleGraph, bundle)), nil
}
func (t *MyTransformer) Transform(asset *parcel.Asset, _ *parcel.Options) error {
content, err := asset.Content()
if err != nil {
return err
}
asset.SetCustomContent(&MyContent{AST: parse(content)})
return nil
}
struct MyContent: AssetContent {
static let contentTypeID = ContentTypeID("MyContent")
var ast: AST
func read() async throws -> Content {
.string(ast.toCode())
}
func package(_ bundle: OutputBundle, in bundleGraph: BundleGraph, options: Options) async throws
-> Content
{
// Generate the final code, e.g. using the bundle graph
// to find the bundles it references.
.string(ast.generate(bundleGraph, bundle))
}
}
struct MyTransformer: Transformer {
func transform(_ asset: Asset, options: Options) async throws {
asset.setCustomContent(MyContent(ast: parse(try asset.content())))
}
}
Later transformers, and the packagePackagepackage(_:in:options:) method of other assets in the bundle graph, can access the value with custom_content::<T>()CustomContent()customContent(as:). Reading the asset's content as a string or bytes calls readReadread() instead.
See the custom content example for Rust, Go, or Swift for more details.
Relevant API
#The API reference below covers JavaScript plugins. For native plugins, see the Rust, Go, and Swift SDKs.
DependencyOptions packages-v3/plugin/src/types.ts:257
Used when creating a Dependency, see that.
type DependencyOptions = {
readonly specifier: DependencySpecifier;
The specifier used to resolve the dependency.
readonly specifierType?: SpecifierType | null;
How the specifier should be interpreted.
- esm: An ES module specifier. It is parsed as a URL, but bare specifiers are treated as node_modules.
- commonjs: A CommonJS specifier. It is not parsed as a URL.
- url: A URL that works as in a browser. Bare specifiers are treated as relative URLs.
- custom: A custom specifier. Must be handled by a custom resolver plugin.
Default value: 'esm'
readonly priority?: DependencyPriority | null;
When the dependency should be loaded.
- sync: The dependency should be resolvable synchronously. The resolved asset will be placed in the same bundle as the parent, or another bundle that's already on the page.
- parallel: The dependency should be placed in a separate bundle that's loaded in parallel with the current bundle.
- lazy: The dependency should be placed in a separate bundle that's loaded later.
Default value: 'sync'
readonly bundleBehavior?: BundleBehavior | 'none' | null;
Controls the behavior of the bundle the resolved asset is placed into. Use in combination with priority
to determine when the bundle is loaded.
- inline: The resolved asset will be placed into a new inline bundle. Inline bundles are not written to a separate file, but embedded into the parent bundle.
- isolated: The resolved asset will be isolated from its parents in a separate bundle. Shared assets will be duplicated.
readonly importType?: ImportType | null;
How the resolved asset is used by the importing asset.
Default value: 'javascript'
readonly needsStableName?: boolean | null;
When the dependency is a bundle entry (priority is "parallel" or "lazy"), this controls the naming
of that bundle. needsStableName indicates that the name should be stable over time, even when the
content of the bundle changes. This is useful for entries that a user would manually enter the URL
for, as well as for things like service workers or RSS feeds, where the URL must remain consistent
over time.
readonly isOptional?: boolean | null;
Whether the dependency is optional. If the dependency cannot be resolved, this will not fail the build.
readonly isEntry?: boolean | null;
Whether the dependency is an entry.
readonly sideEffects?: boolean | null;
Whether the dependency has side effects.
readonly loc?: {
readonly filePath?: string | null;
readonly start: Location;
readonly end: Location;
} | null;
The location within the source file where the dependency was found.
filePath may be an absolute path or a URL, and defaults to the asset's.
readonly target?: Target | null;
The target to resolve the dependency in. Must be a Target obtained from Parcel, e.g. from an asset or dependency. Defaults to the asset's target.
readonly packageConditions?: Array<PackageCondition> | null;
A list of package.json "exports" and "imports" conditions to use when resolving the dependency. An unsupported condition throws.
readonly pipeline?: string | null;
The pipeline defined in .parcelrc that the dependency should be processed with.
readonly resolveFrom?: string | null;
The absolute file path or URL where the dependency should be resolved from. By default, this is the source file where the dependency was specified.
readonly range?: SemverRange | null;
The semver version range expected for the dependency.
}
Referenced by:
MutableAssetDependency packages-v3/plugin/src/types.ts:357
A Dependency denotes a connection between two assets (likely some effect from the importee is expected - be it a side effect or a value is being imported).
interface Dependency {
readonly specifier: DependencySpecifier;
The specifier used to resolve the dependency.
readonly specifierType: SpecifierType;
How the specifier should be interpreted.
- esm: An ES module specifier. It is parsed as a URL, but bare specifiers are treated as node_modules.
- commonjs: A CommonJS specifier. It is not parsed as a URL.
- url: A URL that works as in a browser. Bare specifiers are treated as relative URLs.
- custom: A custom specifier. Must be handled by a custom resolver plugin.
readonly priority: DependencyPriority;
When the dependency should be loaded.
- sync: The dependency should be resolvable synchronously. The resolved asset will be placed in the same bundle as the parent, or another bundle that's already on the page.
- parallel: The dependency should be placed in a separate bundle that's loaded in parallel with the current bundle.
- lazy: The dependency should be placed in a separate bundle that's loaded later.
readonly bundleBehavior: BundleBehavior | undefined;
Controls the behavior of the bundle the resolved asset is placed into. Use in combination with priority
to determine when the bundle is loaded.
- inline: The resolved asset will be placed into a new inline bundle. Inline bundles are not written to a separate file, but embedded into the parent bundle.
- isolated: The resolved asset will be isolated from its parents in a separate bundle. Shared assets will be duplicated.
readonly importType: ImportType;
How the resolved asset is used by the importing asset.
readonly needsStableName: boolean;
When the dependency is a bundle entry (priority is "parallel" or "lazy"), this controls the naming
of that bundle. needsStableName indicates that the name should be stable over time, even when the
content of the bundle changes. This is useful for entries that a user would manually enter the URL
for, as well as for things like service workers or RSS feeds, where the URL must remain consistent
over time.
readonly isOptional: boolean;
Whether the dependency is optional. If the dependency cannot be resolved, this will not fail the build.
readonly isEntry: boolean;
Whether the dependency is an entry.
readonly sideEffects: boolean;
Whether the dependency has side effects.
readonly loc: SourceLocation | undefined;
The location within the source file where the dependency was found.
readonly target: Target;
The target the dependency is resolved in.
readonly packageConditions: Array<PackageCondition>;
The package.json "exports" and "imports" conditions used to resolve the dependency.
readonly resolveFrom: string | undefined;
The URL the dependency is resolved from. Files on disk use file: URLs.
readonly range: SemverRange | undefined;
The semver version range expected for the dependency.
readonly placeholder: string | undefined;
A unique string that a transformer can embed in the asset's content to refer to the dependency. It is replaced with the resolved bundle URL or module id during packaging.
}
Referenced by:
Asset, BundleGraph, DependencyOptions, DependencySpecifier, ResolverAsset packages-v3/plugin/src/types.ts:442
An asset represents a file or part of a file. It may represent any data type, including source code, binary data, etc. Assets may exist in the file system or may be virtual.
Assets passed to namers, optimizers and reporters are read-only, and can only be accessed during the plugin call they were passed to.
interface Asset {
readonly url: string;
The URL of the asset, including its query. Files on disk use file: URLs.
readonly filePath: FilePath;
The file path of the asset.
readonly type: string;
The asset's type. This initially corresponds to the source file extension, but it may be changed during transformation.
readonly target: Target;
The target of the asset.
readonly isSource: boolean;
Whether this asset is part of the project, and not an external dependency (e.g. in node_modules). This indicates that transformation using the project's configuration should be applied.
readonly bundleBehavior: BundleBehavior | undefined;
Controls which bundle the asset is placed into.
- inline: The asset will be placed into a new inline bundle. Inline bundles are not written to a separate file, but embedded into the parent bundle.
- isolated: The asset will be isolated from its parents in a separate bundle. Shared assets will be duplicated.
readonly isBundleSplittable: boolean;
If the asset is used as a bundle entry, this controls whether that bundle can be split into multiple, or whether all of the dependencies must be placed in a single bundle.
readonly sideEffects: boolean;
Whether this asset can be omitted if none of its exports are being used. This is initially set by the resolver, but can be overridden by transformers.
readonly uniqueKey: string | undefined;
When a transformer returns multiple assets, it can give them unique keys to identify them. This can be used to find assets during packaging, or to create dependencies between multiple assets returned by a transformer by using the unique key as the dependency specifier.
readonly pipeline: string | undefined;
The pipeline defined in .parcelrc that the asset should be processed with.
getCode(): string;
Returns the asset contents as a string.
getBuffer(): Uint8Array;
Returns the asset contents as bytes.
getMap(): SourceMapJSON | null;
Returns a copy of the source map for the asset, if available.
getDependencies(): Array<Dependency>;
Returns a snapshot of the asset's dependencies.
}
Referenced by:
BuildSuccessEvent, Bundle, BundleGraph, MutableAsset, ResolveResultMutableAsset packages-v3/plugin/src/types.ts:512
A mutable Asset, available during transformation.
interface MutableAsset extends Asset {
type: string;
The asset's type. This initially corresponds to the source file extension, but it may be changed during transformation.
get bundleBehavior(): BundleBehavior | undefined;
set bundleBehavior(value: BundleBehavior | 'none' | null | undefined);
Controls which bundle the asset is placed into.
- inline: The asset will be placed into a new inline bundle. Inline bundles are not written to a separate file, but embedded into the parent bundle.
- isolated: The asset will be isolated from its parents in a separate bundle. Shared assets will be duplicated.
isBundleSplittable: boolean;
If the asset is used as a bundle entry, this controls whether that bundle can be split into multiple, or whether all of the dependencies must be placed in a single bundle.
Default value: true
sideEffects: boolean;
Whether this asset can be omitted if none of its exports are being used. This is initially set by the resolver, but can be overridden by transformers.
get uniqueKey(): string | undefined;
set uniqueKey(value: string | null | undefined);
When a transformer returns multiple assets, it can give them unique keys to identify them. This can be used to find assets during packaging, or to create dependencies between multiple assets returned by a transformer by using the unique key as the dependency specifier. It can only be set once.
get pipeline(): string | undefined;
set pipeline(value: string | null | undefined);
The pipeline defined in .parcelrc that the asset should be processed with.
addDependency(options: DependencyOptions): string;
Adds a dependency to the asset. Returns the dependency's placeholder, which can be embedded in the asset's content to refer to the resolved dependency.
addURLDependency(
url: string,
options?: Partial<Omit<DependencyOptions, 'specifier'>>,
): string;
Adds a url dependency to the asset. This is a shortcut for addDependency that defaults the specifierType and importType to 'url' and the priority to 'lazy'. Returns the dependency's placeholder.
setCode(code: string, map?: SourceMapJSON | null): void;
Sets the asset contents as a string, and optionally its source map.
setBuffer(buffer: Uint8Array, map?: SourceMapJSON | null): void;
Sets the asset contents as bytes, and optionally its source map.
}
Referenced by:
TransformerResolveOptions packages-v3/plugin/src/types.ts:687
type ResolveOptions = {
readonly specifierType?: SpecifierType;
How the specifier should be interpreted.
- esm: An ES module specifier. It is parsed as a URL, but bare specifiers are treated as node_modules.
- commonjs: A CommonJS specifier. It is not parsed as a URL.
- url: A URL that works as in a browser. Bare specifiers are treated as relative URLs.
- custom: A specifier only a resolver plugin knows how to interpret.
Default value: 'esm'
readonly packageConditions?: Array<string>;
A list of custom conditions to use when resolving package.json "exports" and "imports".
}
Referenced by:
ResolveFnResolveFn packages-v3/plugin/src/types.ts:708
Resolves specifier from the file from with the resolvers configured in .parcelrc, exactly as
a dependency of the asset would be, and returns the absolute path of the resolved file. Rejects
when it does not resolve to a file. Every file the resolvers read invalidates the asset.
Type
type ResolveFn = (
from: FilePath,
specifier: string,
options?: ResolveOptions,
) => Promise<FilePath>;
Referenced by:
TransformerTransformer packages-v3/plugin/src/types.ts:720
The methods for a transformer plugin.
config is the configuration given for the plugin in .parcelrc, if any.
type Transformer<ConfigType> = {
transform(args: {
asset: MutableAsset;
config: ConfigType;
resolve: ResolveFn;
options: PluginOptions;
}): Async<void>;
Transform the asset in place.
}