From 6f24dd523bee7fde869adfca17e0d5c66f0e5497 Mon Sep 17 00:00:00 2001
From: Joshua Bemenderfer
Date: Wed, 23 Sep 2020 20:37:34 -0400
Subject: [PATCH] Convert context to a factory.
---
components/Footer.js | 5 ++-
components/Header.js | 6 ++--
components/NavBar.js | 4 +--
pages/About.js | 12 +++----
pages/Home.js | 12 +++----
pages/Page.js | 4 +--
templater.js | 76 +++++++++++++++++++++-----------------------
7 files changed, 57 insertions(+), 62 deletions(-)
diff --git a/components/Footer.js b/components/Footer.js
index b3fa15c..6dc4595 100644
--- a/components/Footer.js
+++ b/components/Footer.js
@@ -40,8 +40,7 @@ const styles = css`
`
export async function Footer (ctx, { path, title }) {
- ctx.css.add(styles)
- ctx.body = await body(ctx, { path, title })
-
+ ctx.addCSS(styles)
+ ctx.setBody(await body(ctx, { path, title }))
return ctx
}
diff --git a/components/Header.js b/components/Header.js
index 7c3bfd6..9076a46 100644
--- a/components/Header.js
+++ b/components/Header.js
@@ -5,7 +5,7 @@ import base from '../styles/base.js'
const body = async (ctx, { path, title }) => html`
Title: ${sanitize(title)}
- ${await ctx.b(NavBar, { path })}
+ ${await ctx.renderBody(NavBar, { path })}
`
@@ -17,8 +17,8 @@ const styles = css`
`
export async function Header (ctx, { path, title }) {
- ctx.css.add(styles)
- ctx.body = await body(ctx, { path, title })
+ ctx.addCSS(styles)
+ ctx.setBody(await body(ctx, { path, title }))
return ctx
}
diff --git a/components/NavBar.js b/components/NavBar.js
index 2875c21..074e4cc 100644
--- a/components/NavBar.js
+++ b/components/NavBar.js
@@ -52,7 +52,7 @@ const styles = css`
`
export function NavBar (ctx, { path }) {
- ctx.css.add(styles)
- ctx.body = body(path)
+ ctx.addCSS(styles)
+ ctx.setBody(body(path))
return ctx
}
diff --git a/pages/About.js b/pages/About.js
index 176d7e9..8c5bbf8 100644
--- a/pages/About.js
+++ b/pages/About.js
@@ -8,7 +8,7 @@ const head = ({ title }) => html`
`
const body = async (ctx, { path, title }) => html`
- ${await ctx.b(Header, { path, title })}
+ ${await ctx.renderBody(Header, { path, title })}
About Page - ${sanitize(title)}
@@ -23,7 +23,7 @@ const body = async (ctx, { path, title }) => html`
- ${await ctx.b(Footer, { path, title })}
+ ${await ctx.renderBody(Footer, { path, title })}
`
const styles = css`
@@ -33,10 +33,10 @@ const styles = css`
`
export async function AboutPage (ctx, { path, title }) {
- ctx.css.add(base)
- ctx.css.add(styles)
- ctx.head.add(head({ title }))
- ctx.body = await body(ctx, { path, title })
+ ctx.addCSS(base)
+ ctx.addCSS(styles)
+ ctx.addHead(head({ title }))
+ ctx.setBody(await body(ctx, { path, title }))
return ctx
}
diff --git a/pages/Home.js b/pages/Home.js
index fdce832..cf9a8c3 100644
--- a/pages/Home.js
+++ b/pages/Home.js
@@ -8,7 +8,7 @@ const head = ({ title }) => html`
`
const body = async (ctx, { path, title }) => html`
- ${await ctx.b(Header, { path, title })}
+ ${await ctx.renderBody(Header, { path, title })}
Home Page - ${sanitize(title)}
@@ -17,7 +17,7 @@ const body = async (ctx, { path, title }) => html`
- ${await ctx.b(Footer, { path, title })}
+ ${await ctx.renderBody(Footer, { path, title })}
`
const styles = css`
@@ -27,10 +27,10 @@ const styles = css`
`
export async function HomePage (ctx, { path, title }) {
- ctx.css.add(base)
- ctx.css.add(styles)
- ctx.head.add(head({ title }))
- ctx.body = await body(ctx, { path, title })
+ ctx.addCSS(base)
+ ctx.addCSS(styles)
+ ctx.addHead(head({ title }))
+ ctx.setBody(await body(ctx, { path, title }))
return ctx
}
diff --git a/pages/Page.js b/pages/Page.js
index bd40e5f..d97f1ac 100644
--- a/pages/Page.js
+++ b/pages/Page.js
@@ -1,7 +1,7 @@
import { html, render } from '../templater.js'
async function Root (ctx, component, ...params) {
- const result = await ctx.render(component, ...params)
+ const result = await render(ctx, component, ...params)
const scripts = Array.from(result.js).join(';\n')
const css = Array.from(result.css).join('\n')
@@ -25,5 +25,5 @@ async function Root (ctx, component, ...params) {
}
export function page(component, ...params) {
- return render(Root, component, ...params)
+ return render(null, Root, component, ...params)
}
diff --git a/templater.js b/templater.js
index 470d0e5..f83ba81 100644
--- a/templater.js
+++ b/templater.js
@@ -13,29 +13,46 @@ export const css = tmpl
export const javascript = tmpl
// Stupid-simple "sanitization". Just enough for this demo, not for production.
-export function sanitize(str) {
+export function sanitize (str) {
if (typeof str !== 'string') return str
return str.split('<').join('<')
}
-// Shorthand to render a component and retrieve the body.
-async function b(component, ...params) {
- return (await this.render(component, ...params)).body
-}
+function contextFactory (parentCtx) {
+ const head = new Set()
+ const css = new Set()
+ const js = new Set()
+ let body = ''
-// Shorthand to render a component and retrieve the head.
-async function h(component, ...params) {
- return (await this.render(component, ...params)).head
-}
+ const addHead = str => {
+ head.add(str)
+ if (parentCtx) parentCtx.addHead(str)
+ }
+ const addCSS = str => {
+ css.add(str)
+ if (parentCtx) parentCtx.addCSS(str)
+ }
+ const addJS = str => {
+ js.add(str)
+ if (parentCtx) parentCtx.addJS(str)
+ }
+ const setBody = str => (body = str)
+ const renderBody = async (component, ...params) => {
+ debugger;
+ (await render(parentCtx, component, ...params)).body
+ }
-// Shorthand to render a component and retrieve the css.
-async function c(component, ...params) {
- return (await this.render(component, ...params)).css
-}
-
-// Shorthand to render a component and retrieve the js.
-async function j(component, ...params) {
- return (await this.render(component, ...params)).js
+ return {
+ head,
+ css,
+ js,
+ body,
+ renderBody,
+ addHead,
+ addCSS,
+ addJS,
+ setBody
+ }
}
/**
@@ -45,22 +62,9 @@ async function j(component, ...params) {
* @returns {Object}
* An object containing head elements, css, js, and body text returned by the rendered component.
*/
-export async function render(component, ...params) {
+export async function render (parentCtx, component, ...params) {
// Create a new context to pass to a component for each rendering.
- const ctx = {
- head: new Set(),
- css: new Set(),
- js: new Set(),
- body: null,
- }
- // Add render functions to the context object, bound to the current context.
- // This ensures any calls to render child components will have the parent context bound as "this", allowing copying
- // child render results into parent context without having to pass the parent context explicitly to every child component.
- ctx.render = render.bind(ctx)
- ctx.b = b.bind(ctx)
- ctx.h = h.bind(ctx)
- ctx.c = c.bind(ctx)
- ctx.j = j.bind(ctx)
+ const ctx = contextFactory(parentCtx)
// Attempt to load result from cache by component name and params.
const key = hash([component.name, params])
@@ -74,14 +78,6 @@ export async function render(component, ...params) {
// Store result to cache if it wasn't already present.
if (!stored) toCache(key, result)
- // Results with a parent context will copy child context fields into parent context.
- // This enables straightforward component-level caching of body, head, css, and js at the cost of higher memory usage.
- if (this) {
- result.head.forEach(r => this.head.add(r))
- result.css.forEach(r => this.css.add(r))
- result.js.forEach(r => this.js.add(r))
- }
-
// Return result context object to caller.
return result
}