all repos — archive/homestead @ f9fd0d795fb7bff10cb759f2300200d50b0fbab3

My future indieweb platform

feat: Streaming DOM templates via rheo

Alan Pearce
commit

f9fd0d795fb7bff10cb759f2300200d50b0fbab3

parent

4d6378483d46806d0006d6e5755e0eedd6372154

1 file changed, 57 insertions(+), 25 deletions(-)

changed files
M src/index.jssrc/index.js
@@ -3,6 +3,9 @@
const Koa = require('koa') const app = new Koa() +const fs = require('fs') +const streamify = require('stream-array') + const send = require('koa-send') const config = require('./modules/config.js')
@@ -12,51 +15,80 @@
const Router = require('koa-router') const router = new Router() -const view = require('koa-nunjucks-next') +const rheo = require('rheo') const Posts = require('./modules/posts.js') const posts = Posts.getFolder(config.posts.folder) -app.use( - view(`${__dirname}/views`, { - extname: 'njk', - globals: { - site: config.site, - url: (...args) => router.url(...args) - } - }) -) +const index = () => fs.createReadStream(`${__dirname}/templates/index.html`) + +function setTitle (pageTitle) { + return rheo.template(s => + s.inner('title', rheo((pageTitle ? ' · ' : '') + config.site.title)) + ) +} + +function renderPostListItem (template, [, post]) { + return template + .attribute('a', 'href', () => router.url('post', post.basename)) + .inner('a', () => rheo(post.data.get('title'))) +} + +function toArrayStream (iterator) { + return streamify(Array.from(iterator.entries())) +} -const postsArray = Array.from(posts.entries()) -router.get('home', '/', async function (ctx) { - await ctx.render('index', { - posts: postsArray - }) +const postsStream = toArrayStream(posts) +router.get('home', '/', async function (ctx, next) { + ctx.set('Content-Type', 'text/html') + ctx.body = index() + .pipe(rheo()) + .inner('body', pages => pages.find('main.homepage')) + .inner('h1', rheo(config.site.title)) + .inner('.posts', function (postsTemplate) { + return postsStream.pipe(postsTemplate.map(renderPostListItem)) + }) + .pipe(setTitle()) + .render() }) -router.get('post', '/post/:filename', async function (ctx) { +router.get('post', '/post/:filename', async function (ctx, next) { ctx.assert(posts.has(ctx.params.filename), 404, 'Post not found') const post = posts.get(ctx.params.filename) post.body = Posts.render(post) - await ctx.render('post', { - post: post - }) + + ctx.set('Content-Type', 'text/html') + ctx.body = index() + .pipe(rheo()) + .inner('body', pages => pages.find('main.post')) + .inner('article h1', rheo(post.data.get('title'))) + .inner('article main', rheo(post.body)) + .pipe(setTitle()) + .render() }) const taxonomies = Posts.taxonomise(config.taxonomies, posts) for (let [term, items] of taxonomies) { - router.get(`taxon-${term}`, `/${term}/:value`, async function (ctx) { + router.get(`taxon-${term}`, `/${term}/:value`, async function (ctx, next) { const value = ctx.params.value ctx.assert( items.has(ctx.params.value), 404, `Could not find ${term} ${value}` ) - await ctx.render('term', { - term: term, - [term]: value, - posts: items.get(ctx.params.value) - }) + + ctx.set('Content-Type', 'text/html') + ctx.body = index() + .pipe(rheo()) + .inner('body', pages => pages.find('main.taxon')) + .inner('h1', rheo(config.site.title)) + .inner('.posts', function (postsTemplate) { + return toArrayStream(items.get(value)).pipe( + postsTemplate.map(renderPostListItem) + ) + }) + .pipe(setTitle()) + .render() }) }