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:
- All eleventy-blades plugins enabled
- Eleventy Navigation plugin
- Table of Contents plugin (conditionally loaded if installed)
- Markdown-it with anchors and attributes
- YAML data support
- CLI input directory support
- Symlink support for development
- and more
Benefits of symlinking:
- Always up-to-date: Configuration automatically updates when you upgrade the package
- Less maintenance: No need to manually sync configuration changes
- Quick setup: Get started immediately with best-practice configurations
- Easy customization: Override specific settings by creating your own config that imports from the symlinked version
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:
- Install
/anyblades/eleventy-blades to reuse pre-defined 11ty scripts from there:
npm install @anyblades/eleventy-blades
- Create a helper folder
doto symlink thedo/package.jsonwithin:
mkdir do
cd ./do
ln -s ../node_modules/@anyblades/eleventy-blades/src/do/package.json
- Finally register
dofolder as npm workspace in your rootpackage.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:
npm startto start 11ty dev server with live reload and Tailwind watch modenpm run stageto build and serve production-like site locallynpm run buildto finally build the site for production- all available scripts:
/anyblades/eleventy-blades/blob/main/src/do/package.json
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