0
# Plugin System
1
2
The Snowpack plugin system provides a powerful architecture for extending build functionality with custom file processing, transformations, optimization, and build steps. Plugins can load files, transform content, run commands, and optimize the final build output.
3
4
## Capabilities
5
6
### Plugin Interface
7
8
Core plugin interface for extending Snowpack functionality.
9
10
```typescript { .api }
11
/**
12
* Main plugin interface for extending Snowpack
13
*/
14
interface SnowpackPlugin {
15
/** Unique plugin name */
16
name: string;
17
/** File resolution configuration */
18
resolve?: {
19
/** Input file extensions this plugin handles */
20
input: string[];
21
/** Output file extensions this plugin produces */
22
output: string[];
23
};
24
/** Load and process files matching resolve.input */
25
load?(options: PluginLoadOptions): Promise<PluginLoadResult | string | null | undefined | void>;
26
/** Transform files matching resolve.input */
27
transform?(options: PluginTransformOptions): Promise<PluginTransformResult | string | null | undefined | void>;
28
/** Run commands unrelated to file building */
29
run?(options: PluginRunOptions): Promise<unknown>;
30
/** Optimize the entire built application */
31
optimize?(options: PluginOptimizeOptions): Promise<void>;
32
/** Cleanup long-running instances before exit */
33
cleanup?(): void | Promise<void>;
34
/** Known entry points that should be installed */
35
knownEntrypoints?: string[];
36
/** Read and modify Snowpack configuration */
37
config?(snowpackConfig: SnowpackConfig): void;
38
/** Handle file changes during development */
39
onChange?({filePath}: {filePath: string}): void;
40
/** (internal interface, not set by the user) Mark a file as changed */
41
markChanged?(file: string): void;
42
}
43
```
44
45
### Plugin Factory
46
47
Plugin factory function type for creating configurable plugins.
48
49
```typescript { .api }
50
/**
51
* Plugin factory function for creating plugins with options
52
* @param snowpackConfig - Complete Snowpack configuration
53
* @param pluginOptions - Plugin-specific options
54
* @returns Plugin instance
55
*/
56
type SnowpackPluginFactory<PluginOptions = object> = (
57
snowpackConfig: SnowpackConfig,
58
pluginOptions?: PluginOptions,
59
) => SnowpackPlugin;
60
```
61
62
```typescript
63
// Example plugin factory
64
function myPlugin(snowpackConfig, pluginOptions = {}) {
65
return {
66
name: 'my-custom-plugin',
67
resolve: {
68
input: ['.custom'],
69
output: ['.js']
70
},
71
load(options) {
72
// Plugin implementation
73
}
74
};
75
}
76
77
// Using plugin with options
78
const config = createConfiguration({
79
plugins: [
80
[myPlugin, { option1: 'value1' }]
81
]
82
});
83
```
84
85
## Plugin Methods
86
87
### Load Method
88
89
Load and process files, typically converting from one format to another.
90
91
```typescript { .api }
92
/**
93
* Plugin load method options
94
*/
95
interface PluginLoadOptions {
96
/** Absolute file path on disk */
97
filePath: string;
98
/** File extension */
99
fileExt: string;
100
/** Development mode flag */
101
isDev: boolean;
102
/** Hot module replacement enabled */
103
isHmrEnabled: boolean;
104
/** Server-side rendering mode */
105
isSSR: boolean;
106
/** File is inside a package */
107
isPackage: boolean;
108
}
109
110
/**
111
* Plugin load result - map of extensions to built files
112
*/
113
type PluginLoadResult = SnowpackBuildMap;
114
115
/**
116
* Built file structure
117
*/
118
type SnowpackBuiltFile = {
119
/** File contents */
120
code: string | Buffer;
121
/** Source map */
122
map?: string;
123
};
124
125
/**
126
* Map of file extensions to built files
127
*/
128
type SnowpackBuildMap = Record<string, SnowpackBuiltFile>;
129
```
130
131
```typescript
132
// Example load method implementation
133
const plugin = {
134
name: 'sass-plugin',
135
resolve: {
136
input: ['.scss', '.sass'],
137
output: ['.css']
138
},
139
async load({ filePath, isDev }) {
140
const sassContent = await fs.readFile(filePath, 'utf8');
141
const result = sass.compile(sassContent, {
142
sourceMap: isDev,
143
file: filePath
144
});
145
146
return {
147
'.css': {
148
code: result.css,
149
map: result.map
150
}
151
};
152
}
153
};
154
```
155
156
### Transform Method
157
158
Transform files that have already been loaded, modifying content or adding features.
159
160
```typescript { .api }
161
/**
162
* Plugin transform method options
163
*/
164
interface PluginTransformOptions {
165
/** Final build file path */
166
id: string;
167
/** Original source path on disk */
168
srcPath: string;
169
/** File extension */
170
fileExt: string;
171
/** File contents to transform */
172
contents: string | Buffer;
173
/** Development mode flag */
174
isDev: boolean;
175
/** Hot module replacement enabled */
176
isHmrEnabled: boolean;
177
/** Server-side rendering mode */
178
isSSR: boolean;
179
/** File is inside a package */
180
isPackage: boolean;
181
}
182
183
/**
184
* Plugin transform result
185
*/
186
type PluginTransformResult = {
187
/** Transformed contents */
188
contents: string;
189
/** Source map */
190
map: string | RawSourceMap;
191
};
192
193
/**
194
* Source map interface
195
*/
196
interface RawSourceMap {
197
version: number;
198
sources: string[];
199
names: string[];
200
sourceRoot?: string;
201
sourcesContent?: string[];
202
mappings: string;
203
file: string;
204
}
205
```
206
207
```typescript
208
// Example transform method implementation
209
const plugin = {
210
name: 'minify-plugin',
211
async transform({ contents, id, isDev }) {
212
if (isDev || !id.endsWith('.js')) {
213
return null; // Skip in development
214
}
215
216
const result = await minify(contents, {
217
sourceMap: true,
218
filename: id
219
});
220
221
return {
222
contents: result.code,
223
map: result.map
224
};
225
}
226
};
227
```
228
229
### Run Method
230
231
Execute commands or operations unrelated to individual file processing.
232
233
```typescript { .api }
234
/**
235
* Plugin run method options
236
*/
237
interface PluginRunOptions {
238
/** Development mode flag */
239
isDev: boolean;
240
}
241
```
242
243
```typescript
244
// Example run method implementation
245
const plugin = {
246
name: 'type-check-plugin',
247
async run({ isDev }) {
248
if (!isDev) return; // Only type-check in development
249
250
const result = await execa('tsc', ['--noEmit'], {
251
cwd: process.cwd(),
252
reject: false
253
});
254
255
if (result.exitCode !== 0) {
256
console.error('TypeScript errors found:');
257
console.error(result.stdout);
258
}
259
}
260
};
261
```
262
263
### Optimize Method
264
265
Optimize the entire built application for production.
266
267
```typescript { .api }
268
/**
269
* Plugin optimize method options
270
*/
271
interface PluginOptimizeOptions {
272
/** Build output directory */
273
buildDirectory: string;
274
}
275
```
276
277
```typescript
278
// Example optimize method implementation
279
const plugin = {
280
name: 'bundle-plugin',
281
async optimize({ buildDirectory }) {
282
const bundler = new WebpackBundler({
283
entry: path.join(buildDirectory, 'index.js'),
284
output: buildDirectory
285
});
286
287
await bundler.run();
288
}
289
};
290
```
291
292
### Config Method
293
294
Modify the Snowpack configuration object during initialization.
295
296
```typescript { .api }
297
/**
298
* Plugin config method
299
* @param snowpackConfig - Snowpack configuration to modify
300
*/
301
config?(snowpackConfig: SnowpackConfig): void;
302
```
303
304
```typescript
305
// Example config method implementation
306
const plugin = {
307
name: 'auto-mount-plugin',
308
config(config) {
309
// Automatically add common mount points
310
if (!config.mount['src']) {
311
config.mount['src'] = { url: '/', static: false, resolve: true, dot: false };
312
}
313
314
// Add plugin-specific aliases
315
config.alias['@components'] = './src/components';
316
}
317
};
318
```
319
320
### File Change Handling
321
322
Handle file changes during development mode.
323
324
```typescript { .api }
325
/**
326
* Handle file changes during development
327
* @param filePath - Path of changed file
328
*/
329
onChange?({filePath}: {filePath: string}): void;
330
```
331
332
```typescript
333
// Example onChange implementation
334
const plugin = {
335
name: 'config-watch-plugin',
336
onChange({ filePath }) {
337
if (filePath.endsWith('tailwind.config.js')) {
338
console.log('Tailwind config changed, rebuilding CSS...');
339
// Trigger CSS rebuild
340
}
341
}
342
};
343
```
344
345
## Plugin Configuration
346
347
### Adding Plugins
348
349
```typescript
350
// String plugin (no options)
351
const config = createConfiguration({
352
plugins: [
353
'@snowpack/plugin-typescript',
354
'@snowpack/plugin-react-refresh'
355
]
356
});
357
358
// Plugin with options
359
const config = createConfiguration({
360
plugins: [
361
['@snowpack/plugin-typescript', {
362
args: '--strict'
363
}],
364
['@snowpack/plugin-postcss', {
365
config: './postcss.config.js'
366
}]
367
]
368
});
369
370
// Function plugin
371
const config = createConfiguration({
372
plugins: [
373
myCustomPlugin,
374
[myConfigurablePlugin, { option: 'value' }]
375
]
376
});
377
```
378
379
### Plugin Order
380
381
Plugins run in the order they are specified:
382
383
1. **Config methods** - Run first to modify configuration
384
2. **Load methods** - Process files by extension matching
385
3. **Transform methods** - Transform loaded files
386
4. **Run methods** - Execute during build process
387
5. **Optimize methods** - Run during production optimization
388
6. **Cleanup methods** - Run on shutdown
389
390
## Built-in Plugins
391
392
Snowpack includes built-in support for common file types:
393
394
### JavaScript/TypeScript Processing
395
- Built-in esbuild plugin for JS/TS compilation
396
- Supports JSX transformation
397
- Source map generation
398
- Fast compilation
399
400
### CSS Processing
401
- Built-in CSS processing
402
- CSS Modules support
403
- Import resolution
404
- PostCSS integration
405
406
## Common Plugin Patterns
407
408
### File Type Plugin
409
410
```typescript
411
function fileTypePlugin(options = {}) {
412
return {
413
name: 'file-type-plugin',
414
resolve: {
415
input: ['.custom'],
416
output: ['.js', '.css']
417
},
418
async load({ filePath }) {
419
const content = await fs.readFile(filePath, 'utf8');
420
const processed = processCustomFile(content, options);
421
422
return {
423
'.js': { code: processed.js },
424
'.css': { code: processed.css }
425
};
426
}
427
};
428
}
429
```
430
431
### Build Tool Integration
432
433
```typescript
434
function buildToolPlugin(options = {}) {
435
return {
436
name: 'build-tool-plugin',
437
async run({ isDev }) {
438
if (isDev) {
439
// Run in watch mode during development
440
await runTool(['--watch'], { background: true });
441
} else {
442
// Single run for production
443
await runTool(['--production']);
444
}
445
}
446
};
447
}
448
```
449
450
### Optimization Plugin
451
452
```typescript
453
function optimizationPlugin(options = {}) {
454
return {
455
name: 'optimization-plugin',
456
async optimize({ buildDirectory }) {
457
const files = await glob('**/*.js', { cwd: buildDirectory });
458
459
for (const file of files) {
460
const filePath = path.join(buildDirectory, file);
461
const content = await fs.readFile(filePath, 'utf8');
462
const optimized = await optimizeCode(content, options);
463
await fs.writeFile(filePath, optimized);
464
}
465
}
466
};
467
}
468
```
469
470
## Plugin Lifecycle
471
472
1. **Initialization**: Plugin config methods modify Snowpack configuration
473
2. **Development**: Load, transform, and run methods process files
474
3. **File Changes**: onChange methods handle file system events
475
4. **Production**: Optimize methods run during production builds
476
5. **Shutdown**: Cleanup methods run when Snowpack exits