boxlang-ssg
A static site powered by a BoxLang single-file static site generator. The build logic lives in ssg.bx
and turns Markdown (.md
) and BoxLang markup (.bxm
) files that contain front matter into a full _site/
output.
Features
- Lightweight CLI:
build
,list
, andhelp
- Markdown and
.bxm
templates with YAML front matter - Layouts, views, and partials under
_includes/
- Collections for pages, posts, tags, plus JSON data from
_data/
- Flexible permalinks, custom extensions, passthrough assets, and pagination-aware navigation
Prerequisites
- BoxLang runtime and CLI (
boxlang
on your PATH) - Modules listed in
requirements.txt
:bx-jsoup
,[email protected]
,bx-yaml
Install modules with the helper script:
boxlang setup.bx
or manually:
install-bx-module bx-jsoup [email protected] bx-yaml
Building
boxlang ssg.bx build
Build artifacts land in _site/
(configurable in ssg-config.json
). Use boxlang ssg.bx list
to inspect which documents were discovered.
Project layout
ssg.bx
– CLI entry point and build pipelinesetup.bx
– installs required modules fromrequirements.txt
ssg-config.json
– output directory, passthrough, and ignore lists_includes/
– layouts, views, and partials (e.g._includes/layouts/main.bxm
)_data/
– optional global JSON data loaded intocollections.global
posts/
– example contentassets/
– copied straight through to_site/
index.bxm
,tags.bxm
, etc. – sample templates that demonstrate pagination and collections
Authoring content
Files may include front matter to control metadata and output:
---
layout: main
type: post
permalink: /blog/{{slug}}/
title: My Post
description: Short summary
tags:
- cfml
published: true
---
Important front matter keys:
type
aligns items with views and collectionslayout
chooses a layout from_includes/layouts
view
forces a specific view; defaults totype
when availablepermalink
overrides the generated URL so you can opt into pagination placeholdersfileExt
customises the written extension (XML, JSON, etc.)pagination
enables paginated output (see next section)
Collections are exposed to templates as collections.*
. Posts gain tag metadata (collections.tags
, collections.byTag
) and _data/*.json
files become nested structures inside collections.global
.
Pagination
Pagination is handled entirely inside processPagination()
and applies to any template whose front matter includes a pagination
block. The pagination
struct supports:
data
(required): may be an array supplied directly in front matter or a string pointing to data in scope (e.g.collections.post
,collections.global.products
). Strings are resolved viastructGet
, and when the resolved value is a struct the keys are paginated alphabetically.size
(optional, default1
): number of items per page. Multi-item pagination (size > 1
) returns arrays; single-item pagination (size == 1
) emits one template per item.alias
(optional): name used to expose the paged value in the page PRC. When omitted the value is available asprc.pagedData
.
Examples cover URL outcomes for placeholder, fixed, and implicit permalinks. Key behaviors are:
- If a parent permalink contains
{{page}}
or{{pageNumber}}
, the first page uses the canonical permalink with placeholders removed, while pages ≥2 substitute the page number. - Without page placeholders, pages ≥2 fall back to
page/<n>/
under the same base directory. If no permalink is declared,/<fileSlug>/
is used as the base. - For single-item paginators that declare an
alias
, the alias placeholder (e.g.{{tag}}
) is replaced with the value for each item instead of adding page numbers.
Each generated page receives navigation metadata in prc.paginationInfo
, shaped as:
{
pageNumber: 2,
pageSize: 6,
totalPages: 5,
totalItems: 30,
href: {
current: "/blog/page/2/",
previous: "/blog/",
next: "/blog/page/3/",
first: "/blog/",
last: "/blog/page/5/"
},
pages: [
{ "number": 1, "href": "/blog/", "current": false },
{ "number": 2, "href": "/blog/page/2/", "current": true }
]
}
This metadata powers the navigation in index.bxm
, which reads prc.pagedData
(or the alias) for items and prc.paginationInfo.pages
to build an accessible pager. The paginator also merges data automatically when the data
source is a struct: for each key, the corresponding struct value is appended to the per-page PRC so templates can use the expanded record.
Configuration
ssg-config.json
controls output settings:
{
"outputDir": "_site",
"passthru": ["router.bxs", "assets"],
"ignore": []
}
outputDir
is purged on each build. Any entries in passthru
are copied verbatim, and additional ignore rules may be added to skip discovery.