Recipes
Quick solutions for common jstatico tasks.
Recipe: RSS Feed Generator
Create blog/feed.processor.js:
export default function(tree, context) {
const posts = Object.entries(tree.blog || {})
.filter(([key, val]) => val.meta && !key.includes('processor'))
.map(([key, post]) => ({
title: post.meta.title,
date: post.meta.date,
url: `/blog/${key}/`
}))
.sort((a, b) => new Date(b.date) - new Date(a.date));
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>My Blog</title>
<link>https://example.com</link>
${posts.map(p => `
<item>
<title>${p.title}</title>
<link>https://example.com${p.url}</link>
<pubDate>${new Date(p.date).toUTCString()}</pubDate>
</item>`).join('')}
</channel>
</rss>`;
return {
path: 'blog/feed.xml',
content: xml,
meta: {}
};
}Recipe: Sitemap Generator
Create sitemap.processor.js:
export default function(tree, context) {
const urls = [];
function walk(node, path = '') {
for (const [key, value] of Object.entries(node)) {
if (key.startsWith('_')) continue;
if (value.meta) {
urls.push(`https://example.com${path}/${key}/`);
} else if (typeof value === 'object') {
walk(value, `${path}/${key}`);
}
}
}
walk(tree);
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.map(url => ` <url><loc>${url}</loc></url>`).join('\n')}
</urlset>`;
return {
path: 'sitemap.xml',
content: xml,
meta: {}
};
}Recipe: Tag Pages
Create blog/tags.processor.js:
export default function(tree, context) {
const tagMap = {};
for (const [key, post] of Object.entries(tree.blog || {})) {
if (!post.meta?.tags) continue;
for (const tag of post.meta.tags) {
if (!tagMap[tag]) tagMap[tag] = [];
tagMap[tag].push({ key, ...post.meta });
}
}
return Object.entries(tagMap).map(([tag, posts]) => ({
path: `blog/tags/${tag}/index.html`,
content: `<h1>Posts tagged "${tag}"</h1>
<ul>
${posts.map(p => `<li><a href="/blog/${p.key}/">${p.title}</a></li>`).join('\n')}
</ul>`,
meta: { title: `Tag: ${tag}` }
}));
}Recipe: Reading Time
Create _processors/preprocessors/readingTime.ts:
import type { Preprocessor, ProcessResult } from 'jstatico';
export const processor: Preprocessor = {
name: 'reading-time',
match: /\.md$/,
process: function(): ProcessResult {
const content = this.getContent();
const words = content.split(/\s+/).length;
const minutes = Math.ceil(words / 200);
return {
meta: {
...this.meta,
readingTime: `${minutes} min read`
}
};
}
};Use in templates:
<span>{{ meta.readingTime }}</span>