Functions
fasset(
file: string,
content: string | Uint8Array<ArrayBufferLike>
): Asset
A file for the build, made from data: a search index, a feed, a generated image. The build writes it, and a page links to it by this value, its URL with a hash of the content, like the JS and CSS links: <input data-index="{{ search.index }}"> -> data-index="/search.json?v=1a2b3c4d". The hash only changes when the content does, so browsers and CDNs can keep it until then.
fbuild(site: Site): Promise<void>
The production build, from an empty build folder.
fclean(site: Site): Promise<void>
Removes the build folder, what the production build starts with.
fdefineConfig(config: Config): Config
Gives the config its types in your editor, it's returned as it is.
fdev(
site: Site,
{ host, port }?: { host?: string; port?: number; }
): Promise<void>
Builds, serves and rebuilds what changes.
fescapeHtml(text: string): string
Escapes the characters that mean something in HTML, &<>"', so the text shows as it is.
fhtml(strings: TemplateStringsArray, ...values: any[]): Html
A template tag for HTML in .data.js files. What goes into it is escaped, unless it's Html already: another html..., raw(), or a list of those. null, undefined and false are left out.
floadConfig(root?: string): Promise<Site>
Imports a folder's mothwing.config.js and resolves it, what the CLI does before it builds.
flog(type: string, message: string): void
Prints a line the way mothwing's own are, [ HTML ] 2026-01-01 12:00:00 message, for hooks to report in.
fraw(value: string): Html
Marks a string as HTML already, for html... to put in without escaping. Only for HTML you trust.
frenderSite(
site: Site,
{ only }?: { only?: Set<string>; }
): Promise<{ deps: Record<string, string[]>; written: number; }>
Renders the pages into an existing build, as dev does after a change. With only, just those pages, and the sitemaps are left as they are.
fresolveConfig(config: Config, root: string): Site
Checks a config and fills in its defaults. An unknown option, or one without a domain, throws.
fslug(name: string): string
Makes a name safe for a URL, for the slugs of generated pages.
funescapeHtml(html: string): string
Undoes escapeHtml, for text that comes escaped, like the value of an attribute.
Types
Ttype Asset
No documentation
path: string- Its path in the build, "/search.json"
content: string | Uint8Array<ArrayBufferLike>- What's written
url: string- The path with a hash of the content, which changes when the content does: "/search.json?v=1a2b3c4d"
toString(): string- The URL, so {{ }} and html
... put it in as it is
Ttype Config
What a site's mothwing.config.js default exports. Only domain is needed. Paths are relative to src unless they say otherwise. The extras (minify to activeLinks) are off until asked for: true turns one on as it comes, an object with its own settings.
domain: string- "example.com", for the canonical URLs, sitemaps and CNAME
src?: string- The source folder, relative to the config. "src"
out?: string- The build folder, relative to the config. "dist"
pages?: string- The pages folder. "pages"
partials?: string- The partials folder, left out of the build. <x-html> takes a partial from anywhere in src, this is only the folder that isn't copied. "partials"
data?: string- The data folder, its files are in every page by their name: projects.json -> {{ projects }}. Left out of the build. "data"
notFound?: string- The 404 page, in the pages folder. Kept in the build's root, out of the sitemap. "404.html"
js?: JsConfig- The JS to bundle
sass?: Record<string, string>- Sass to compile, source to output: { "scss/index.scss": "css/index.css" }. Needs sass installed
exclude?: string[]- Folders left out of the build, on top of pages, partials and data: ["js", "scss"]
rerender?: string[]- Folders and files the pages read with fs, whose changes render every page again in dev. They can be outside src, "../README.md", and are watched too, Sass in them builds the CSS first. What the pages import, include or use from the data folder is followed on its own
seo?: SeoConfig- For <x-seo>
minify?: boolean- Minify the HTML of production builds: comments and the whitespace that doesn't show are taken out, and esbuild minifies the inline scripts and styles. The tags and their attributes stay as written
csp?: boolean | Record<string, string>- A Content-Security-Policy <meta> that allows only the site's own files, and its inline scripts by their hash. An object sets directives over the defaults: { "style-src": "'self' 'unsafe-inline'" }
sitemap?: boolean | SitemapConfig- sitemap.xml with every page, each dated by the last git commit to its files
robots?: boolean | RobotsConfig- robots.txt, allowing every crawler and pointing at the sitemap
cname?: boolean- A CNAME file with the domain, for GitHub Pages
activeLinks?: boolean | ActiveLink- aria-current="page" on links to the page they're on, "true" on links to its section
tags?: Record<string, TagFunction>- Your own tags: { "x-name": ({ attrs }) => "<b>html</b>" }
transforms?: Transform[]- Run on every page's HTML once its placeholders are filled
after?: Hook[]- Run once the pages are written
esbuild?: BuildOptions- esbuild options for every bundle, over mothwing's
Ttype JsConfig
Each file is bundled to the same path in the build, js/index.js -> /js/index.js.
scripts?: string[]- For <x-js src="..."/>, bundled on their own
modules?: string[]- For <x-js src="..." module/>, ES modules that share their common code in chunks
chunks?: string- Where the shared chunks go. A chunks folder next to the first module
Ttype RobotsConfig
What robots.txt turns away.
block?: string[]- Crawlers turned away from the whole site, by name
disallow?: string[]- Paths kept out of every crawler
Ttype Route
A page to write. Most come one to a file in the pages folder, a [name].html file gives one per item. Its props can have files, more files to write, by their path in the build.
source: string- "gathering/[item].html", relative to the pages folder
output: string- Where it goes in the build: "gathering/cedar-log/index.html"
url: string- "/gathering/cedar-log/"
props: Record<string, any>- Its own values, the data folder's are added when it's rendered
sources: string[]- Files its content comes from, relative to src, for the sitemap's lastmod
Ttype SeoConfig
What <x-seo> fills its tags with when a page doesn't say.
siteName?: string- Added to titles that fit, and the link previews' site name. The domain
locale?: string- "en_US"
image?: null | { src: string; width: number; height: number; alt: string; }- The link preview for pages without their own
maxTitle?: number- Titles longer than this leave out the site name, search results cut them off. 60
maxDescription?: number- Longer descriptions are cut at a word. 160
Ttype Site
What Config becomes after resolveConfig, and what tags, transforms and hooks get: every option filled in with its default, its folders absolute, and each extra either false or its settings.
domain: string- "example.com", for the canonical URLs, sitemaps and CNAME
partials: string- The partials folder, left out of the build. <x-html> takes a partial from anywhere in src, this is only the folder that isn't copied. "partials"
data: string- The data folder, its files are in every page by their name: projects.json -> {{ projects }}. Left out of the build. "data"
notFound: string- The 404 page, in the pages folder. Kept in the build's root, out of the sitemap. "404.html"
sass: Record<string, string>- Sass to compile, source to output: { "scss/index.scss": "css/index.css" }. Needs sass installed
rerender: string[]- Folders and files the pages read with fs, whose changes render every page again in dev. They can be outside src, "../README.md", and are watched too, Sass in them builds the CSS first. What the pages import, include or use from the data folder is followed on its own
minify: boolean- Minify the HTML of production builds: comments and the whitespace that doesn't show are taken out, and esbuild minifies the inline scripts and styles. The tags and their attributes stay as written
cname: boolean- A CNAME file with the domain, for GitHub Pages
tags: Record<string, TagFunction>- Your own tags: { "x-name": ({ attrs }) => "<b>html</b>" }
transforms: Transform[]- Run on every page's HTML once its placeholders are filled
after: Hook[]- Run once the pages are written
esbuild: BuildOptions- esbuild options for every bundle, over mothwing's
url: string- "https://example.com"
root: string- The config's folder
src: string- The source folder, absolute
out: string- The build folder, absolute
pages: string- The pages folder, absolute
exclude: string[]- Folders left out of the build, with pages, partials and data
js: Required<JsConfig>- The JS to bundle
seo: Required<SeoConfig>- For <x-seo>
csp: false | Record<string, string>- The Content-Security-Policy's directives
sitemap: false | Required<SitemapConfig>- sitemap.xml
robots: false | Required<RobotsConfig>- robots.txt
activeLinks: false | ActiveLink- aria-current on links to the page they're on and to its section
Ttype SitemapConfig
How sitemap.xml is split and dated.
sections?: string[]- Sections that get a sitemap of their own behind a sitemap index, the rest share sitemap-pages.xml. Without any, sitemap.xml has every page itself
dates?: boolean- Date each page by the last git commit to its files. true
Callback types
cbActiveLink(
href: string,
route: Route
): false | "page" | "section" | undefined
Decides what a link on a page is to it: "page" for the page itself, "section" for a section it's in, false for neither. undefined leaves it to the default.
cbHook(build: { site: Site; routes: Route[]; dev: boolean; }): any
Run once the pages are written, dev is true on dev renders.
cbTagFunction(
tag: { attrs: Record<string, string | true>; route: Route; site: Site; }
): string | string[]
Returns the HTML a tag turns into. A list is one line each, indented like the tag.
cbTransform(html: string, route: Route, site: Site): string
Run on every page's HTML once its placeholders are filled, returns the HTML to write.