@funcstache/funcstache
v0.1.19
Published
A JavaScript library to render mustache templates into documents. For example, webpages that are dynamically generated on a server.
Readme
funcstache
A JavaScript library to render Mustache templates into documents. For example, webpages that are dynamically generated on a server.
- File-based routing.
- Stream-based to deliver a rendered document as quickly as possible.
- Defined interfaces and conventions that simplify document rendering.
The proven pattern of rendered templates, combined with modern JavaScript capabilities, plus some conventions, to simplify rendering documents dynamically.
Contents
Usage
You'll need to create an instance of a Renderer to do the work of creating web pages. First create the options to pass to the Renderer.
const options: WebRendererOptions<ModuleState> = {
indexDirectory,
moduleState,
path: requestUrl.pathname,
rootDirectory,
};Then create an instance of the Renderer.
const renderer = new Renderer(options);
renderer
.render(Writable.toWeb(stream))
.then(() => {
stream.end();
})
.catch((err) => {
stream.end();
});You may notice the stream argument of renderer.render(Writable.toWeb(stream)) and be wondering
where stream comes from; it's the destination stream where the rendered template output will be
written (note that this is a web
WritableStream - not NodeJs's native
WritableStream). This stream comes from the surrounding environment. For example, in KOA this is the
value of context.body. If using a framework look for documentation that describes how to return a
stream in the response.
See the apps in the repo for more examples of how to create an instance of a Renderer.
File-based routing
funcstache uses two different files to render a document:
- A JavaScript file - known as a module file - that:
- must return a path to the Mustache file to be rendered
- optionally returns context information to be used when rendering the document
- A Mustache template file that defines the document to be rendered.
[!NOTE] The module file could also be a TypeScript file if you are using Deno or some other runtime that supports TypeScript. The module file extension is set separately in the RendererOptions options.
Here's a simple example of an index and Mustache file inside a directory named "root."
root/
├── index.js
└── main.mustacheThe module file
[!NOTE] The example code is written in TypeScript to illustrate the interfaces and types available to developers.
The module file (index.js) implements the FuncStacheModule interface, defining the Mustache template to render and the context associated with that template to be used during the rendering process.
context returns an object whose keys will be matched to Tag
keys in the Mustache template and the value will
replace the tag. The type of a context property value varies depending on the tag type. See
stache-stream documentation.
The template function returns information about the template to be rendered either:
- a string that is the name of the template - without a file extension - the name must refer to a file with the same name in the same directory as the module file
- a tuple with two elements: first the name of the template file and second a path to the directory where the template file is located; the path is relative to the location of the module file.
/*
root/index.ts
*/
import { type FuncStacheModule } from "@funcstache/funcstache";
export const { context, template }: FuncStacheModule<ModuleState> = {
context: async (options: Options<ModuleState> | WebOptions<ModuleState>): Promise<Record<string, ContextTypes>> => ({
title: "Hello World",
}),
template: async (options: Options<ModuleState> | WebOptions<ModuleState>): Promise<TemplateName> => ["layout", "./layouts/default/layout"],
};Mustache template
Mustache templates are text files with optional tags that follow the rules defined by the Mustache standards.
<!--
root/main.mustache
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>{{title}}</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
</head>
<body>
<p>Hello funcstache!</p>
</body>
</html>Notice that this template has one variable tag {{title}} that will be replaced by context data.
Rendering the document
When created a Renderer instance is passed a fully-qualified path to a file system directory, this
is known as the "root directory." funcstache will be able to traverse all the directories and files
under the root. The root directory must contain a module file (index.js). funcstache will read
the module file to determine which template to render at the root.
After the Renderer is created invoke the asynchronous render function to begin transforming a
Mustache file and writing the output to the provided stream.
import { Renderer } from "@funcstache/funcstache";
const options: WebRendererOptions<ModuleState> = {
indexDirectory: ".",
moduleState: {},
path: "/",
rootDirectory: "/home/user/funcstache/root"
};
const renderer = new Renderer(options);
renderer
.render(Writable.toWeb(stream))
.then(() => {
stream.end();
})
.catch((err) => {
stream.end();
});After the files are processed, and a rendered document created, the contents of stream will be an
HTML document with the {{title}} tag replaced with the value of context's title property -
"Hello World".
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
</head>
<body>
<p>Hello funcstache!</p>
</body>
</html>Using these basic building blocks you can create complex templates composed of smaller individual - partial - templates.
Develop
Install
npm i @funcstache/funcstacheLogging
Logging can be set by adding an environment variable named LOG_LEVEL. The following values are
supported: "debug", "log", "warn", "error".
