Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

🔏 A safe and simple template engine with the ergonomics of JSX

License

NotificationsYou must be signed in to change notification settings

iCodeIN/render.rs

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🔏 A safe and simple template engine with the ergonomics of JSX

render itself is a combination of traits, structs and macros that together unify andboost the experience of composing tree-shaped data structures. This works best with HTML andXML rendering, but can work with other usages as well, like ReasonML'sPastel library for terminal colors.

How?

A renderable component is a struct that implements theRender trait. Thereare multiple macros that provide a better experience implementing Renderable:

  • #[component] for defining components using a function
  • rsx! for composing elements with JSX ergonomics
  • html! for composing elements and render them to a string

Why is this different from...

handlebars?

Handlebars is an awesome spec that lets us devs define templates and workseemlessly between languages and frameworks. Unfortunately, it does not guarantee any of Rust'stype-safety, due to its spec. This forces you to write tests for validating types for your views, like you would in a dynamically typed language. These tests weren't necessary in a type-safe language like Rust — but Handlebars is JSON-oriented, which doesn't comply Rust's type system.

render provides the same level of type-safety Rust provides, with no compromises ofergonomics or speed.

typed-html?

typed-html is a wonderful library. Unfortunately, it focused its power in strictness of the HTML spec itself, and doesn't allow arbitrary compositions of custom elements.

render takes a different approach. For now, HTML is not typed at all. It can get any key and get any string value. The main focus is custom components, so you can create a composable and declarative template with no runtime errors.

Usage

Simple HTML rendering

In order to render a simple HTML fragment into aString, use thersx! macro to generate acomponent tree, and callrender on it:

use render::{rsx,Render};let tree =rsx!{  <div>    <h1>{"Hello!"}</h1>    <p>{"Hello world!"}</p>  </div>};assert_eq!(tree.render(),"<div><h1>Hello!</h1><p>Hello world!</p></div>");

Because this is so common, there's another macro calledhtml! that callsrsx! to generatea component tree, and then callsrender on it. Most of the time, you'll find yourself usingthersx! macro to compose arbitrary components, and only callinghtml! when you need aString output, when sending a response or generating a Markdown file.

In Render, attributes and plain strings are escaped using therender::html_escaping module. In order touse un-escaped values so you can dangerously insert raw HTML, use theraw! macro around yourstring:

use render::{html, raw};let tree =html!{  <div>    <p>{"<Hello />"}</p>    <p>{raw!("<Hello />")}</p>  </div>};assert_eq!(tree,"<div><p>&lt;Hello /&gt;</p><p><Hello /></p></div>");

Custom components

Render's greatest ability is to provide type-safety along with custom renderable components.Introducing new components is as easy as defining a function that returns aRender value.

In order to build up components from other components or HTML nodes, you can use thersx!macro, which generates aRender component tree:

use render::{component, rsx, html};#[component]fnHeading<'title>(title:&'titlestr){rsx!{ <h1 class={"title"}>{title}</h1>}}let rendered_html =html!{  <Heading title={"Hello world!"} />};assert_eq!(rendered_html,r#"<h1>Hello world!</h1>"#);

If you pay close attention, you see that the functionHeading is:

  • declared with an uppercase. Underneath, it generates a struct with the same name, andimplements theRender trait on it.
  • does not have a return type. This is because everything is written to a writer, forperformance reasons.

Visibility & Component Libraries

Often you're going to want to store your components somewhere else in yourproject tree other than the module you're working on (if not in a differentmodule entirely!). In these cases, the visibility applied top the function thatdefines your component will flow down into all fields of that struct.

For example, if we add "pub" to the front of our Heading component above:

#[component]pubfnHeading<'title>(title:&'titlestr){rsx!{ <h1 class={"title"}>{title}</h1>}}

...the struct that is generated would look something like...

pubstructHeading{pubtitle:&'titlestr}

This is important to understand from a safety point of view when structuringyour libraries.

Full example

// A simple HTML 5 doctype declarationuse render::html::HTML5Doctype;use render::{// A macro to create components    component,// A macro to compose components in JSX fashion    rsx,// A macro to render components in JSX fashion    html,// A trait for custom componentsRender,};// This can be any layout we want#[component]fnPage<'a,Children:Render>(title:&'astr,children:Children){rsx!{     <>       <HTML5Doctype />       <html>         <head><title>{title}</title></head>         <body>{children}         </body>       </html>     </>}}// This can be a route in Rocket, the web framework,// for instance.pubfnsome_page(user_name:&str) ->String{html!{      <Page title={"Home"}>{format!("Welcome, {}", user_name)}      </Page>}}

License: MIT

About

🔏 A safe and simple template engine with the ergonomics of JSX

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Rust100.0%

[8]ページ先頭

©2009-2025 Movatter.jp