Table of Contents
Integrate with Eleventy Base Blog
This article is planned for revision, its content might be stale.
Add Baseline to the official eleventy-base-blog starter with as little disruption as the starter's existing wiring allows. The work splits into four pieces: bring Baseline in, line the starter's directories up with Baseline's contract, migrate the starter's hand-rolled <head> into Baseline's head pipeline, and confirm the output.
If you don't already have a project to integrate into, the simple site tutorial is the lighter starting point.
Prerequisites
- You have
eleventy-base-blogcloned and running (npm install,npm run devworks). - Eleventy 3.x;
package.jsonhasdevandbuildscripts. settings.urlwill be set via env (URL) for production.
1) Install Baseline
npm install @apleasantview/eleventy-plugin-baseline
2) Wire Baseline into eleventy.config.js
In your existing config:
-
Remove the
HtmlBasePluginimport and call. Baseline registers its own. -
Import Baseline and the Baseline directory contract; add the plugin last so it sees the rest of your config:
import baseline, { config as baselineConfig } from '@apleasantview/eleventy-plugin-baseline'; import settings from './src/_data/settings.js'; export default async function (eleventyConfig) { // ...your existing config eleventyConfig.addPlugin(baseline(settings)); } export const config = baselineConfig; // spread to override if needed
- Update
passthroughCopyinputs to./src/static/and./src/content/feed/pretty-atom-feed.xsl. - Remove watch targets for CSS or images if present (Baseline handles them).
- Point CSS and JS bundle
toFileDirectorytoassets/cssandassets/jsrespectively. - Set
basetoprocess.env.URL.
The full file is in the eleventy-base-blog fork.
3) Add a local .env for development
ELEVENTY_ENV="development"
URL="http://localhost:8080"
In CI and production, set URL to your live origin (e.g. https://www.example.com); Baseline uses it for canonical URLs and the sitemap.
4) Move Eleventy Base Blog folders under src/
Move the following folders to match Baseline's defaults:
_data→src/_data_includes→src/_includescontent→src/contentcss→src/assets/csspublic→src/static
The last move has an asymmetry worth knowing upfront. Baseline's directory contract sets public: 'static', so the virtual key on eleventyConfig.directories is public but the folder on disk stays static/. The config-export reference covers the same split.
Update layouts and includes to resolve from src/, and content from src/content/. Delete sitemap.xml.njk in src/content/; Baseline's sitemap module handles it.
5) Add the required data file
src/_data/settings.js is the single source for site identity and head extras. The starter's _data/head.js is no longer in play once Baseline is wired; head extras move onto settings.head instead (step 7 walks through the migration):
export default {
title: 'Eleventy Base Blog (Baseline Edition)',
tagline: 'Baseline + Eleventy Base Blog',
url: process.env.URL || 'http://localhost:8080/',
defaultLanguage: 'en',
noindex: false,
head: {
link: [{ rel: 'stylesheet', href: '/assets/css/index.css' }],
script: [{ src: '/assets/js/index.js', defer: true }]
}
};
6) Align assets
Make sure these exist (or create minimal stubs):
src/assets/css/index.css: import your base CSS or start empty.src/assets/js/index.js: optional JS entry; can be empty.src/assets/assets.11tydata.jsto keep the assets directory out of collections:export default { eleventyExcludeFromCollections: true };
7) Migrate the starter's head children
The starter's base.njk writes a <head> with three extras Baseline does not render for you: an Atom feed <link>, an inline <style> produced by eleventy-plugin-bundle, and a @zachleat/heading-anchors <script type="module">. With Baseline, you do not author your own <head>; you push these into the head pipeline. One pattern per extra, in the same order:
Atom feed link → settings.head.link[]. Site-wide static link. Add it to src/_data/settings.js:
head: {
link: [
{ rel: 'stylesheet', href: '/assets/css/index.css' },
{
rel: 'alternate',
type: 'application/atom+xml',
title: 'Eleventy Base Blog',
href: '/feed/feed.xml'
}
];
}
@zachleat/heading-anchors script → settings.head.script[] plus an entry point. Re-export the module from a small entry under src/assets/js/heading-anchors/index.js:
import '@zachleat/heading-anchors';
Baseline's assets pipeline bundles it to dist/assets/js/heading-anchors/index.js. Reference it in head extras:
script: [
{ src: '/assets/js/index.js', defer: true },
{ src: '/assets/js/heading-anchors/index.js', type: 'module' }
];
Per-page bundled CSS → getBundle("css") style block. This is the non-trivial migration. The starter collects per-page CSS through eleventy-plugin-bundle and inlines the result. Baseline has no head-extras shape for inline <style>, so two approaches work depending on what the bundle is for:
-
If the styles are page-specific and small, keep the bundle plugin and inline them from the layout body (after
<baseline-head>), with the small caveat that they sit outside the<head>. Most browsers handle this fine, but it's not strictly compliant. -
If the styles are reusable, consolidate them into files under
src/assets/css/and inline with Baseline'sinlinePostCSSfilter, called inside an inlineable head fragment that the layout includes:{% set cssPath = _baseline.paths.assets ~ "css/post.css" %} {{ cssPath | inlinePostCSS | safe }}This belongs at the top of the layout body, not inside
<baseline-head>(which Baseline replaces wholesale). The placeholder is your<head>; everything else goes in the body.
8) Add <baseline-head> to base.njk
The placeholder sits inside <html>, as a sibling of <body>. Baseline replaces it with the rendered <head> element at build time. Don't author your own <head> around it:
<!DOCTYPE html>
<html lang="en">
<baseline-head></baseline-head>
<body>
...
</body>
</html>
9) Organise content and set permalinks.
Move the following files to src/content/pages/ and set their permalinks as needed:
404.md,about.md,blog.njk,index.njk,tag-pages.njk,tags.njk
Example index.njk:
---js
const permalink = "/";
---
Add the permalink function in blog.11tydata.js:
export default {
// Keep tags and layout keys.
permalink: function ({ page }) {
if (page.inputPath.includes('11tydata.js')) {
return false;
}
return `/blog/${this.slugify(page.fileSlug)}/`;
}
};
10) Use Baseline's inline-asset filters where it makes sense.
Replace direct CSS link-tags in src/_includes/layouts/post.njk and src/_includes/layouts/home.njk with the inline PostCSS filter. _baseline.paths.assets resolves to your assets input directory:
nunjucks {% set cssPath = _baseline.paths.assets ~ "css/message-box.css" %} {{ cssPath | inlinePostCSS | safe }}
11) Verify head, meta, and sitemap.
- Dev: npx rimraf dist/ && npm run dev
- Build: npx rimraf dist/ && npm run build
- Check a page's <head> for <title>, <meta name="description">, <link rel="canonical">, and (if multilingual) hreflang alternates.
- Inspect dist/sitemap.xml for correct URLs (uses settings.url and pathPrefix if set).
12) Optional: navigator and debug filters.
- Set navigator: true in the plugin options if you want the navigator page (dev only).
- Use the _inspect, _json, and _keys filters on a debug page to inspect data.
Next steps
- Add recommended build scripts and helper packages: Build Scripts and Cleanup.
Notes
- Keep
settings.urlorigin-only; usepathPrefixif you deploy under a subpath. - Baseline's assets pipeline uses
src/assets/css/index.cssandsrc/assets/js/index.jsas the default entry points. - If you have other CSS or JS paths, either point
settings.head.link[]andsettings.head.script[]at the Baseline output paths or mirror the files intosrc/assets/.
See also
Previous: Multilingual Index