Skip to content

Latest commit

 

History

History
166 lines (131 loc) · 4.77 KB

README.md

File metadata and controls

166 lines (131 loc) · 4.77 KB

UY-lang

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:

  1. Provide templating engine for your web apps
  2. Add interactivity to your static HTML (only when needed)

Features

  • 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.

Example

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

Language features

  • Blocks
    • For loop
    • Match (switch replacement)
    • elseif branch (syntax sugar)
    • try/catch
  • Elvis operator (?.)
  • Support async/await (for HTML rendering just ignore it)
  • Destructuring
  • Spread operator (...)
  • 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?

Future

  • 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

Potential optimizations

References