├── .gitignore ├── Cargo.toml ├── README.md └── src ├── lib.rs └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "react" 3 | description = "React library for server-side rendering with Rust. Very early days, this doesn't do much yet." 4 | version = "0.1.0" 5 | authors = ["Cam Jackson "] 6 | repository = "https://github.com/camjackson/react-rs" 7 | readme = "README.md" 8 | keywords = ["react", "jsx", "html", "javascript"] 9 | license = "GPL-3.0" 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/) 2 | 3 | # react-rs 4 | React library for server-side rendering with Rust. Very early days, this doesn't do much yet. 5 | 6 | When it's done, this: 7 | ```rust 8 | react.Div { 9 | className: "hello", 10 | children: vec![react.Img { src: "world.jpg" }] 11 | }.render() 12 | ``` 13 | 14 | will return this: 15 | ```html 16 |
17 | ``` 18 | 19 | However, Instead of writing that very verbose Rust, you'll be able to use [jsx-rs](https://github.com/camjackson/jsx-rs). 20 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub trait Component { 2 | fn render(&self) -> String; 3 | } 4 | 5 | pub struct Div { 6 | pub children: Vec>, 7 | pub class_name: &'static str, 8 | } 9 | 10 | pub struct Img { 11 | pub src: &'static str, 12 | } 13 | 14 | impl Component for Div { 15 | fn render(&self) -> String { 16 | render_dom_component("div", self.props(), self.render_children()) 17 | } 18 | } 19 | 20 | impl Div { 21 | fn props(&self) -> String { 22 | let mut props = String::new(); 23 | if self.class_name.len() > 0 { 24 | props = props + &format!(" class=\"{}\"", self.class_name) 25 | } 26 | props 27 | } 28 | 29 | fn render_children(&self) -> String { 30 | self.children.iter().map(|child| { 31 | child.render() 32 | }).collect() 33 | } 34 | } 35 | 36 | impl Component for Img { 37 | fn render(&self) -> String { 38 | render_void_dom_component("img", self.props()) 39 | } 40 | } 41 | 42 | impl Img { 43 | fn props(&self) -> String { 44 | let mut props = String::new(); 45 | if self.src.len() > 0 { 46 | props = props + &format!(" src=\"{}\"", self.src) 47 | } 48 | props 49 | } 50 | } 51 | 52 | fn render_dom_component(name: &'static str, props: String, children: String) -> String { 53 | format!("<{}{}>{}", name, props, children, name) 54 | } 55 | 56 | fn render_void_dom_component(name: &'static str, props: String) -> String { 57 | format!("<{}{}/>", name, props) 58 | } 59 | 60 | #[test] 61 | fn it_renders_an_empty_div() { 62 | let div = Div { class_name: "", children: vec!() }; 63 | assert_eq!(div.render(), "
"); 64 | } 65 | 66 | #[test] 67 | fn it_renders_an_img() { 68 | let img = Img { src: "" }; 69 | assert_eq!(img.render(), ""); 70 | } 71 | 72 | #[test] 73 | fn it_renders_a_div_with_a_class() { 74 | let div = Div { class_name: "container", children: vec!() }; 75 | assert_eq!(div.render(), "
"); 76 | } 77 | 78 | #[test] 79 | fn it_renders_an_img_with_a_src() { 80 | let img = Img { src: "pic.jpg" }; 81 | assert_eq!(img.render(), ""); 82 | } 83 | 84 | #[test] 85 | fn it_renders_a_div_with_a_child_div() { 86 | let nested_div = Box::new(Div { class_name: "", children: vec!() }); 87 | let div = Div { class_name: "", children: vec!(nested_div) }; 88 | assert_eq!(div.render(), "
"); 89 | } 90 | 91 | #[test] 92 | fn it_renders_a_complicated_thing() { 93 | let div = Div {class_name: "container", children: vec!( 94 | Box::new(Div {class_name: "row", children: vec!( 95 | Box::new(Div {class_name: "col-md-4", children: vec!()}), 96 | Box::new(Div {class_name: "col-md-4 col-md-offset-4", children: vec!( 97 | Box::new(Img {src: "https://example.com/img.jpg"})) 98 | }) 99 | )}), 100 | Box::new(Div {class_name: "row", children: vec!( 101 | Box::new(Div {class_name: "col-md-6", children: vec!()}), 102 | Box::new(Div {class_name: "col-md-6", children: vec!()}) 103 | )}), 104 | )}; 105 | 106 | let dom = div.render(); 107 | 108 | assert_eq!(dom, concat!( 109 | "
", 110 | "
", 111 | "
", 112 | "
", 113 | "
", 114 | "", 115 | "
", 116 | "
", 117 | "
", 118 | "
", 119 | "
", 120 | "
", 121 | "
", 122 | "
", 123 | "
" 124 | )); 125 | } 126 | 127 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate react; 2 | 3 | use react::Component; 4 | 5 | fn main() { 6 | let div = react::Div { class_name: "container", children: Vec::new() }; 7 | 8 | println!("{}", div.render()); 9 | } 10 | --------------------------------------------------------------------------------