Documentation
    Preparing search index...

    Module @funcstache/stache-stream - v0.3.3

    Streaming Mustache Template Rendering

    A Mustache template renderer for JavaScript focused on returning results as quickly as possible.

    This library renders a Mustache template as it's read, rather than loading the entire template into memory before processing. The values of tags in the Mustache template are rendered as soon as possible and written to the output stream.

    stache-stream is intended to be used as part of a server-side rendering platform that generates HTML, whose goal is to provide a superior Web user experience on all kinds of devices - especially devices with lower memory and CPU capabilities.

    Tip

    Use the funcstache library to begin rendering Mustache files into HTML documents. It provides:

    • file-based routing for a web server
    • conventions for creating Mustache templates and context
    • defined interfaces for creating context for different types of tags

    The library is constructed to maximize asynchronous processing of a Mustache template and streaming the result to a client as quickly as possible.

    • Input is a ReadableStream created with a Mustache template, for example, from a string or a file.
    • Context that prefers the use of async functions (lambdas) to provide the data rendered into the template.
    • A WritableStream that will receive the rendered template output.

    This functionality is wrapped in a StacheTransformStream that implements a NodeJS TransformStream.

    The components that comprise a StacheTransformStream instance process a Mustache template in this order:

    ReadableStream -> (Parse → Tokenize → Queue → Template) → WritableStream
    

    When using a StacheTransformStream you will need to provide a Mustache template in the source ReadableStream and options that include the ContextProvider to be used to render data into the template.

    The following example includes a template with two variables that are replaced. The output illustrates how chunks are written to the output as they become available.

    // Mustache template provided by `readable` (a ReadableStream):
    // "Dear {{title}} {{name}},\n\nYou may already be a winner!"

    const stacheTransformStream = new StacheTransformStream({
    contextProvider: {
    context: { name: "Alice Brown" },
    getContextValue: async (tag) => (tag.key === "title" ? "Doctor" : ""),
    },
    });

    for await (const chunk of readable.pipeThrough(stacheTransformStream)) {
    await writable.getWriter().write(chunk);
    }

    // Writable stream output chunks:
    // "Dear "
    // "Doctor"
    // " "
    // "Alice Brown"
    // ",\n\nYou may already be a winner!"

    A more complex example renders a partial tag by reading the partial's replacement - another mustache template - from a file. The replacement template has a variable for the current date which named newsItemDate which is replaced with a value from newsItem's parent's context.

    // Mustache template provided by `readable` (a ReadableStream):
    // "<article>Latest news: {{ >newsItem }}</article>"

    // `newsItem` template:
    // "<p>As of {{newsItemDate}} - in the news...</p>"

    const stacheTransformStream = new StacheTransformStream({
    contextProvider: {
    context: {
    newsItemDate: new Date().toString(),
    newsItem: async (tag: Tag): Promise<ReadableStream> => {
    const fileName = "latest-news-item.mustache";
    const file = fs.createReadStream(fileName, { encoding: "utf-8" });
    return ReadableStream.from(file);
    },
    },
    },
    });

    for await (const chunk of readable.pipeThrough(stacheTransformStream)) {
    await writable.getWriter().write(chunk);
    }

    The previous example is trivial and a little silly, but being able to render a template containing HTML and write it to an output stream as soon as possible can have significant performance improvements for display in a web browser. Consider the following pseudo-code for a Mustache template that outputs a complete HTML file.

    <!-- HTML with embedded Mustache tags. -->

    <html>
    <head>
    <!-- load CSS files and other assets -->
    <link rel="stylesheet" href="styles.css" />
    </head>
    <body>
    <!--
    The content for the page at this route is generated dynamically, maybe it's a table with data
    that varies depending on the search params...
    -->
    <section>{{>aboveTheFoldContent}}</section>
    <section>{{>content}}</section>
    </body>
    </html>

    When rendered using stache-stream all the content up to the {{>content}} partial tag is sent to the browser immediately. Browsers will parse streamed response data as it arrives and where possible will begin to render the web page. In the case of a head tag with CSS and other assets the browser will begin to download those assets in the background as soon as they are parsed. This is a main goal of stache-stream to improve the experience in a browser by allowing web pages to load and render more quickly.

    We can also break the page content into separate blocks - for example, content that appears "above the fold" will be transformed on the server and sent down as soon as that is complete, without waiting for the rest of the content to be rendered. THis can be especially helpful when display data is fetched from storage.

    Context

    Context
    PartialTagContextLambda
    PartialTagContextLambdaResult
    SectionTagCallback
    SectionTagContextRecord
    VariableTagContextLambda
    VariableTagContextRecord
    ContextTypes
    PartialTagContext
    SectionTagContext
    VariableTagContext
    VariableTagContextPrimitive

    Other

    StacheTransformStream
    ContextProvider
    Tag
    JsonType
    TemplateName

    Partial

    PartialTagContextLambda
    PartialTagContextLambdaResult
    PartialTagContext

    Section

    SectionTagCallback
    SectionTagContextRecord
    SectionTagContext

    Variable

    VariableTagContextLambda
    VariableTagContextRecord
    VariableTagContext
    VariableTagContextPrimitive