@chronocide/spider
v10.2.1
Published
Tiny static site generator
Readme
spider is a tiny static site generator (SSR) meant for small websites. It uses a modular plugin system for maximum flexibility.
Features
- No dependencies
- No templating language, uses plain JS/TS
- Modular loaders, allowing any file type to be used
- By default, loads
.ts,.jsand.mdfiles
- By default, loads
- Flexible API, every page has full access to the whole website allowing for the creation of RSS feeds, collection pages, etc.
- Sensible defaults
- File URL's are generated based on folder structure and title (
/<folder>/<title>) - Creation and update dates are truncated to days
- Output files are HTML
- File URL's are generated based on folder structure and title (
Getting Started
Installation
npm i @chronocide/spider -DExample
A quick example of how spider can be used to create a website.
src/about.ts
import type { Draft } from '@chronocide/spider';
const page: Draft = {
title: 'About',
body: () => 'This is my page'
};
export default page;build.ts
import Spider from '@chronocide/spark';
const spider = new Spider({
entryPoints: ['src/**/*.ts']
root: 'src',
outdir: 'build',
});
spider.build();Running the build script creates build/about/index.html:
node scripts/build.tsAPI
Registry
The registry contains a list (flat and tree) of page nodes. A node contains a page and references to its children. This allows for easy generation of RSS feeds, breadcrumbs and other patterns that require site structure information.
Some examples:
import type { Draft } from '@chronocide/spider';
const page: Draft = {
title: 'blogs',
body: registry => `<ul>${registry.get('/blogs/')?.children.map(child => {
const { url, title } = child.value;
return `<li><a href="${url}">${title}</a></li>`;
})}</ul>`
};
export default page;import type { Draft, Node, Page } from '@chronocide/spider';
const page: Draft = {
title: 'breadcrumbs',
body: registry => {
const breadcrumbs: Node<Page>[];
let current = registry.get('/a/b/c/');
while (current) {
breadcrumbs.push(current);
current = current.parent;
}
return `<nav aria-description="Breadcrumbs">
<ol>
${breadcrumbs.reverse().map((node, i) => `<li>
<a href=${node.value.url} ${i === breadcrumbs.length - 1 ? 'aria-current="page"' : ''}>${node.value.title}</a>
</li>`)}
</ol>
</nav>`;
}
};
export default page;import type { Draft, Node, Page } from '@chronocide/spider';
const page: Draft = {
title: 'sitemap',
body: registry => {
const render = (node: Node<Page>) => `<li>
<a href="${node.value.url}">${node.value.title}</a>
<ul>${node.children.map(render).join('')}</ul>
</li>`;
return `<ul>${render(registry.get('/')).join('')}</ul>`
}
};
export default page;Loader
Loaders are used to load different file types. By default, spider supports loading .js, .ts and .md files. Loaders can be created or overwritten. An example loader for .txt files:
import type { Loader } from '@chronocide/spider';
import fsp from 'fs/promises';
import path from 'path';
import Spider from '@chronocide/spider';
const loader: Loader = async file => {
const raw = await fsp.readFile(file, 'utf-8');
const { name } = path.parse(file);
return {
title: name,
description: null,
url: null,
ext: null,
created: null,
updated: null,
template: null,
body: () => raw
}
};
const spider = new Spider({
entryPoints: ['src/**/*.txt'],
root: 'src',
outdir: 'build',
loader: {
'.txt': loader
}
});
spider.build();URL / path resolution
File paths and url's are automatically generated, but can be overwritten manually. spider uses the following rules:
Path
/+index=>/index.html/+about=>/about/index.html/+about.html=>/about.html/+about.xml=>/about.xml/about+index=>/about/index.html/about+me=>/about/me/index.html/about+about=>/about/index.html/about+about.html=>/about/about.html/about+about.xml=>/about/about.xml
URL
/+index=>//+about=>/about//+about.html=>/about/+about.xml=>/about.xml/about+index=>/about//about+me=>/about/me//about+about=>/about//about+about.html=>/about/about/about+about.xml=>/about/about.xml
