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 Resolver plugin enables custom module resolution logic for import and require statements. Resolvers determine how module specifiers are resolved to actual file paths and provide the foundation for custom module systems.
Base class for creating module resolution plugins.
/**
* Base class for module resolution plugins
* @template T - Configuration type for this resolver
*/
export declare class Resolver<T> {
constructor(opts: ResolverOpts<T>);
}
/**
* Resolver plugin configuration interface
* @template ConfigType - Type of configuration returned by loadConfig
*/
interface ResolverOpts<ConfigType> {
/** Load configuration for this resolver */
loadConfig?: (args: {
config: Config;
options: PluginOptions;
logger: PluginLogger;
tracer: PluginTracer;
}) => Promise<ConfigType> | ConfigType;
/** Resolve a module specifier to a file path (required) */
resolve(args: {
dependency: Dependency;
options: PluginOptions;
logger: PluginLogger;
tracer: PluginTracer;
specifier: FilePath;
pipeline?: string;
config: ConfigType;
}): Promise<ResolveResult | null>;
}Usage Example:
import { Resolver } from "@parcel/plugin";
import path from "path";
export default new Resolver({
// Load resolver configuration
loadConfig({config}) {
return config.getConfigFrom(/* config path */);
},
// Main resolution logic (required)
async resolve({dependency, specifier, options, logger}) {
// Handle different types of specifiers
if (specifier.startsWith('~')) {
// Resolve from node_modules
const modulePath = specifier.slice(1);
const resolved = path.resolve(options.projectRoot, 'node_modules', modulePath);
return {
filePath: resolved,
sideEffects: false
};
}
if (specifier.startsWith('./') || specifier.startsWith('../')) {
// Relative path resolution
const fromDir = path.dirname(dependency.sourcePath);
const resolved = path.resolve(fromDir, specifier);
return {
filePath: resolved,
sideEffects: true
};
}
// Return null to let other resolvers handle this
return null;
}
});/**
* Result from a module resolution operation
*/
interface ResolveResult {
/** Resolved file path */
filePath: FilePath;
/** Whether this module has side effects */
sideEffects?: boolean;
/** Module resolution priority */
priority?: ResolvePriority;
/** Whether this is an excluded dependency */
isExcluded?: boolean;
/** Code to inline instead of resolving */
code?: string;
/** Query parameters for the resolved module */
query?: URLSearchParams;
/** Pipeline to use for processing this module */
pipeline?: string;
/** Environment for this module */
env?: EnvironmentOptions;
/** Module metadata */
meta?: Record<string, any>;
/** Symbol exports from this module */
symbols?: Map<Symbol, SymbolResolution>;
}
/**
* Resolution priority levels
*/
type ResolvePriority = "sync" | "parallel" | "lazy";/**
* Dependency being resolved
*/
interface Dependency {
/** Module specifier to resolve */
specifier: string;
/** Source file path containing this dependency */
sourcePath: FilePath;
/** Source location of the dependency */
loc?: SourceLocation;
/** Import type */
specifierType: SpecifierType;
/** Whether this is an optional dependency */
isOptional?: boolean;
/** Whether this dependency is async */
isAsync?: boolean;
/** Dependency priority */
priority?: DependencyPriority;
/** Bundle behavior for this dependency */
bundleBehavior?: BundleBehavior;
/** Environment for this dependency */
env?: EnvironmentOptions;
/** Dependency metadata */
meta?: Record<string, any>;
/** Pipeline to use for this dependency */
pipeline?: string;
/** Symbols imported from this dependency */
symbols?: Map<Symbol, SymbolResolution>;
}
/**
* Types of module specifiers
*/
type SpecifierType =
| "commonjs"
| "esm"
| "url"
| "relative"
| "absolute";
/**
* Dependency loading priority
*/
type DependencyPriority = "sync" | "parallel" | "lazy";
/**
* Bundle inclusion behavior
*/
type BundleBehavior =
| "inline"
| "isolated";/**
* Location information in source code
*/
interface SourceLocation {
/** Source file path */
filePath: FilePath;
/** Start position */
start: Position;
/** End position */
end: Position;
}
/**
* Position in source code
*/
interface Position {
/** Line number (1-based) */
line: number;
/** Column number (0-based) */
column: number;
}Package Resolution:
// Resolve from node_modules
if (!specifier.startsWith('.')) {
const packagePath = await options.packageManager.resolve(specifier, fromPath);
return { filePath: packagePath };
}Alias Resolution:
// Handle path aliases
const aliases = config.aliases || {};
for (const [alias, target] of Object.entries(aliases)) {
if (specifier.startsWith(alias)) {
const resolved = specifier.replace(alias, target);
return { filePath: path.resolve(options.projectRoot, resolved) };
}
}Extension Resolution:
// Try different file extensions
const extensions = ['.js', '.ts', '.jsx', '.tsx'];
for (const ext of extensions) {
const withExt = specifier + ext;
if (await options.inputFS.exists(withExt)) {
return { filePath: withExt };
}
}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