Skip to main content

LUAT Templating

LUAT (Lua Templates) is Wunderframe's powerful server-side templating engine inspired by Svelte. It compiles .luat files into efficient Lua modules that render HTML entirely on the server.

What is LUAT?

LUAT brings Svelte-like component architecture to server-side rendering with:

  • 📝 Familiar syntax - {#if}, {#each}, components with props and children
  • ⚡ High performance - Templates compile to optimized Lua code
  • 🔒 Secure by default - Automatic HTML escaping and sensitive content handling
  • 🧩 Component system - Reusable components with props and children
  • 🔄 No hydration - Pure server-side rendering for blazing-fast load times

Core Concepts

Templates

Files with .luat extension containing HTML markup with embedded Lua expressions:

<!-- Hero.luat -->
<div class="hero">
<h1>{props.title}</h1>
<p>{props.subtitle}</p>
</div>

Components

Reusable template modules that can be imported and used like HTML elements:

<!-- Page.luat -->
<script>
local Hero = require("components/Hero")
</script>

<div class="page">
<Hero title="Welcome" subtitle="Get started with LUAT" />
</div>

Script Blocks

Two types of script execution contexts:

  • <script> - Runs on every render, for importing components and preparing data
  • <script module> - Runs once when module loads, for exports and utilities

Quick Start

1. Install the CLI

npm install -g @solutas/wunder-cli

2. Initialize a Project

wunder init my-project
cd my-project

3. Create Your First Template

Create lib/components/Hello.luat:

<script>
local name = props.name or "World"
</script>

<div class="greeting">
<h1>Hello, {name}!</h1>
<p>Welcome to LUAT templating</p>
</div>

4. Use in a Page

Create lib/pages/Home.luat:

<script>
local Hello = require("lib/components/Hello")
</script>

<html>
<head>
<title>My LUAT App</title>
</head>
<body>
<Hello name="Developer" />
</body>
</html>

5. Bundle and Run

# Bundle templates
wunder bundle

# Start development server
wunder dev

Template Structure

Every LUAT template follows this structure:

<!-- Optional module script (runs once) -->
<script module>
local type = "component:hero"
exports.type = type
</script>

<!-- Regular script (runs on each render) -->
<script>
local Helper = require("lib/utils/helper")
local title = props.title or "Default Title"
</script>

<!-- HTML markup with expressions -->
<div class="component">
<h1>{title}</h1>
{@render props.children?.()}
</div>

What's Next?