A simpler static site generator with extensive templating support and plugin ecosystem.
—
File processing pipeline including passthrough copy, transforms, collections, preprocessors, linters, and output generation for comprehensive static site building workflows.
Copy static assets and files directly to output without processing.
/**
* Add files or directories to passthrough copy
* @param fileOrDir - String path or object mapping input to output
* @param copyOptions - Options for recursive copy behavior
* @returns UserConfig instance for chaining
*/
addPassthroughCopy(fileOrDir: string | Record<string, string>, copyOptions?: PassthroughCopyOptions): UserConfig;
interface PassthroughCopyOptions {
/** Copy mode for HTML-relative paths */
mode?: 'html-relative';
/** Recursive copy options */
overwrite?: boolean;
expand?: boolean;
dot?: boolean;
junk?: boolean;
filter?: string[] | Function;
rename?: Function;
transform?: Function;
}
/**
* Set server passthrough copy behavior
* @param behavior - Copy behavior during development
*/
setServerPassthroughCopyBehavior(behavior: 'copy' | 'passthrough'): void;Usage Examples:
// Basic passthrough copy
eleventyConfig.addPassthroughCopy("assets");
eleventyConfig.addPassthroughCopy("images");
// Object mapping (input -> output)
eleventyConfig.addPassthroughCopy({
"src/assets": "assets",
"src/images": "img",
"node_modules/prismjs/themes": "assets/css/prism-themes"
});
// With copy options
eleventyConfig.addPassthroughCopy("files", {
filter: ["**/*.pdf", "**/*.zip"],
overwrite: true
});
// HTML-relative mode (copies relative to HTML files)
eleventyConfig.addPassthroughCopy("*.jpg", { mode: "html-relative" });
// Configure server behavior
eleventyConfig.setServerPassthroughCopyBehavior("passthrough"); // Faster for developmentProcess final output content before writing to disk.
/**
* Add content transform
* @param name - Transform name
* @param callback - Transform function
*/
addTransform(name: string, callback: TransformFunction): void;
/**
* Transform function signature
* @param content - File content to transform
* @param outputPath - Output file path
* @returns Transformed content
*/
type TransformFunction = (content: string, outputPath: string) => string | Promise<string>;Usage Examples:
// Minify HTML
eleventyConfig.addTransform("htmlmin", (content, outputPath) => {
if (outputPath && outputPath.endsWith(".html")) {
const htmlmin = require("html-minifier");
return htmlmin.minify(content, {
useShortDoctype: true,
removeComments: true,
collapseWhitespace: true
});
}
return content;
});
// Add copyright notice
eleventyConfig.addTransform("copyright", (content, outputPath) => {
if (outputPath && outputPath.endsWith(".html")) {
const copyright = `<!-- © ${new Date().getFullYear()} My Website -->`;
return content.replace("</body>", `${copyright}\n</body>`);
}
return content;
});
// Async transform with external processing
eleventyConfig.addTransform("processImages", async (content, outputPath) => {
if (outputPath && outputPath.endsWith(".html")) {
// Process images in HTML content
return await processImagesInHtml(content);
}
return content;
});Process template content before template engine processing.
/**
* Add preprocessor for specific file types
* @param name - Preprocessor name
* @param fileExtensions - File extensions to process
* @param callback - Preprocessor function
*/
addPreprocessor(name: string, fileExtensions: string, callback: PreprocessorFunction): void;
/**
* Preprocessor function signature
* @param content - Template content
* @param inputPath - Input file path
* @returns Processed content
*/
type PreprocessorFunction = (content: string, inputPath: string) => string | Promise<string>;
interface PreprocessorConfig {
/** File extensions filter */
filter: string;
/** Preprocessor callback function */
callback: PreprocessorFunction;
}Usage Examples:
// Preprocess Sass in markdown files
eleventyConfig.addPreprocessor("sass", "md", (content, inputPath) => {
// Process Sass code blocks in markdown
return content.replace(/```sass\n([\s\S]*?)\n```/g, (match, sass) => {
const compiled = require("sass").renderSync({ data: sass }).css;
return `<style>\n${compiled}\n</style>`;
});
});
// Add TypeScript preprocessing
eleventyConfig.addPreprocessor("typescript", "ts,tsx", async (content, inputPath) => {
const ts = require("typescript");
const result = ts.transpile(content, {
target: ts.ScriptTarget.ES2020,
module: ts.ModuleKind.ESNext
});
return result;
});
// Import processing
eleventyConfig.addPreprocessor("imports", "md", (content, inputPath) => {
// Replace import statements with file contents
return content.replace(/^@import "([^"]+)"$/gm, (match, filename) => {
const fs = require("fs");
const path = require("path");
const importPath = path.resolve(path.dirname(inputPath), filename);
return fs.readFileSync(importPath, "utf8");
});
});Validate and check content quality before processing.
/**
* Add content linter
* @param name - Linter name
* @param callback - Linter function
*/
addLinter(name: string, callback: LinterFunction): void;
/**
* Linter function signature
* @param content - Content to lint
* @param inputPath - Input file path
* @param outputPath - Output file path
*/
type LinterFunction = (content: string, inputPath: string, outputPath: string) => void;Usage Examples:
// Check for TODO comments
eleventyConfig.addLinter("todos", (content, inputPath, outputPath) => {
const todos = content.match(/TODO:/g);
if (todos) {
console.warn(`Found ${todos.length} TODO comments in ${inputPath}`);
}
});
// Validate HTML
eleventyConfig.addLinter("html-validate", (content, inputPath, outputPath) => {
if (outputPath && outputPath.endsWith(".html")) {
const { HtmlValidate } = require("html-validate");
const htmlvalidate = new HtmlValidate();
const report = htmlvalidate.validateString(content);
if (!report.valid) {
console.error(`HTML validation errors in ${outputPath}:`);
report.results.forEach(result => {
result.messages.forEach(msg => {
console.error(` ${msg.line}:${msg.column} ${msg.message}`);
});
});
}
}
});
// Check accessibility
eleventyConfig.addLinter("a11y", (content, inputPath, outputPath) => {
if (outputPath && outputPath.endsWith(".html")) {
// Check for accessibility issues
const issues = [];
if (!content.includes('alt=') && content.includes('<img')) {
issues.push("Images without alt attributes found");
}
if (issues.length > 0) {
console.warn(`A11y issues in ${outputPath}: ${issues.join(", ")}`);
}
}
});Define and organize template collections for site structure.
/**
* Add template collection
* @param name - Collection name
* @param callback - Function returning collection items
*/
addCollection(name: string, callback: CollectionFunction): void;
/**
* Collection function signature
* @param collectionApi - API for accessing templates
* @returns Array of collection items
*/
type CollectionFunction = (collectionApi: CollectionApi) => CollectionItem[];
interface CollectionApi {
/** Get all templates */
getAll(): CollectionItem[];
/** Get templates with specific tag */
getFilteredByTag(tagName: string): CollectionItem[];
/** Get templates matching glob pattern */
getFilteredByGlob(glob: string): CollectionItem[];
}
interface CollectionItem {
/** Template instance */
template: any;
/** Input file path */
inputPath: string;
/** File slug (filename without extension) */
fileSlug: string;
/** Output file path */
outputPath: string;
/** Template URL */
url: string;
/** Template date */
date: Date;
/** Template data */
data: any;
}Usage Examples:
// Basic collections
eleventyConfig.addCollection("posts", (collectionApi) => {
return collectionApi.getFilteredByGlob("./src/posts/*.md");
});
eleventyConfig.addCollection("pages", (collectionApi) => {
return collectionApi.getFilteredByTag("page");
});
// Advanced collections with processing
eleventyConfig.addCollection("recentPosts", (collectionApi) => {
return collectionApi
.getFilteredByTag("post")
.filter(item => !item.data.draft)
.sort((a, b) => b.date - a.date)
.slice(0, 5);
});
// Grouped collections
eleventyConfig.addCollection("postsByYear", (collectionApi) => {
const posts = collectionApi.getFilteredByTag("post");
const grouped = {};
posts.forEach(post => {
const year = post.date.getFullYear();
if (!grouped[year]) grouped[year] = [];
grouped[year].push(post);
});
return grouped;
});
// Tagged collections with metadata
eleventyConfig.addCollection("featured", (collectionApi) => {
return collectionApi
.getAll()
.filter(item => item.data.featured)
.map(item => ({
...item,
excerpt: item.data.content ? item.data.content.slice(0, 200) + "..." : ""
}));
});Transform URLs during the build process.
/**
* Add URL transform function
* @param callback - URL transformation function
*/
addUrlTransform(callback: UrlTransformFunction): void;
/**
* URL transform function signature
* @param url - URL to transform
* @param outputPath - Output file path
* @returns Transformed URL
*/
type UrlTransformFunction = (url: string, outputPath: string) => string;Usage Examples:
// Add trailing slashes
eleventyConfig.addUrlTransform((url, outputPath) => {
if (url !== "/" && !url.endsWith("/") && !url.includes(".")) {
return url + "/";
}
return url;
});
// Localize URLs based on output path
eleventyConfig.addUrlTransform((url, outputPath) => {
if (outputPath.includes("/es/")) {
return `/es${url}`;
}
if (outputPath.includes("/fr/")) {
return `/fr${url}`;
}
return url;
});
// CDN transforms for assets
eleventyConfig.addUrlTransform((url, outputPath) => {
if (url.startsWith("/images/") || url.startsWith("/assets/")) {
return `https://cdn.example.com${url}`;
}
return url;
});Configure the build pipeline behavior.
/**
* Configure error reporting
* @param options - Error reporting options
*/
configureErrorReporting(options?: ErrorReportingOptions): void;
/**
* Configure template handling
* @param options - Template handling options
*/
configureTemplateHandling(options?: TemplateHandlingOptions): void;
interface ErrorReportingOptions {
/** Allow missing file extensions */
allowMissingExtensions?: boolean;
}
interface TemplateHandlingOptions {
/** Write mode for templates */
writeMode?: 'sync' | 'async';
}
/**
* Set build concurrency
* @param number - Number of concurrent operations
*/
setConcurrency(number: number): void;
/**
* Get current build concurrency
* @returns Current concurrency setting
*/
getConcurrency(): number;Usage Examples:
// Configure error handling
eleventyConfig.configureErrorReporting({
allowMissingExtensions: true
});
// Configure template processing
eleventyConfig.configureTemplateHandling({
writeMode: "async"
});
// Set concurrency for parallel processing
eleventyConfig.setConcurrency(4); // Process 4 templates in parallelConfigure how files are written to the output directory.
/**
* Set output directory
* @param dir - Output directory path
*/
setOutputDirectory(dir: string): void;
/**
* Configure layout aliases for easier referencing
* @param from - Alias name
* @param to - Actual layout path
*/
addLayoutAlias(from: string, to: string): void;
/**
* Configure layout resolution behavior
* @param resolution - Enable/disable extension-less layout resolution
*/
setLayoutResolution(resolution: boolean): void;Usage Examples:
// Set custom output directory
eleventyConfig.setOutputDirectory("dist");
// Layout aliases
eleventyConfig.addLayoutAlias("base", "layouts/base.njk");
eleventyConfig.addLayoutAlias("post", "layouts/post.liquid");
// Layout resolution
eleventyConfig.setLayoutResolution(true); // Allow layouts without extensionsinterface PassthroughCopyOptions {
mode?: 'html-relative';
overwrite?: boolean;
expand?: boolean;
dot?: boolean;
junk?: boolean;
filter?: string[] | Function;
rename?: Function;
transform?: Function;
}
type TransformFunction = (content: string, outputPath: string) => string | Promise<string>;
type PreprocessorFunction = (content: string, inputPath: string) => string | Promise<string>;
type LinterFunction = (content: string, inputPath: string, outputPath: string) => void;
type CollectionFunction = (collectionApi: CollectionApi) => CollectionItem[];
type UrlTransformFunction = (url: string, outputPath: string) => string;
interface CollectionApi {
getAll(): CollectionItem[];
getFilteredByTag(tagName: string): CollectionItem[];
getFilteredByGlob(glob: string): CollectionItem[];
}
interface CollectionItem {
template: any;
inputPath: string;
fileSlug: string;
outputPath: string;
url: string;
date: Date;
data: any;
}
interface PreprocessorConfig {
filter: string;
callback: PreprocessorFunction;
}
interface ErrorReportingOptions {
allowMissingExtensions?: boolean;
}
interface TemplateHandlingOptions {
writeMode?: 'sync' | 'async';
}Install with Tessl CLI
npx tessl i tessl/npm-11ty--eleventy