Table of Contents
Customise the Assets Pipeline
When the fallback configs in the assets module are not enough, drop your own in. PostCSS for CSS, esbuild for JS. The module picks them up.
Prerequisites
- Baseline registered in
eleventy.config.js. - Default entries in place:
src/assets/css/index.cssandsrc/assets/js/index.js. package.jsonwith"type": "module"and scripts (start,build).
PostCSS config
A postcss.config.js at the project root replaces Baseline's fallback wholesale. Bring the plugins you want, gate cssnano on production, and check the output.
1) Install PostCSS and the plugins you plan to use:
npm install postcss postcss-import postcss-preset-env cssnano postcss-mixins
Once you ship your own postcss.config.js, the fallback plugins are gone. Whatever you list here has to be installed explicitly.
2) Add postcss.config.js at the project root:
import postcssImport from 'postcss-import';
import postcssMixins from 'postcss-mixins';
import postcssPresetEnv from 'postcss-preset-env';
import cssnano from 'cssnano';
const isProd = process.env.ELEVENTY_ENV === 'production';
const plugins = [postcssImport(), postcssMixins(), postcssPresetEnv({ stage: 1 })];
if (isProd) {
plugins.push(cssnano({ preset: 'default' }));
}
/** @type {import('postcss-load-config').Config} */
export default {
map: isProd ? false : { inline: true },
plugins
};
3) Exercise the config in your CSS (imports and mixins):
src/assets/css/base.css:
:root {
color-scheme: light;
}
body {
font-family: system-ui, sans-serif;
margin: 0;
padding: 2rem;
line-height: 1.5;
color: #1f2937;
background: #f8fafc;
}
h1 {
margin-bottom: 0.5rem;
}
.pill {
display: inline-block;
padding: 0.25rem 0.75rem;
border-radius: 999px;
background: #e0f2fe;
color: #0f172a;
font-weight: 600;
}
src/assets/css/mixins.css:
@define-mixin linksMixin {
color: #0f172a;
text-decoration: underline;
text-decoration-color: #fc35b9;
text-decoration-thickness: 2px;
text-underline-offset: 3px;
font-weight: 600;
}
src/assets/css/links.css:
a {
@mixin linksMixin;
}
a:hover {
color: #fc35b9;
}
src/assets/css/index.css:
@import './base.css';
@import './mixins.css';
@import './links.css';
4) Run and inspect.
- Dev:
npx rimraf dist/ && npm run dev - Build:
npx rimraf dist/ && npm run build - Check
dist/assets/css/index.css:- Dev: expanded CSS with mapped imports; no minification.
- Prod: minified (cssnano), imports flattened, custom media resolved.
Notes
- Your
postcss.config.jsfully overrides Baseline's fallback. Keep the entry file atsrc/assets/css/index.cssand add partials via imports. - Reach for what you need (purge, RTL, lightningcss, others). Env guards are the cleanest way to keep dev output readable and production output optimised.
Esbuild targets
The JS pipeline takes more nudging than the CSS one. You may want extra entry points, different targets, or a one-off inline bundle, and esbuild is the lever for all three.
1) Install and pin esbuild explicitly.
Baseline depends on esbuild already, but esbuild's own docs recommend pinning the version you build against:
npm install --save-exact --save-dev esbuild
2) Add additional entry points.
An entry point is the file Baseline hands to esbuild as the start of a bundle. Each index.js under src/assets/js/**/ is one entry point and produces one bundle in dist/assets/js/:
mkdir -p src/assets/js/home src/assets/js/about
echo "console.log('home bundle');" > src/assets/js/home/index.js
echo "console.log('about bundle');" > src/assets/js/about/index.js
Reference them from a page's front matter:
---
title: 'Hello Baseline'
description: 'A minimal Eleventy page powered by eleventy-plugin-baseline.'
permalink: '/'
layout: 'layouts/base.njk'
head:
script:
- src: '/assets/js/home/index.js'
defer: true
---
3) Inline a small script.
For tiny helpers, inline the bundled output with Baseline's inlineESbuild filter. _baseline.paths.assets is the resolved input path to your assets directory; concatenating the relative path keeps the example portable:
{% set jsPath = _baseline.paths.assets ~ "js/about/index.js" %}
{{ jsPath | inlineESbuild | safe }}
This bundles and minifies the file with esbuild's es2020 target, then injects a <script>...</script> tag.
4) Set default target and minification for all bundles.
Pass assets.esbuild options when you register Baseline:
import baseline, { config as baselineConfig } from '@apleasantview/eleventy-plugin-baseline';
import settings from './src/_data/settings.js';
/** @param {import("@11ty/eleventy").UserConfig} eleventyConfig */
export default async function (eleventyConfig) {
eleventyConfig.addPlugin(
baseline(settings, {
assets: {
esbuild: {
minify: process.env.ELEVENTY_ENV === 'production',
target: 'es2017'
}
}
})
);
}
export const config = baselineConfig;
5) Override target or minification for a specific inline script.
For one-offs, pass options directly to the filter. They merge over your defaults from assets.esbuild:
{% set jsPath = _baseline.paths.assets ~ "js/about/index.js" %}
{{ jsPath | inlineESbuild({ minify: false, target: "es2018" }) | safe }}
- Verify.
- Dev:
npm start - Build:
npm run build - Check
dist/assets/js/**/index.jsfor bundled output and size. - For inlined scripts, view the page source and confirm the bundled code is present.
- Dev:
Notes
- Baseline's default JS bundling: any
index.jsundersrc/assets/js/**/is bundled, minified, and targeted toes2020. - Inline only for small helpers; keep larger bundles as external files so they cache.
- A global override is yours to maintain. Revisit it whenever your browser support changes.
- If you reach for the same inline overrides repeatedly, write your own filter that calls
inlineESbuildwith preset options and use that filter instead.
See also
Previous: How-To's
Next: Deploy Under a Subpath