Table of Contents

v0.1.0-next.46

The biggest release so far, and it has one new feature and a lot of sharpening. The feature is page breaks: a comment in the body turns one file into several pages, an affordance WordPress has had for twenty years and static site generators have not.

The sharpening is mostly the image shortcode, which was opened up after a consumer forked a hundred and forty lines of it to get past a closed function. Three breaking changes come out of that, and one of them changes the markup on every site that renders an image.

Baseline also stops narrating your build unless you ask it to.


Breaking

  • A missing alt now throws instead of warning.

    The build stops rather than shipping a page with an unlabelled image. This is what eleventy-img itself does, and a warning was the wrong tool: it scrolls past, and the page ships either way.

    Use an empty string for a decorative image. alt: "" is a statement, and it now reaches the output intact where the attribute renderer used to drop it, which had erased the difference between a decorative image and one nobody had thought about.

    • Symptom: a build that stops naming a file and an image, where it used to print a warning you had learned to ignore.
  • Five image options were removed rather than deprecated.

    imageClass, containerClass, style, attrs and figure are gone. Passing one is ignored, so check your call sites. Two bags replace all five: img for attributes on the <img>, picture for attributes on the <picture>, and both take anything HTML takes.

    {% image {
    	src: "/media/hero.jpg",
    	alt: "The valley at first light",
    	img: { class: "u-rounded", "data-zoom": true },
    	picture: { class: "c-hero__media" }
    } %}

    The migration table is on the image shortcode reference. Dropping figure fixes a silent data loss on the way past: figure: false alongside a caption used to return the picture alone and discard the caption, on a green build.

  • jpeg joined the default formats, and the <img> fallback changed size.

    Defaults are now ['avif', 'webp', 'jpeg'], and the <img> inside the <picture> takes the largest rendition of the most compatible format rather than the smallest.

    Both halves are about the same thing. The <img> carries no srcset, so its src is not the first of several candidates a browser picks from: it is the whole answer for anything that reads the markup without rendering it, which is feed readers, scrapers and link-preview bots. Those were being handed the smallest file, described with the largest file's width and height. With only avif and webp generated there was also no format a client could fall back to.

    • Costs a third encode per width. Drop jpeg from media.image.formats if you would rather not pay it, and the emitted markup on every existing site changes on the next build either way.

Changed

  • Baseline is quiet by default. You get the startup banner, a version line and one line naming the active modules. verbose: true opts into the full narrative. verbose: false is a third state and means silence, because saying nothing and saying no are different requests. warn and error still emit in every state, and Eleventy's own --quiet has the same effect as false.

  • An asset that does not compile now fails the build. There is no useful site on the other side of a stylesheet that did not parse, and the error names the file. The dev server is the exception and still degrades to a placeholder comment, because a dead watch loop is worse than a broken reload.

  • assets.esbuild reaches esbuild whole. It never did: the processor read minify and target off the object and dropped everything else, while the docs said otherwise. define, loader, banner, external and the rest all work now. If you have been setting a key that was quietly discarded, it takes effect on this release, and a bad value fails the build where it used to do nothing.

  • A name you already defined stays yours. Register a markdownify filter or an image shortcode of your own and Baseline leaves it alone rather than overwriting it, and says at startup which ones it skipped. Eleventy's own warning for this goes to a debug namespace nobody has switched on.

  • The pre-pass stopped building what it throws away. It no longer compiles the asset pipeline into a dry run whose output is discarded, and the image shortcode uses statsOnly there rather than encoding every rendition twice per build.


Added

  • Page breaks. A <!--pagebreak--> in the body splits the page into parts, one Eleventy page each, numbered under the page's own URL. The grammar borrows wikilinks, so <!--pagebreak#setup|Data files--> names the part and gives it an entry point. Baseline emits no navigation markup: _pagebreak carries the parts and your layout draws the links, the same bargain as page.translations. See splitting a long page.

  • Project-wide image defaults. media: { image: { widths, formats, sizes } } at registration, so a house style is set once rather than on every call. A single call still overrides them.

  • A build cache for image renditions. In a build, renditions are written to .cache/media/ and copied into the output afterwards, so wiping dist or starting from a clean CI checkout no longer costs a re-encode. Nothing invalidates it, deliberately: clearing a cache is your maintenance, not the plugin's. Persisting .cache between deploys is one block on Netlify and automatic on Vercel and Cloudflare.

  • Attributes on the inline filters. inlineESbuild and inlinePostCSS take an attributes object and put it on the <script> or <style> tag, which is the only way to attach a CSP nonce to a bundle the filter has just produced. true renders a bare attribute; false and null are dropped.


Fixed

  • A media-scoped <meta> no longer disappears. Dedupe keyed on name alone, so two theme-color tags differing only by media query were treated as one and the second was dropped. Media-scoped theme-color is the canonical use of that attribute, so any site with a dark mode hit this.

  • ogImage: false declines a share image properly, rather than falling through to the site default. The chain was using ??, which passes anything that is not null or undefined, so false sailed through it.

  • Every language root is a home page. On a multilingual site only / counted, so /nl/ and /fr/ were treated as ordinary pages by anything reading the home flag.

  • The sitemap honours defaultLocale. It read settings.defaultLanguage directly, so a site setting only the documented alias failed the multilingual check and got one flat sitemap while multilang was running.

  • <meta name="description"> no longer falls back to the first paragraph. A page with nothing to say about itself now says nothing, rather than repeating its opening sentence into a search result.


Docs

The whole tree had an accuracy pass, a reconciliation pass driven from the commit history, and a voice pass, chapter by chapter. The results worth naming: ten page-level seo.* front-matter keys now have a reference entry where they had none, the settings.seo example names the four keys inside openGraph and twitter, and the reserved data keys list was two short.


Reading list

Where to go deeper on the surfaces that changed.

Page breaks

Images

Assets

SEO front matter