assets
INTERNAL_KEY: '_assets'
What it does
The assets module is the bridge between Eleventy's template system and the asset processors. It registers js and css as template formats, gates them with compile guards (filters that decide which files get processed), watches the assets directory for changes, and exposes two inline filters for embedding bundles directly in a template.
esbuild handles JS, PostCSS handles CSS. Both ship with Baseline.
Active when
Always. The assets module is always loaded.
Lifecycle
Build-time only. The module registers template formats, compile guards, a watch target, and the inline filters. It does no cascade-time or transform-time work.
How it works
- Resolve the assets directory. The composition root registers a virtual directory keyed
assetsand exposes the resolved path through_baseline.paths.assets. - Register
jsandcsstemplate formats. Each gets an extension handler withread: falseso the processor owns its own I/O. - Apply compile guards. A compile guard is a small filter inside the extension handler. JS guards: only
index.jsfiles underassets/js/are processed;11tydata.jsfiles are also explicitly excluded from the template graph. CSS guard: onlyindex.cssfiles underassets/css/. Anything else returns undefined and is skipped without error. - Watch the assets directory. The watch glob covers JS, CSS, and common image formats so an asset edit triggers a reload during
npm start. - Register inline filters. An inline filter runs the processor against a path you give it and wraps the result in
<script>or<style>tags. See the processor subsections below.
Defaults
- Assets directory. The virtual directory keyed
assetsoneleventyConfig.directories. Defaults tosrc/assets/per the directory contract. Available in templates as_baseline.paths.assets. - JS entry points. Any
index.jsunderassets/js/(including nested folders). An entry point is the front door of a bundle; everything else is reached throughimportfrom there. - CSS entry points. Any
index.cssunderassets/css/. Reach the rest through@import. - esbuild.
minify: true,target: 'es2020'. Defaults live in _baseline/modules/assets/processors/esbuild-process.js. - PostCSS. Resolves your project's
postcss.config.jsfrom the project root (cwd). If none is found, falls back to the config bundled with baseline (postcss-import-ext-glob,postcss-import,postcss-preset-env, andcssnanoin production). The resolved config is cached for the lifetime of the process; restart Eleventy to pick up changes. - Watch target.
assets/**/*.{css,js,svg,png,jpeg,jpg,webp,gif,avif}. A watch target is a glob Eleventy reloads on during--serve. - Output. Compiled files land under
dist/assets/, mirroring the input layout.
Options
| Option | Type | Default | Meaning |
|---|---|---|---|
assets.esbuild |
object | {} |
Forwarded to esbuild on every entry-point build, merged over the defaults. Does not reach inlineESbuild. |
PostCSS has no plugin-level options. Configure it through your own postcss.config.js. See Customise the assets pipeline for the recipe.
JS processor: esbuild
The JS processor bundles a JavaScript file and returns the compiled text. A pure function with no Eleventy knowledge: takes a path, returns a string.
At the plugin level, override esbuild defaults through options.assets.esbuild:
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) {
await eleventyConfig.addPlugin(
baseline(settings, {
assets: {
esbuild: {
minify: process.env.ELEVENTY_ENV === 'production',
target: 'es2017'
}
}
})
);
}
export const config = baselineConfig;
These apply to compiled entry points only. The inline filter does not see them: it goes straight to the processor, so it always starts from minify: true and target: 'es2020' however you set assets.esbuild. Give the filter anything it should do differently per call.
Per call, the inlineESbuild filter accepts an options object that merges over the processor defaults:
{% set jsPath = _baseline.paths.assets ~ "js/inline-example.js" %}
{{ jsPath | inlineESbuild({ minify: false, target: "es2017" }) | safe }}
The filter is not limited to the assets directory: pass any absolute path. In Markdown, keep the call unindented and on its own lines so the <script> tag is treated as raw HTML, and pipe through | safe so Nunjucks does not escape it.
On error, the processor logs and returns /* Error processing JS */ so the build does not break.
CSS processor: PostCSS
The CSS processor runs a CSS file through PostCSS and returns the compiled text. Pure function, same shape as the JS processor.
It does not take plugin-level options. Configure it through postcss.config.js at your project root. See Customise the assets pipeline for the steps.
The inlinePostCSS filter wraps any CSS file in <style> tags:
{% set cssPath = _baseline.paths.assets ~ "css/critical.css" %}
{{ cssPath | inlinePostCSS | safe }}
Same Markdown caveat: keep the call unindented, pipe through | safe. Useful for critical CSS that should render before the main stylesheet loads.
On error, the processor logs and returns /* Error processing CSS */.
Tips
- Two entry points. Only
index.jsandindex.cssare compiled; reach everything else throughimportand@import. - Images are watched. The watch target covers them too, so editing an SVG or PNG triggers a reload without extra config.
- PostCSS config is optional. The bundled fallback is a sensible starting point, and you only need your own
postcss.config.jsto customise plugins. - Inline sparingly. The inline filters suit small critical-path assets; anything large ends up duplicated on every page.
Peer deps
esbuild and postcss. Both ship with Baseline.
See also
- Image shortcode for images, which this module only watches. It resolves its
srcagainst the input directory rather than the assets one. - Filters reference lists
inlineESbuildandinlinePostCSSalongside the rest. - Customise the assets pipeline
- Tutorial: assets pipeline