Templating

Right now everything lives in one index.html file. That works for a single page, but a real app has a header, footer, and a <head> block that every page shares. Copy-pasting them into every template is a maintenance problem.

LiteNode's built-in template engine (STE) solves this with two features: includes and variable injection.

Includes

The {{#include("path/to/file.html")}} directive embeds another template inline. The included file inherits the full data object of its parent — no extra plumbing required.

Variable injection

Double curly braces inject values from the data object you pass to res.render():

<title>{{title}}</title> <meta name="description" content="{{description}}" />

To inject raw HTML (like the converted Markdown content), prefix the property name with html_:

<main>{{html_content}}</main>

Restructure the views directory

Update your views/ directory to look like this:

views/
├── index.md
├── layouts/
│   └── index.html
└── components/
    ├── head.html
    ├── header.html
    ├── main.html
    └── footer.html

Write the components

views/components/head.html

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="{{description}}" />
    <title>{{title}} | My App</title>
</head>

views/components/header.html

<header>
    <a href="/">Home</a>
</header>

views/components/main.html

<main>{{html_content}}</main>

views/components/footer.html

<footer>
    <p>Built with LiteNode</p>
</footer>

Update the main layout

Replace the contents of views/layouts/index.html:

<!DOCTYPE html>
<html lang="en">
    {{#include("components/head.html")}}
    <body>
        {{#include("components/header.html")}}
        {{#include("components/main.html")}}
        {{#include("components/footer.html")}}
    </body>
</html>

Reload the browser. The page renders exactly as before, but now each part of the HTML lives in its own file. Now any change to header.html applies across every page that uses this layout.

Render multiple pages

Now that the template is modular, let's add support for multiple Markdown pages. Create a views/pages/ directory and add a few Markdown files. Each one needs a frontmatter href property — that's the URL slug for the page.

In index.js, add a dynamic route:

app.get("/page/:href", async (req, res) => {
    const pages = await app.parseMarkdownFileS("pages")

    const current = pages.find((file) => file.frontmatter.href === req.params.href)

    if (!current) {
        return res.status(404).txt("Page not found")
    }

    const { title, description } = current.frontmatter
    const html_content = marked.parse(current.content)

    res.render("layouts/index.html", { title, description, html_content })
})

parseMarkdownFileS (plural) reads an entire directory of Markdown files and returns them as an array. The route finds the one whose href matches the URL parameter.

Visit /page/your-file-name and each Markdown file renders through the same template.

The data object passed to a parent template is automatically available to all included templates. You don't need to pass data down manually.