UY-lang is an embedded scripting language for Rust that makes defining HTML templates easy.
This is an early stage prototype. Do not use in production.
UY-lang has two primary goals:
- Provide templating engine for your web apps
- Add interactivity to your static HTML (only when needed)
- Embedded: Parse and evaluate HTML templates from your Rust application.
- Static by default: JS is needed only if you use interactive components on the page.
- JSX support out-of-the-box: Write plain HTML.
- Human-readable JS: Interactive components are compiled to a human-readable JavaScript.
- Lightweight: UY-lang brings only a couple of extra dependencies to your project.
First define your templates:
import { useState } from "preact/hooks";
// Define our IndexPage. JSX support is built-in. You can write HTML as is!
export fn IndexPage() {
<html>
<head>
<meta charset="utf-8" />
<title>Minimal example</title>
</head>
<body>
<h1>Click on the button below!</h1>
<main>
<Button initial={0} />
</main>
</body>
</html>
}
// Define an interactive component. Up until this point our HTML was static.
// UY-lang knows where you need interactivity and will compile only relevant parts to JS.
fn Button(props) {
let [clicks, setClicks] = useState(props.initial);
<button type="button" onClick={|| setClicks(clicks + 1)}>
Clicks: {clicks}
</button>
}
Now from Rust:
let conf = uylang::Config {
import_map: HashMap::from([
("preact", "https://esm.sh/[email protected]"),
("preact/", "https://esm.sh/[email protected]/"),
]),
bundle_path: Some("assets/uy-bundle.js".into()), // Server should serve this file
};
// Parse our source file
let module = uylang::import("index.uy", conf)?;
// Compile UY-lang code to JS and store the file on disk.
module.save_js_bundle()?;
// Get HTML string
let html = module.render("IndexPage")?;
This repo has more examples. You can run them locally with:
cargo run -p example-axum-minimal
cargo run -p example-axum-todomvc
- Blocks
- For loop
- Match (switch replacement)
- elseif branch (syntax sugar)
- try/catch
- Elvis operator (?.)
- Support async/await (for HTML rendering just ignore it)
- Destructuring
- Arrays
- Objects
- Allow in function arguments
- Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#rest_property
- Spread operator (...)
- In Arrays
- In Objects
- Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
- Define global methods
- Array
- Object
- Number
- Math
- fetch/setTimeout/... (Window methods)
- globalThis
- String
- Template literal
- Quotes
- JSX
- Generate random ID when hydrating
- to_json: Escape quotes
- useEffect hook
- JS compilation
- Convert if expressions to JS statements
- Convert block expressions to JS statements
- Escape quotes in strings
- Make semicolon optional after blocks
- Bundle JS dependencies
- JS compatibility:
- JS doesn't allow redeclaring variables with let.
- Keywords and reserved words
- Preact Context
- How to identify interactive components?
- Usage of any hooks and "on.." event listener attributes?
- Multiple modules (import from other files)
- Tree-sitter parser
- Syntax highlighting (GitHub and editors)
- Source maps
- Hot-code reload
- CSS
- Compile time safety when calling UY-lang's functions from Rust
- Optional type-safety
- Testing
- Untie from Preact
- Stream HTML
- Use references in EvaluatedModule
- Remove clones
- smallvec: store small vectors on the stack
- smol_str: store short strings on the stack