Build your own react in rust.

ยท

5 min read

Introduction

In this blog I am going through on how can you make your own react like library (Or I should say framework because rust won't be so lenient on you๐Ÿคฃ), In this blog I'll be showing you JavaScript and Rust code examples side by side.

Disclaimer

This is not an end-to-end clone of react I'll just be showcasing how react puts stuff inside html and how will rust do. and will not cover how it updates current present data in webpage.

Inspiration

Inspiration for this blog is from

and my motivation to not write JS ๐Ÿ˜ฃ

Hello World.

Hello World in react.

Default react app.

first let's take a look at default react app. for this first make a folder and inside that folder do

 create-react-app ./

here is how folder structure will look like

react-hello/
โ”œโ”€โ”€ .gitignore
โ”œโ”€โ”€ package-lock.json
โ”œโ”€โ”€ package.json
โ”œโ”€โ”€ public/
|  โ”œโ”€โ”€ favicon.ico
|  โ”œโ”€โ”€ index.html
|  โ”œโ”€โ”€ logo192.png
|  โ”œโ”€โ”€ logo512.png
|  โ”œโ”€โ”€ manifest.json
|  โ””โ”€โ”€ robots.txt
โ”œโ”€โ”€ README.md
โ””โ”€โ”€ src/
   โ”œโ”€โ”€ App.css
   โ”œโ”€โ”€ App.js
   โ”œโ”€โ”€ App.test.js
   โ”œโ”€โ”€ index.css
   โ”œโ”€โ”€ index.js
   โ”œโ”€โ”€ logo.svg
   โ”œโ”€โ”€ reportWebVitals.js
   โ””โ”€โ”€ setupTests.js

we are going to ignore most of the files and look at App.js, index.js and index.html

Here is what's happening in App.js we are just returning a html <h1> tag that has Hello World! in it.


// scr/App.js
function App() {
  return (
      <h1>Hello World!</h1>
  );
}

export default App;

Here is what's happening in index.js

// src/index.js
import ReactDOM from 'react-dom/client';
import App from './App';

const domRoot = document.getElementById('root');
const root = ReactDOM.createRoot(domRoot);
root.render(
    <App />
);
  • Writing our plan old JavaScript to get a html element which has an attribute id of name "root"

  • passing that html element in ReactDOM.createRoot() which will do all the fun stuff of react like making a "virtual-dom" and all comparison between new and old code.

  • rendering out <App /> component from root of ReactDOM.createRoot() function

lets look at index.html file.

<!--public/index.html-->
<html lang="en">
  <head>
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

there is one little magic going on of from where is this index.html file connected to index.js who's trick I'll tell you now. But for that first build your react app by doing

npm run build

after doing this go to your build/ folder you'll find a index.html file inside that build folder where there magic fails and they have to add script tag (you might notice that its not same index.js that we were editing, well its same same but different ๐Ÿคฃ it too is generated on running that build command.)

<script defer="defer" src="/static/js/main.67d6da4b.js">

Thats it thats how react works at its basic.

Custome React app

It's pretty much same as react app only we wont be passing our component in ReactDOM.createRoot() function instead we'll define our own render and ReactDOM.createRoot() function we'll doing this in browser itself. so if you have your real react app running open console in browser and type

const myCopm = {
    type: "h1",
    child: "Hello world! from custom React"
}

function render(root, comp) {
    const newEle = document.createElement(comp.type)
    newEle.innerHTML = comp.child
    root.appendChild(newEle)
}

const domRoot = document.getElementById('customeRoot');

render(domRoot, myComp)

Also add a div tag in html with id customeRoot And there you have it you have just made your own react, the output should look something like this

Note: Since I have build my own render function I get to decide how and what type I am going to expect its parameters this same component wont work in react because react is not expecting this type of parameters. What I have shown is trick of react + other libraries such as babel and webpack. To check the real tricks refer build folder.

Hello World in Leptos.

Default leptos app

Now let's look at rust web library leptos it is similar to react but in rust.

For this make a folder leptos-hello and cd into it and do

cargo init
cargo install trunk
cargo add leptos --features=csr,nightly
rustup toolchain install nightly
rustup override set nightly

this will install leptos in current project (trunk is similar to webpack in rust it is responsible to insert your rust code in index.html)

Also you'll need a index.html file in top level of you project as trunk will use that index file (This setting can be changed in trunk config.toml file, let me know if you would want me to make a blog on same) this is how your project would look like.

leptos-hello/
โ”œโ”€โ”€ Cargo.lock
โ”œโ”€โ”€ Cargo.toml
โ”œโ”€โ”€ index.html
โ””โ”€โ”€ src/
|  โ””โ”€โ”€ main.rs

now lets open up main.rs file

use leptos::*;

fn main() {
     mount_to_body(|| view! { <h1>"Hello World!"</h1> })
}

Yeah this is all the code you need to make "Hello World" leptos app pretty neat right? ๐Ÿ˜‰

its just adding the h1 tag inside body of our index.html file.

No, you dont need div with id root here this'll work just fine to run this go to current folder terminal and type

trunk serve --open

now check localhost:8080 you'll see "Hello World!"

Custome Leptos app

we'll be using web_sys to make custome app as this library is responsible to convert our rust code to javascript and make connection between our wasm code and browser this can be imported from leptos as well

Open up same main.rs file and lets start editing it.

use leptos::*;

fn main() {
    let window = web_sys::window().unwrap();
    let document = window.document().unwrap();
    let body = document.body().unwrap();
    let h1 = document.create_element("h1").unwrap();
    h1.set_inner_html("Hello World! from custom leptos");
    body.append_child(&h1).unwrap();

}

The code is pretty self explanatory itself but in a gist its grabing window then from window getting document using that its creating a h1 element and adding innerHTML in it as we did in our react app now we will add that h1 element as a child of our body which we can get from document. Thats all. now you have created your custome leptos app easy right.

to run this use same command.

trunk serve --open

You'll see something like this in browser

you can look at wasm code in script (I didn't understand it ๐Ÿค”๐Ÿซก)

All right. Thats it for this blog, Let me know if you have any questions post them in comments.

Thanks for the read.

Have a great day bye-bye

ย