CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-11ty--eleventy

A simpler static site generator with extensive templating support and plugin ecosystem.

Pending
Overview
Eval results
Files

build-pipeline.mddocs/

Build Pipeline

File processing pipeline including passthrough copy, transforms, collections, preprocessors, linters, and output generation for comprehensive static site building workflows.

Capabilities

Passthrough Copy

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 development

Transforms

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

Preprocessors

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

Linters

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

Collections

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) + "..." : ""
    }));
});

URL Transforms

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

Build Configuration

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 parallel

Output Configuration

Configure 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 extensions

Types

interface 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

docs

build-pipeline.md

configuration-api.md

data-system.md

development-tools.md

index.md

plugin-system.md

programmatic-api.md

template-processing.md

tile.json