Build Awesome Power tools by Eleventy Blades

Table of Contents

Modern starters


Base eleventy.config.js

The package includes a fully-configured Eleventy config file eleventy.config.js that you can symlink to your project to get:

Benefits of symlinking:

Installation as simple as:

npm install @anyblades/eleventy-blades
ln -s ./node_modules/@anyblades/eleventy-blades/src/eleventy.config.js
How it works ```js

/* Plugins / import { RenderPlugin } from "@11ty/eleventy"; import eleventyBladesPlugin from "@anyblades/eleventy-blades"; / Dynamic plugins / let eleventyNavigationPlugin; try { eleventyNavigationPlugin = (await import("@11ty/eleventy-navigation")).default; } catch (e) { // @11ty/eleventy-navigation not installed } let pluginTOC; try { pluginTOC = (await import("@uncenter/eleventy-plugin-toc")).default; } catch (e) { // @uncenter/eleventy-plugin-toc not installed } let feedPlugin; try { feedPlugin = (await import("@11ty/eleventy-plugin-rss")).feedPlugin; } catch (e) { // @11ty/eleventy-plugin-rss not installed } / Libraries / import markdownIt from "markdown-it"; / Dynamic libraries / let slugify; try { slugify = (await import("@sindresorhus/slugify")).default; } catch (e) { // @sindresorhus/slugify not installed } let markdownItAnchor; try { markdownItAnchor = (await import("markdown-it-anchor")).default; } catch (e) { // markdown-it-anchor not installed } let markdownItAttrs; try { markdownItAttrs = (await import("markdown-it-attrs")).default; } catch (e) { // markdown-it-attrs not installed } / Data / import yaml from "js-yaml"; / System */ import fs from "node:fs"; import path from "node:path";

/**

  • Eleventy Configuration
  • @param {Object} eleventyConfig - The Eleventy configuration object
  • @returns {Object} The Eleventy configuration object */ export default function (eleventyConfig) { const inputDir = eleventyConfig.directories.input;

/* Jekyll parity */ eleventyConfig.addPassthroughCopy("assets"); eleventyConfig.addGlobalData("layout", "default"); eleventyConfig.setLiquidOptions({ dynamicPartials: false, // allows unquoted Jekyll-style includes root: [ eleventyConfig.directories.includes, inputDir + "../_includes", // for shared multisite includes fs.realpathSync(path.resolve("./node_modules/@anyblades/blades/_includes")), // for symlinks to work after /harttle/liquidjs/pull/870 ], }); eleventyConfig.addFilter("relative_url", (content) => content); // dummy

/* Plugins */ eleventyConfig.addPlugin(RenderPlugin); if (eleventyNavigationPlugin) eleventyConfig.addPlugin(eleventyNavigationPlugin); eleventyConfig.addPlugin(eleventyBladesPlugin, { mdAutoNl2br: true, mdAutoUncommentAttrs: true, mdAutoRawTags: true, autoLinkFavicons: true, siteData: true, filters: [ "attr_set", "attr_includes", "merge", "remove_tag", "if", "attr_concat", "fetch", "section", "strip_tag", "unindent", "date", ], }); if (pluginTOC) { eleventyConfig.addPlugin(pluginTOC, { ignoredElements: [".header-anchor", "sub"], ul: true, wrapper: (toc) => ${toc}, }); } // /docs/plugins/rss/#virtual-template if (feedPlugin) { eleventyConfig.addCollection("feed", (collectionApi) => collectionApi.getAll().filter((item) => item.data.revised)); let siteData = {}; try { siteData = yaml.load(fs.readFileSync(${inputDir}/_data/site.yml, "utf8")); } catch (e) { // _data/site.yml not found } eleventyConfig.addPlugin(feedPlugin, { type: "atom", // or "rss", "json" outputPath: "/feed.xml", collection: { name: "feed", // iterate over collections.posts limit: 100, // 0 means no limit }, metadata: siteData, }); }

/* Libraries */ let md = markdownIt({ html: true, linkify: true, }); if (markdownItAnchor) { md = md.use(markdownItAnchor, { slugify: slugify, // @TODO: TRICKS permalink: markdownItAnchor.permalink.ariaHidden(), }); } if (markdownItAttrs) md = md.use(markdownItAttrs); eleventyConfig.setLibrary("md", md); eleventyConfig.addFilter("markdownify", (content) => md.render(String(content ?? "")));

/* Data */ eleventyConfig.addDataExtension("yml", (contents) => yaml.load(contents));

/* Build */ eleventyConfig.addPassthroughCopy( { _public: ".", ...(inputDir !== "." && { [${inputDir}/_public]: "." }), }, { expand: true }, // This follows/resolves symbolic links );

/* Dev tools */ // Follow symlinks in Chokidar used by 11ty to watch files eleventyConfig.setChokidarConfig({ followSymlinks: true }); }


</details>
                

Base 11ty npm scripts via npm workspace

This package provides a pre-configured do folder setup that helps organize your development workflow using npm workspaces. The do folder contains scripts for building and running your Eleventy project.

Installation:

  1. Install /anyblades/eleventy-blades to reuse pre-defined 11ty scripts from there:
npm install @anyblades/eleventy-blades
  1. Create a helper folder do to symlink the do/package.json within:
mkdir do
cd ./do
ln -s ../node_modules/@anyblades/eleventy-blades/src/do/package.json
  1. Finally register do folder as npm workspace in your root package.json:
{
  ...
  "workspaces": ["do"],
  "scripts": {
    "start": "npm -w do run start",
    "stage": "npm -w do run stage",
    "build": "npm -w do run build"
  },
  ...
}

Done! 🎉 Now you can run:

Living examples:

Benefits:

  • Clean separation: Keep build scripts separate from project configuration
  • Reusable workflows: Update scripts by upgrading the package
  • Workspace isolation: Scripts run in their own workspace context
  • Easy maintenance: No need to manually maintain build scripts

Data helpers

Adds global site data to your Eleventy project, providing commonly needed values that can be accessed in all templates:

Variable Value
{{ site.year }} The current year as a number (e.g., 2026)
{{ site.prod }} Boolean indicating if running in production mode (true for eleventy build, false for eleventy serve)
How it works ```js /** * Add site.year and site.prod global data * - site.prod: Boolean indicating if running in production mode (build) vs development (serve) * - site.year: Sets the current year to be available in all templates as {{ site.year }} * * @param {Object} eleventyConfig - The Eleventy configuration object */ export function siteData(eleventyConfig) { eleventyConfig.addGlobalData("site.prod", () => process.env.ELEVENTY_RUN_MODE === "build"); eleventyConfig.addGlobalData("site.year", () => new Date().getFullYear()); } ```

Appendix

Find and kill 11ty processes

ps aux | grep eleventy
pkill -f eleventy

You can even combine it with other processes hanging around:

ps aux | grep -E 'eleventy|tailwind|.bin/serve'
pkill -f tailwind
pkill -f .bin/serve