Get started Eleventy Blades base package

Base package bundles Eleventy Blades with other popular 11ty plugins, providing a ready-to-go reusable, zero-maintenance config:

npm install @anyblades/eleventy-blades-base

# Link base templates:
cd _includes/
ln -s ../node_modules/@anyblades/blades/_includes/blades

# Run Eleventy:
eleventy --config=node_modules/@anyblades/eleventy-blades-base/eleventy.config.js

Live examples:


If you don't want to type --config=... every time, symlink it once:

ln -s node_modules/@anyblades/eleventy-blades-base/eleventy.config.js
eleventy

Or save it in your package.json scripts:

  "scripts": {
    "build": "eleventy --config=node_modules/@anyblades/eleventy-blades-base/eleventy.config.js"
  }

Alternatively, import it as a base config in your 11ty config:

import baseConfig from "@anyblades/eleventy-blades-base";

export default async function (eleventyConfig) {
  await baseConfig(eleventyConfig);
}

You can toggle features/filters like this:

await baseConfig(eleventyConfig, {
  plugins: {
    "@anyblades/eleventy-blades": {
      mdAutoRawTags: false,
      filters: { attr_set: false },
    },
  },
});

Live examples:


B. Starter projects

Eleventy Blades plugin and base package are included out-of-the-box with:

BA v4 6-in-1 Starter
Modern, lightweight Eleventy v4 multi-site starter showcasing Eleventy Blades Kit and Tailwind CLI for: [1] Tailwind CSS + Typography [2] Blades CSS [3] Bootstrap CSS [4] Pico CSS [5] Simple CSS [6] Liquid Templates.
11ty v4 Subtle
The most subtle Eleventy v4 micro-starter for content-first sites. Powered by Eleventy Blades Kit
Built-in bare-minimum examples
/anyblades/eleventy-blades/tree/main/examples

Appendix


How it works

/anyblades/eleventy-blades/refs/heads/main/packages/eleventy-blades-base/eleventy.config.js :


/* Plugins (core > official > contrib) */
import { RenderPlugin } from "@11ty/eleventy";
import { feedPlugin } from "@11ty/eleventy-plugin-rss";
import eleventyNavigationPlugin from "@11ty/eleventy-navigation";
import eleventyBladesPlugin from "@anyblades/eleventy-blades";
import pluginTOC from "@uncenter/eleventy-plugin-toc";
import { siteData } from "@anyblades/eleventy-blades/features/siteData.js";
/* Libraries (A-Z) */
import markdownIt from "markdown-it";
import markdownItAnchor from "markdown-it-anchor";
import markdownItAttrs from "markdown-it-attrs";
import slugify from "@sindresorhus/slugify";
import YAML from "yaml";
/* System (A-Z) */
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 async function (eleventyConfig, pluginOptions = {}) {
  /* Dirs */
  const inputDir = eleventyConfig.directories.input;
  const outputDir = eleventyConfig.directories.output;
  const cwdIsDotEleventy = path.basename(process.cwd()) === ".11ty";
  if (cwdIsDotEleventy) {
    // Per https://www.11ty.dev/docs/config/#directory-for-includes
    // Order matters, put this at the top of your configuration file.
    // This is relative to your input directory!
    eleventyConfig.setIncludesDirectory("./.11ty/_includes/");
  }

  /* Plugins */
  eleventyConfig.addBundle("css", { bundleHtmlContentFromSelector: "style" }); // per https://www.11ty.dev/docs/plugins/bundle/#bundling-html-node-content
  eleventyConfig.addTransform("inject-css-bundle", function (content) {
    const isHtml = typeof this.page.outputPath === "string" && this.page.outputPath.endsWith(".html");
    const css = isHtml && eleventyConfig.getFilter("getBundle").call(this, "css");
    return css ? content.replace("</head>", `<style>${css}</style></head>`) : content;
  });
  eleventyConfig.addPlugin(RenderPlugin);
  eleventyConfig.addPlugin(eleventyNavigationPlugin);
  eleventyConfig.addPlugin(
    eleventyBladesPlugin,
    pluginOptions.plugins?.["@anyblades/eleventy-blades"] ?? { mdAutoRawTags: true },
  );
  eleventyConfig.addPlugin(pluginTOC, {
    ignoredElements: [".header-anchor", "sub"],
    ul: true,
    wrapper: (toc) => `${toc}`,
  });
  // Feed plugin
  eleventyConfig.addCollection("feed", (collectionApi) =>
    collectionApi.getAll().filter((item) => item.data.date || item.data.revised),
  );
  eleventyConfig.addPlugin(feedPlugin, {
    // per https://www.11ty.dev/docs/plugins/rss/#virtual-template
    type: "atom", // or "rss", "json"
    outputPath: "/feed.xml",
    collection: {
      name: "feed",
      limit: 100, // 0 means no limit
    },
    templateData: {
      eleventyComputed: {
        metadata: (data) => {
          return {
            base: "https://example.com/", // sample/fallback value required by Feed plugin
            ...siteData(data),
          };
        },
      },
    },
  });

  /* Libraries */
  let md = markdownIt({
    html: true,
    linkify: true,
  })
    .use(markdownItAnchor, {
      slugify: slugify, // @TODO: TRICKS
      permalink: markdownItAnchor.permalink.ariaHidden(),
    })
    .use(markdownItAttrs);
  await import("markdown-it-deflist")
    .then(({ default: markdownItDeflist }) => {
      md.use(markdownItDeflist);
    })
    .catch(() => {
      /* optional – skip if not installed */
    });
  eleventyConfig.setLibrary("md", md);
  ``````js
  eleventyConfig.addFilter("markdownify", (content) => md.render(String(content ?? "")));
  ``````js

  /* Data */
  eleventyConfig.addDataExtension("yml,yaml", (contents) => YAML.parse(contents));
  eleventyConfig.addGlobalData("layout", "default");
  // Sitemap
  eleventyConfig.addTemplate("sitemap.xml.njk", "", {
    permalink: "/sitemap.xml",
    layout: "blades/sitemap.xml.njk",
    eleventyExcludeFromCollections: true,
  });

  /* Build */
  eleventyConfig.addPassthroughCopy(
    {
      // From current working directory
      _public: "./",
      media: "./media/",
      // Additionally from input dirs like `../` or `./site-1`
      [`${inputDir}/_public/`]: "./",
      [`${inputDir}/media/`]: "./media/",
    },
    { expand: true }, // This follows/resolves symbolic links
  );

  /* Internal */
  // Jekyll templates compatibility
  eleventyConfig.addFilter("relative_url", (content) => content); // dummy
  eleventyConfig.setLiquidOptions({
    dynamicPartials: false, // allows unquoted Jekyll-style includes
    root: [
      eleventyConfig.directories.includes,
      fs.realpathSync(path.resolve("./node_modules/@anyblades/blades/_includes")), // for symlinks to work after https://github.com/harttle/liquidjs/pull/870
    ],
  });
  // Dev tools
  eleventyConfig.setChokidarConfig({ followSymlinks: true }); // follow symlinks in Chokidar used by 11ty to watch files
  if (cwdIsDotEleventy) {
    eleventyConfig.watchIgnores.add(`../.11ty/${outputDir}`); // !!! avoid circular watching
    eleventyConfig.watchIgnores.add("../.11ty/node_modules/"); // avoid performance issues
  }
}