0
# Plugin System
1
2
Comprehensive plugin interfaces for extending Parcel's build pipeline at every stage, including transformers, resolvers, bundlers, packagers, and more.
3
4
## Capabilities
5
6
### Plugin Base Types
7
8
Core interfaces and utilities shared across all plugin types.
9
10
```typescript { .api }
11
/**
12
* Base plugin configuration provided to all plugins
13
*/
14
interface PluginOptions {
15
/** Input file system */
16
inputFS: FileSystem;
17
/** Output file system */
18
outputFS: FileSystem;
19
/** Build cache */
20
cache: Cache;
21
/** Plugin logger */
22
logger: PluginLogger;
23
/** Package manager */
24
packageManager: PackageManager;
25
/** Worker farm for parallel processing */
26
workerFarm: WorkerFarm;
27
/** Performance tracer */
28
tracer: PluginTracer;
29
/** Build mode */
30
mode: BuildMode;
31
/** Environment variables */
32
env: EnvMap;
33
/** Feature flags */
34
featureFlags: FeatureFlags;
35
/** Hot module replacement port */
36
hmrPort?: number;
37
/** Whether HMR is enabled */
38
hmrOptions?: HMROptions;
39
/** Development server options */
40
serveOptions?: ServerOptions;
41
}
42
43
/**
44
* Plugin logger interface
45
*/
46
interface PluginLogger {
47
/** Log verbose information */
48
verbose(message: string): void;
49
/** Log informational message */
50
info(message: string): void;
51
/** Log general message */
52
log(message: string): void;
53
/** Log warning message */
54
warn(message: string): void;
55
/** Log error message */
56
error(message: string): void;
57
}
58
59
/**
60
* Performance tracing interface
61
*/
62
interface PluginTracer {
63
/** Create a performance measurement */
64
createMeasurement(name: string, category?: string): TraceMeasurement;
65
}
66
67
/**
68
* Performance measurement interface
69
*/
70
interface TraceMeasurement {
71
/** End the measurement */
72
end(): void;
73
}
74
```
75
76
### Transformer Plugin
77
78
Transform assets during the build process (e.g., TypeScript to JavaScript, SCSS to CSS).
79
80
```typescript { .api }
81
/**
82
* Transformer plugin interface
83
*/
84
interface Transformer<ConfigType = any> {
85
/** Load configuration for this transformer */
86
loadConfig?(opts: {
87
config: Config;
88
options: PluginOptions;
89
}): Promise<ConfigType> | ConfigType;
90
91
/** Check if AST can be reused from previous transformation */
92
canReuseAST?(opts: {
93
ast: AST;
94
options: PluginOptions;
95
}): boolean;
96
97
/** Parse source code into AST */
98
parse?(opts: {
99
asset: MutableAsset;
100
config: ConfigType;
101
options: PluginOptions;
102
}): Promise<AST> | AST;
103
104
/** Transform the asset */
105
transform(opts: {
106
asset: MutableAsset;
107
config: ConfigType;
108
options: PluginOptions;
109
}): Promise<Array<TransformerResult>> | Array<TransformerResult>;
110
111
/** Post-process after all transformations */
112
postProcess?(opts: {
113
assets: Array<MutableAsset>;
114
config: ConfigType;
115
options: PluginOptions;
116
}): Promise<Array<TransformerResult>> | Array<TransformerResult>;
117
118
/** Generate final code from AST */
119
generate?(opts: {
120
asset: Asset;
121
ast: AST;
122
options: PluginOptions;
123
}): Promise<GenerateOutput> | GenerateOutput;
124
}
125
126
/**
127
* Transformer result type
128
*/
129
type TransformerResult = MutableAsset | Asset;
130
131
/**
132
* Code generation output
133
*/
134
interface GenerateOutput {
135
/** Generated code */
136
content: string;
137
/** Source map */
138
map?: SourceMap;
139
}
140
```
141
142
### Resolver Plugin
143
144
Resolve import specifiers to absolute file paths.
145
146
```typescript { .api }
147
/**
148
* Resolver plugin interface
149
*/
150
interface Resolver<ConfigType = any> {
151
/** Load configuration for this resolver */
152
loadConfig?(opts: {
153
config: Config;
154
options: PluginOptions;
155
}): Promise<ConfigType> | ConfigType;
156
157
/** Resolve a dependency to a file path */
158
resolve(opts: {
159
dependency: Dependency;
160
options: PluginOptions;
161
config: ConfigType;
162
specifier: DependencySpecifier;
163
pipeline: ?string;
164
}): Promise<?ResolveResult> | ?ResolveResult;
165
}
166
167
/**
168
* Resolution result
169
*/
170
interface ResolveResult {
171
/** Resolved file path */
172
filePath?: FilePath;
173
/** Asset pipeline to use */
174
pipeline?: string;
175
/** Invalidation dependencies */
176
invalidateOnFileChange?: Array<FilePath>;
177
/** Invalidation on file creation */
178
invalidateOnFileCreate?: Array<FileCreateInvalidation>;
179
/** Environment variable invalidations */
180
invalidateOnEnvChange?: Array<string>;
181
/** Side effects information */
182
sideEffects?: boolean;
183
/** Code information */
184
code?: string;
185
/** Query string */
186
query?: URLSearchParams;
187
/** Asset priority */
188
priority?: DependencyPriority;
189
}
190
```
191
192
### Bundler Plugin
193
194
Group assets into bundles for optimal loading performance.
195
196
```typescript { .api }
197
/**
198
* Bundler plugin interface
199
*/
200
interface Bundler<ConfigType = any> {
201
/** Load configuration for this bundler */
202
loadConfig?(opts: {
203
config: Config;
204
options: PluginOptions;
205
}): Promise<ConfigType> | ConfigType;
206
207
/** Create bundles from the asset graph */
208
bundle(opts: {
209
bundleGraph: MutableBundleGraph;
210
config: ConfigType;
211
options: PluginOptions;
212
}): Promise<void> | void;
213
214
/** Optimize bundles after creation */
215
optimize?(opts: {
216
bundleGraph: MutableBundleGraph;
217
config: ConfigType;
218
options: PluginOptions;
219
}): Promise<void> | void;
220
}
221
```
222
223
### Namer Plugin
224
225
Generate names for bundles and assets.
226
227
```typescript { .api }
228
/**
229
* Namer plugin interface
230
*/
231
interface Namer<ConfigType = any> {
232
/** Load configuration for this namer */
233
loadConfig?(opts: {
234
config: Config;
235
options: PluginOptions;
236
}): Promise<ConfigType> | ConfigType;
237
238
/** Generate name for a bundle */
239
name(opts: {
240
bundle: Bundle;
241
bundleGraph: BundleGraph<NamedBundle>;
242
config: ConfigType;
243
options: PluginOptions;
244
}): Promise<?string> | ?string;
245
}
246
```
247
248
### Runtime Plugin
249
250
Inject runtime code into bundles for features like hot module replacement.
251
252
```typescript { .api }
253
/**
254
* Runtime plugin interface
255
*/
256
interface Runtime<ConfigType = any> {
257
/** Load configuration for this runtime */
258
loadConfig?(opts: {
259
config: Config;
260
options: PluginOptions;
261
}): Promise<ConfigType> | ConfigType;
262
263
/** Apply runtime modifications to bundle */
264
apply(opts: {
265
bundle: NamedBundle;
266
bundleGraph: BundleGraph<NamedBundle>;
267
config: ConfigType;
268
options: PluginOptions;
269
}): Promise<void | RuntimeAsset> | void | RuntimeAsset;
270
}
271
272
/**
273
* Runtime asset for injection
274
*/
275
interface RuntimeAsset {
276
/** Runtime code */
277
code: string;
278
/** Asset type */
279
filePath: FilePath;
280
/** Environment */
281
env?: Environment;
282
/** Dependencies */
283
dependency?: Dependency;
284
}
285
```
286
287
### Packager Plugin
288
289
Package bundles into final output files.
290
291
```typescript { .api }
292
/**
293
* Packager plugin interface
294
*/
295
interface Packager<ConfigType = any, BundleConfigType = any> {
296
/** Load configuration for this packager */
297
loadConfig?(opts: {
298
config: Config;
299
options: PluginOptions;
300
}): Promise<ConfigType> | ConfigType;
301
302
/** Load bundle-specific configuration */
303
loadBundleConfig?(opts: {
304
bundle: NamedBundle;
305
bundleGraph: BundleGraph<NamedBundle>;
306
config: ConfigType;
307
options: PluginOptions;
308
}): Promise<BundleConfigType> | BundleConfigType;
309
310
/** Package the bundle */
311
package(opts: {
312
bundle: NamedBundle;
313
bundleGraph: BundleGraph<NamedBundle>;
314
getInlineBundleContents: (bundle: Bundle, bundleGraph: BundleGraph<NamedBundle>) => Promise<{contents: Blob}>;
315
getSourceMapReference: (map: ?SourceMap) => Promise<?string>;
316
config: ConfigType;
317
bundleConfig: BundleConfigType;
318
options: PluginOptions;
319
}): Promise<BundleResult> | BundleResult;
320
}
321
322
/**
323
* Bundle packaging result
324
*/
325
interface BundleResult {
326
/** Bundle contents */
327
contents: Blob;
328
/** Source map */
329
map?: SourceMap;
330
}
331
```
332
333
### Optimizer Plugin
334
335
Optimize packaged bundles (minification, compression, etc.).
336
337
```typescript { .api }
338
/**
339
* Optimizer plugin interface
340
*/
341
interface Optimizer<ConfigType = any, BundleConfigType = any> {
342
/** Load configuration for this optimizer */
343
loadConfig?(opts: {
344
config: Config;
345
options: PluginOptions;
346
}): Promise<ConfigType> | ConfigType;
347
348
/** Load bundle-specific configuration */
349
loadBundleConfig?(opts: {
350
bundle: NamedBundle;
351
bundleGraph: BundleGraph<NamedBundle>;
352
config: ConfigType;
353
options: PluginOptions;
354
}): Promise<BundleConfigType> | BundleConfigType;
355
356
/** Optimize the bundle */
357
optimize(opts: {
358
bundle: NamedBundle;
359
bundleGraph: BundleGraph<NamedBundle>;
360
contents: Blob;
361
map?: SourceMap;
362
config: ConfigType;
363
bundleConfig: BundleConfigType;
364
options: PluginOptions;
365
}): Promise<BundleResult> | BundleResult;
366
}
367
```
368
369
### Compressor Plugin
370
371
Compress optimized bundles for final output.
372
373
```typescript { .api }
374
/**
375
* Compressor plugin interface
376
*/
377
interface Compressor {
378
/** Compress bundle contents */
379
compress(opts: {
380
stream: Readable;
381
options: PluginOptions;
382
}): Promise<Readable> | Readable;
383
}
384
```
385
386
### Validator Plugin
387
388
Validate assets and report errors or warnings.
389
390
```typescript { .api }
391
/**
392
* Single-threaded validator plugin
393
*/
394
interface DedicatedThreadValidator {
395
/** Validate an asset */
396
validate(opts: {
397
asset: Asset;
398
options: PluginOptions;
399
config: any;
400
}): Promise<ValidateResult> | ValidateResult;
401
}
402
403
/**
404
* Multi-threaded validator plugin
405
*/
406
interface MultiThreadValidator {
407
/** Validate multiple assets */
408
validateAll(opts: {
409
assets: Array<Asset>;
410
options: PluginOptions;
411
config: any;
412
}): Promise<Array<ValidateResult>> | Array<ValidateResult>;
413
}
414
415
/**
416
* Validator result
417
*/
418
interface ValidateResult {
419
/** Validation warnings */
420
warnings: Array<Diagnostic>;
421
/** Validation errors */
422
errors: Array<Diagnostic>;
423
}
424
```
425
426
### Reporter Plugin
427
428
Report build events and results.
429
430
```typescript { .api }
431
/**
432
* Reporter plugin interface
433
*/
434
interface Reporter {
435
/** Report a build event */
436
report(opts: {
437
event: ReporterEvent;
438
options: PluginOptions;
439
}): Promise<void> | void;
440
}
441
442
/**
443
* Reporter event types
444
*/
445
type ReporterEvent =
446
| BuildStartEvent
447
| BuildProgressEvent
448
| BuildSuccessEvent
449
| BuildFailureEvent
450
| WatchStartEvent
451
| WatchEndEvent
452
| LogEvent
453
| ValidationEvent
454
| CacheEvent
455
| TraceEvent;
456
```
457
458
**Usage Examples:**
459
460
```typescript
461
import type { Transformer, PluginOptions, MutableAsset } from '@parcel/types';
462
463
// Implement a custom transformer
464
class MyTransformer implements Transformer {
465
async transform({ asset, options }: {
466
asset: MutableAsset;
467
options: PluginOptions;
468
}) {
469
const code = await asset.getCode();
470
471
// Transform the code
472
const transformedCode = `// Transformed by MyTransformer\n${code}`;
473
asset.setCode(transformedCode);
474
475
// Log transformation
476
options.logger.info(`Transformed ${asset.filePath}`);
477
478
return [asset];
479
}
480
}
481
482
// Implement a custom resolver
483
class MyResolver implements Resolver {
484
async resolve({ dependency, options }) {
485
if (dependency.specifier.startsWith('virtual:')) {
486
// Handle virtual modules
487
return {
488
filePath: `/virtual/${dependency.specifier.slice(8)}.js`,
489
code: `export default "Virtual module: ${dependency.specifier}";`
490
};
491
}
492
493
return null; // Let other resolvers handle it
494
}
495
}
496
497
// Implement a custom reporter
498
class MyReporter implements Reporter {
499
async report({ event, options }) {
500
if (event.type === 'buildSuccess') {
501
options.logger.info(`Build completed with ${event.bundleGraph.getBundles().length} bundles`);
502
}
503
}
504
}
505
```