Static Site

LiteNode can render your app to plain HTML files — no server required to host them. You run a build script once, and the output is a folder of HTML, CSS, and JS files ready to deploy anywhere.

How it works

LiteNode's renderToFile(template, data, outputPath) method does the same thing as res.render() but writes the result to a file instead of sending it to a browser. You call it for each page and the _site/ directory fills up with the static equivalents.

Create the build script

This section provides an example of how to write a build script. The script will vary depending on the application's structure and the features being added.

Create functions/build.js:

import { app, marked } from "./initialize.js"
import { buildMenu } from "./buildMenu.js"
import { cp, mkdir, rm } from "node:fs/promises"

// Parse everything once
const index = app.parseMarkdownFile("index.md")
const pages = await app.parseMarkdownFileS("markdown")
const grouped = await app.groupByMarkdownProperty(
    "markdown",
    ["metadata.category", "metadata.catIndex", "metadata.subcategory", "metadata.subCatIndex", "href"],
    "metadata.category",
)
const mainMenu = buildMenu(grouped)

async function build() {
    // Clean previous output
    await rm("_site", { recursive: true, force: true })

    // Create directories
    await mkdir("_site/static", { recursive: true })
    await mkdir("_site/tutorial", { recursive: true })

    // Copy static assets
    await cp("static", "_site/static", { recursive: true })

    // Build each page
    await buildHomepage()
    await buildTutorialPages()
    await build404()

    console.log("✓ Built to _site/")
}

async function buildHomepage() {
    const html_content = marked.parse(index.content)
    const { title, description } = index.frontmatter

    await app.renderToFile(
        "layouts/index.html",
        { title, description, html_content, entryRoute: true },
        "_site/index.html",
    )
}

async function buildTutorialPages() {
    for (const page of pages) {
        const { href, title, description } = page.frontmatter
        await mkdir(`_site/tutorial/${href}`, { recursive: true })

        const html_content = marked.parse(page.content)
        const html_toc = app.generateTOC(html_content)

        await app.renderToFile(
            "layouts/index.html",
            { mainMenu, title, description, html_content, html_toc, tutorialRoute: true },
            `_site/tutorial/${href}/index.html`,
        )
    }
}

async function build404() {
    await app.renderToFile(
        "layouts/index.html",
        { title: "Page Not Found", description: "Page not found.", notFoundRoute: true },
        "_site/404.html",
    )
}

await build()

Add the build script to package.json

"scripts": {
  "build": "node functions/build.js"
}

Run the build:

npm run build

Output structure

_site/
├── index.html
├── 404.html
├── tutorial/
│   ├── installation/
│   │   └── index.html
│   ├── basic-usage/
│   │   └── index.html
│   └── ...
└── static/
    └── css/
        └── app.css

Each tutorial page gets its own directory so clean URLs work without a server rewriting them.

Preview locally

Install the Live Server extension in VS Code, right-click _site/index.html, and select Open with Live Server. Or use any static file server:

npx serve _site

Deploy

Any static hosting platform can serve the _site/ directory:

The build takes under a second for a project this size, so CI/CD pipelines on any of these platforms will feel instant.