A lightning-fast frontend build tool designed to leverage JavaScript's native ESM system for unbundled development with instant browser updates.
82
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.
Core plugin interface for extending Snowpack functionality.
/**
* Main plugin interface for extending Snowpack
*/
interface SnowpackPlugin {
/** Unique plugin name */
name: string;
/** File resolution configuration */
resolve?: {
/** Input file extensions this plugin handles */
input: string[];
/** Output file extensions this plugin produces */
output: string[];
};
/** Load and process files matching resolve.input */
load?(options: PluginLoadOptions): Promise<PluginLoadResult | string | null | undefined | void>;
/** Transform files matching resolve.input */
transform?(options: PluginTransformOptions): Promise<PluginTransformResult | string | null | undefined | void>;
/** Run commands unrelated to file building */
run?(options: PluginRunOptions): Promise<unknown>;
/** Optimize the entire built application */
optimize?(options: PluginOptimizeOptions): Promise<void>;
/** Cleanup long-running instances before exit */
cleanup?(): void | Promise<void>;
/** Known entry points that should be installed */
knownEntrypoints?: string[];
/** Read and modify Snowpack configuration */
config?(snowpackConfig: SnowpackConfig): void;
/** Handle file changes during development */
onChange?({filePath}: {filePath: string}): void;
/** (internal interface, not set by the user) Mark a file as changed */
markChanged?(file: string): void;
}Plugin factory function type for creating configurable plugins.
/**
* Plugin factory function for creating plugins with options
* @param snowpackConfig - Complete Snowpack configuration
* @param pluginOptions - Plugin-specific options
* @returns Plugin instance
*/
type SnowpackPluginFactory<PluginOptions = object> = (
snowpackConfig: SnowpackConfig,
pluginOptions?: PluginOptions,
) => SnowpackPlugin;// Example plugin factory
function myPlugin(snowpackConfig, pluginOptions = {}) {
return {
name: 'my-custom-plugin',
resolve: {
input: ['.custom'],
output: ['.js']
},
load(options) {
// Plugin implementation
}
};
}
// Using plugin with options
const config = createConfiguration({
plugins: [
[myPlugin, { option1: 'value1' }]
]
});Load and process files, typically converting from one format to another.
/**
* Plugin load method options
*/
interface PluginLoadOptions {
/** Absolute file path on disk */
filePath: string;
/** File extension */
fileExt: string;
/** Development mode flag */
isDev: boolean;
/** Hot module replacement enabled */
isHmrEnabled: boolean;
/** Server-side rendering mode */
isSSR: boolean;
/** File is inside a package */
isPackage: boolean;
}
/**
* Plugin load result - map of extensions to built files
*/
type PluginLoadResult = SnowpackBuildMap;
/**
* Built file structure
*/
type SnowpackBuiltFile = {
/** File contents */
code: string | Buffer;
/** Source map */
map?: string;
};
/**
* Map of file extensions to built files
*/
type SnowpackBuildMap = Record<string, SnowpackBuiltFile>;// Example load method implementation
const plugin = {
name: 'sass-plugin',
resolve: {
input: ['.scss', '.sass'],
output: ['.css']
},
async load({ filePath, isDev }) {
const sassContent = await fs.readFile(filePath, 'utf8');
const result = sass.compile(sassContent, {
sourceMap: isDev,
file: filePath
});
return {
'.css': {
code: result.css,
map: result.map
}
};
}
};Transform files that have already been loaded, modifying content or adding features.
/**
* Plugin transform method options
*/
interface PluginTransformOptions {
/** Final build file path */
id: string;
/** Original source path on disk */
srcPath: string;
/** File extension */
fileExt: string;
/** File contents to transform */
contents: string | Buffer;
/** Development mode flag */
isDev: boolean;
/** Hot module replacement enabled */
isHmrEnabled: boolean;
/** Server-side rendering mode */
isSSR: boolean;
/** File is inside a package */
isPackage: boolean;
}
/**
* Plugin transform result
*/
type PluginTransformResult = {
/** Transformed contents */
contents: string;
/** Source map */
map: string | RawSourceMap;
};
/**
* Source map interface
*/
interface RawSourceMap {
version: number;
sources: string[];
names: string[];
sourceRoot?: string;
sourcesContent?: string[];
mappings: string;
file: string;
}// Example transform method implementation
const plugin = {
name: 'minify-plugin',
async transform({ contents, id, isDev }) {
if (isDev || !id.endsWith('.js')) {
return null; // Skip in development
}
const result = await minify(contents, {
sourceMap: true,
filename: id
});
return {
contents: result.code,
map: result.map
};
}
};Execute commands or operations unrelated to individual file processing.
/**
* Plugin run method options
*/
interface PluginRunOptions {
/** Development mode flag */
isDev: boolean;
}// Example run method implementation
const plugin = {
name: 'type-check-plugin',
async run({ isDev }) {
if (!isDev) return; // Only type-check in development
const result = await execa('tsc', ['--noEmit'], {
cwd: process.cwd(),
reject: false
});
if (result.exitCode !== 0) {
console.error('TypeScript errors found:');
console.error(result.stdout);
}
}
};Optimize the entire built application for production.
/**
* Plugin optimize method options
*/
interface PluginOptimizeOptions {
/** Build output directory */
buildDirectory: string;
}// Example optimize method implementation
const plugin = {
name: 'bundle-plugin',
async optimize({ buildDirectory }) {
const bundler = new WebpackBundler({
entry: path.join(buildDirectory, 'index.js'),
output: buildDirectory
});
await bundler.run();
}
};Modify the Snowpack configuration object during initialization.
/**
* Plugin config method
* @param snowpackConfig - Snowpack configuration to modify
*/
config?(snowpackConfig: SnowpackConfig): void;// Example config method implementation
const plugin = {
name: 'auto-mount-plugin',
config(config) {
// Automatically add common mount points
if (!config.mount['src']) {
config.mount['src'] = { url: '/', static: false, resolve: true, dot: false };
}
// Add plugin-specific aliases
config.alias['@components'] = './src/components';
}
};Handle file changes during development mode.
/**
* Handle file changes during development
* @param filePath - Path of changed file
*/
onChange?({filePath}: {filePath: string}): void;// Example onChange implementation
const plugin = {
name: 'config-watch-plugin',
onChange({ filePath }) {
if (filePath.endsWith('tailwind.config.js')) {
console.log('Tailwind config changed, rebuilding CSS...');
// Trigger CSS rebuild
}
}
};// String plugin (no options)
const config = createConfiguration({
plugins: [
'@snowpack/plugin-typescript',
'@snowpack/plugin-react-refresh'
]
});
// Plugin with options
const config = createConfiguration({
plugins: [
['@snowpack/plugin-typescript', {
args: '--strict'
}],
['@snowpack/plugin-postcss', {
config: './postcss.config.js'
}]
]
});
// Function plugin
const config = createConfiguration({
plugins: [
myCustomPlugin,
[myConfigurablePlugin, { option: 'value' }]
]
});Plugins run in the order they are specified:
Snowpack includes built-in support for common file types:
function fileTypePlugin(options = {}) {
return {
name: 'file-type-plugin',
resolve: {
input: ['.custom'],
output: ['.js', '.css']
},
async load({ filePath }) {
const content = await fs.readFile(filePath, 'utf8');
const processed = processCustomFile(content, options);
return {
'.js': { code: processed.js },
'.css': { code: processed.css }
};
}
};
}function buildToolPlugin(options = {}) {
return {
name: 'build-tool-plugin',
async run({ isDev }) {
if (isDev) {
// Run in watch mode during development
await runTool(['--watch'], { background: true });
} else {
// Single run for production
await runTool(['--production']);
}
}
};
}function optimizationPlugin(options = {}) {
return {
name: 'optimization-plugin',
async optimize({ buildDirectory }) {
const files = await glob('**/*.js', { cwd: buildDirectory });
for (const file of files) {
const filePath = path.join(buildDirectory, file);
const content = await fs.readFile(filePath, 'utf8');
const optimized = await optimizeCode(content, options);
await fs.writeFile(filePath, optimized);
}
}
};
}Install with Tessl CLI
npx tessl i tessl/npm-snowpackevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10