CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-snowpack

A lightning-fast frontend build tool designed to leverage JavaScript's native ESM system for unbundled development with instant browser updates.

82

1.22x
Overview
Eval results
Files

plugins.mddocs/

Plugin System

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.

Capabilities

Plugin Interface

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

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' }]
  ]
});

Plugin Methods

Load Method

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 Method

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
    };
  }
};

Run Method

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 Method

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();
  }
};

Config Method

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';
  }
};

File Change Handling

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
    }
  }
};

Plugin Configuration

Adding Plugins

// 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' }]
  ]
});

Plugin Order

Plugins run in the order they are specified:

  1. Config methods - Run first to modify configuration
  2. Load methods - Process files by extension matching
  3. Transform methods - Transform loaded files
  4. Run methods - Execute during build process
  5. Optimize methods - Run during production optimization
  6. Cleanup methods - Run on shutdown

Built-in Plugins

Snowpack includes built-in support for common file types:

JavaScript/TypeScript Processing

  • Built-in esbuild plugin for JS/TS compilation
  • Supports JSX transformation
  • Source map generation
  • Fast compilation

CSS Processing

  • Built-in CSS processing
  • CSS Modules support
  • Import resolution
  • PostCSS integration

Common Plugin Patterns

File Type Plugin

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 }
      };
    }
  };
}

Build Tool Integration

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']);
      }
    }
  };
}

Optimization Plugin

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);
      }
    }
  };
}

Plugin Lifecycle

  1. Initialization: Plugin config methods modify Snowpack configuration
  2. Development: Load, transform, and run methods process files
  3. File Changes: onChange methods handle file system events
  4. Production: Optimize methods run during production builds
  5. Shutdown: Cleanup methods run when Snowpack exits

Install with Tessl CLI

npx tessl i tessl/npm-snowpack

docs

build-system.md

cli.md

configuration.md

development-server.md

index.md

plugins.md

utilities.md

tile.json