An extremely simple, pluggable static site generator for NodeJS
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Core build methods for processing files through the plugin pipeline and outputting results. These methods orchestrate the complete Metalsmith workflow from reading files to writing output.
Execute the complete build process: read files, process through plugins, and write to destination.
/**
* Build with current settings, outputting to destination directory
* @param callback - Optional callback for completion
* @returns Promise resolving to processed files (if no callback provided)
*/
build(callback?: BuildCallback): Promise<Files> | void;
type BuildCallback = (error: Error | null, files: Files) => void;Usage Examples:
import Metalsmith from "metalsmith";
// Promise-based build
try {
const files = await metalsmith.build();
console.log(`Built ${Object.keys(files).length} files`);
} catch (error) {
console.error('Build failed:', error);
}
// Callback-based build
metalsmith.build((error, files) => {
if (error) {
console.error('Build failed:', error);
return;
}
console.log(`Built ${Object.keys(files).length} files`);
});Process files through plugins without writing to the filesystem. Useful for in-memory processing and testing.
/**
* Process files through plugins without writing to filesystem
* @param callback - Optional callback for completion
* @returns Promise resolving to processed files (if no callback provided)
*/
process(callback?: BuildCallback): Promise<Files> | void;Usage Examples:
// Process files in memory only
const processedFiles = await metalsmith.process();
// Useful for testing or preview mode
metalsmith.process((error, files) => {
if (error) throw error;
// Files are processed but not written to disk
Object.keys(files).forEach(filepath => {
console.log(`Processed: ${filepath}`);
console.log(`Content: ${files[filepath].contents.toString()}`);
});
});Run a specific set of files through the plugin pipeline with optional custom plugin list.
/**
* Run files through plugin pipeline
* @param files - Files object to process
* @param callback - Callback for completion
*/
run(files: Files, callback: BuildCallback): void;
/**
* Run files through specific plugins
* @param files - Files object to process
* @param plugins - Array of plugins to use (defaults to instance plugins)
* @param callback - Callback for completion
*/
run(files: Files, plugins: Plugin[], callback: BuildCallback): void;
/**
* Run files through plugin pipeline (Promise version)
* @param files - Files object to process
* @param plugins - Optional array of plugins to use
* @returns Promise resolving to processed files
*/
run(files: Files, plugins?: Plugin[]): Promise<Files>;Usage Examples:
import Metalsmith from "metalsmith";
import markdown from "@metalsmith/markdown";
// Run with default plugins
const inputFiles = {
'index.md': {
contents: Buffer.from('# Hello World'),
title: 'Home Page'
}
};
const outputFiles = await metalsmith.run(inputFiles);
// Run with specific plugins only
const customPlugins = [markdown()];
const result = await metalsmith.run(inputFiles, customPlugins);
// Callback version
metalsmith.run(inputFiles, (error, files) => {
if (error) throw error;
console.log('Processed files:', Object.keys(files));
});The build pipeline follows this sequence:
Build Process Control:
// Full build with all steps
await metalsmith
.clean(true) // Clean destination first
.source('src') // Read from src/
.destination('build') // Write to build/
.build();
// Process only (skip file I/O)
await metalsmith.process(); // Only steps 3 (plugins)
// Custom processing
const files = await metalsmith.read(); // Step 2 only
const processed = await metalsmith.run(files); // Step 3 only
await metalsmith.write(processed); // Step 4 onlyBuild methods provide comprehensive error handling for all stages of processing.
// Promise error handling
try {
await metalsmith.build();
} catch (error) {
if (error.code === 'invalid_frontmatter') {
console.error('Front-matter parsing failed:', error.message);
} else if (error.code === 'failed_read') {
console.error('File reading failed:', error.message);
} else if (error.code === 'failed_write') {
console.error('File writing failed:', error.message);
} else {
console.error('Plugin error:', error.message);
}
}
// Callback error handling
metalsmith.build((error, files) => {
if (error) {
console.error('Build error:', error.message);
console.error('Stack trace:', error.stack);
return;
}
console.log('Build successful');
});Process files continuously when source files change (experimental feature).
/**
* Enable file watching for continuous rebuilds
* @param options - Watch configuration or boolean
* @returns Metalsmith instance or current watch settings
*/
watch(options?: boolean | string | string[] | WatchOptions): Metalsmith | boolean | WatchOptions;
interface WatchOptions {
/** Paths to watch (default: source directory) */
paths?: string[];
/** Wait for write operations to complete */
awaitWriteFinish?: boolean;
/** Additional chokidar options */
[key: string]: any;
}Watch Mode Examples:
// Enable watching of source directory
metalsmith
.clean(false) // Use partial rebuilds
.watch(true) // Watch source directory
.build((error, files) => {
if (error) {
console.error('Build error:', error);
return;
}
console.log(`Rebuilt ${Object.keys(files).length} files`);
});
// Watch specific directories
metalsmith
.watch(['src', 'templates'])
.process((error, files) => {
// Continuous in-memory processing
console.log('Files reprocessed');
});
// Stop watching
metalsmith.watch(false);Tips for optimizing build performance:
// Limit file concurrency to prevent resource exhaustion
metalsmith.concurrency(50);
// Use partial rebuilds in watch mode
metalsmith.clean(false);
// Enable debug logging to identify slow plugins
metalsmith.env('DEBUG', '@metalsmith/*');
// Measure build time
const startTime = performance.now();
await metalsmith.build();
const buildTime = ((performance.now() - startTime) / 1000).toFixed(1);
console.log(`Build completed in ${buildTime}s`);