Plugins

On this page

Plugins extend the Kilim build. They run only at build time: nothing in a plugin reaches the browser except the output it changes, and pages stay free of JavaScript unless a plugin explicitly declares client scripts (see Client scripts).

Using plugins

Plugins are factories that return a plugin object. Add them to plugins in kilim.config.ts:

import { defineConfig } from "@kilim-dev/core";
import { readingTime } from "./plugins/reading-time.ts";

export default defineConfig({
  plugins: [readingTime({ wordsPerMinute: 230 })],
  audit: {
    // Plugin rules are typed: `max` must be a number here.
    rules: { "reading-time/too-long": ["error", { max: 15 }] },
  },
});

Plugins run in this order:

  1. the built-in ones the config leaves on: feed, sitemap, og-image;
  2. the theme's (defineTheme({ plugins })), base theme first when it extends another;
  3. the config's plugins, in order.

A plugin with the same name as an earlier one replaces it, at its own position. That is how a site configures a theme's plugin, or a built-in one:

import { feed, sitemap } from "@kilim-dev/core/plugins";

export default defineConfig({
  plugins: [feed({ formats: ["rss", "atom"], limit: 50 })],
});

The config options feed, sitemap and ogImage are shorthands for the built-in plugins and stay supported: sitemap: false turns the sitemap plugin off, feed: { limit: 50 } is the same as plugins: [feed({ limit: 50 })]. Use one or the other for a plugin, not both.

Built-in plugins

@kilim-dev/core/plugins has these plugins:

PluginOn by defaultWhat it writes
sitemap()yes/sitemap.xml of the indexable pages, with language alternates.
feed()yesRSS (and optionally Atom and JSON Feed) next to each collection list.
ogImage()yesAn Open Graph image per page from the theme's template.
search()noA search index and the script of the theme's search box.
llmsTxt()no/llms.txt and /llms-full.txt for language models.
import { search } from "@kilim-dev/core/plugins";

export default defineConfig({
  plugins: [search({ collections: ["docs"] })],
});

search() writes /_kilim/search.json with each page's title, description, headings and the start of its text, and adds a small script to the pages that have a search box (an element with data-kilim-search; the default theme puts one above the docs sidebar, or in the header with the setting search: header). Other pages stay free of JavaScript. Matching runs in the browser, ignores accents and ranks titles over headings over text; a result can jump to the matching section.

OptionMeaning
collectionsCollections to index; every published page by default.
bodyLengthCharacters of body text kept per page (default 2000); 0 keeps only headings.
script"inline" (default, allowed by a CSP hash) or "file", one cached script file.

kilim check warns when the index grows past 500 KB (search/index-size).

llms.txt

import { llmsTxt } from "@kilim-dev/core/plugins";

export default defineConfig({
  plugins: [llmsTxt({ collections: ["docs"] })],
});

llmsTxt() writes /llms.txt (the site title, description and a linked list of pages per collection, as llmstxt.org describes) and /llms-full.txt, the Markdown source of those pages, for language models. full: false leaves out llms-full.txt. This site has both: /llms.txt. kilim check warns when an llms-full.txt grows past 500 KB, so that it still fits in the context of a language model (llms-txt/full-size).

Writing your own

Writing plugins covers definePlugin, the build hooks, frontmatter fields, audit rules and client scripts.