Yosuke Onoue - Think About Front-end Web Development with Rust — RustFest Global 2020

Show video

Hello. The title of this presentation is ‘Think about Front-End Web Development with Rust’. I’m Onoue. In this session, I’ll talk about front-end web development through technological progress like WebAssembly in Rust. A bit about me, I work in research and education as an Associate Professor at Nihon University. My research is on information visualization and I mainly develop visual analytic systems with web technology. I follow the cutting-edge web technology like Rust to achieve high-speed web applications.

This talk will be on front-end development on Rust, what it can and can’t do, and web development trends. First, I’ll explain about recent front-end technology. Web application architecture for front-end technology has drastically developed and changed in the last 10 years. This was the typical web application configuration: It linked the application server to PHP or Python Ruby and used a template engine to assemble HTML from information loaded from a database. Then it transmitted this HTML to the client web browser.

As the front-end became more important, the configuration increasingly became single page application (SPA). HTML, CSS, and JavaScript was broadcasted from the web server as a static asset. This is loaded on the browser, constructs a UI, links to the API servers, and presents information to users. The architecture changed for various reasons. Its main effect was better performance and improved UX. Along with this, more weight was put on front-end development, which became complicated.

Before the browser directly loaded and processed JavaScript. The modern front-end requires a complicated bundling process on the browser: It transpiles language like TypeScript in JavaScript and aggregates multiple JavaScript files into one. With this, I’d like to consider how Rust can contribute to this complicated front-end development. The Rust websites lists their strengths as its performance with zero cost abstraction and no garbage collection, its reliability and memory safety with a powerful type system, and its productivity with a modern tool chain. These capabilities of Rust were created to be leveraged with conventional system programming.

The debut of WebAssembly has made bringing the capabilities of Rust to development more feasible. WebAssembly is a binary format language and the #2 programming language running on a browser. Rust incorporated WebAssembly support at an early stage and enables build within standard tool chains. Rust is characterized by its near-native performance and small binary size without a runtime. Web front-end development by compiling WebAssembly is difficult and requires a link to an API on JavaScript. The tool to support that is wasm-bindgen.

Low-level FFI to call JavaScript to Rust is made simple thanks to the crates wasm-bindgen, js-sys, and web-sys. There are two main approaches to incorporate this in web front-end development with Rust. The first is to incorporate Rust code in part of the web application mainly created with JavaScript. There’s a tool called wasm-pack for this. You can easily create a Javascript package on Rust with this. The other approach is to create an entire web application on Rust. Currently, React, Angular, and Vue are popular frameworks but require a front-end framework in Rust.

This talk will be on how to write these overall with Rust. Let’s discuss the architecture adopted in the previously mentioned frameworks: React, Angular, and Vue. This is not always the case, but a model architecture centered on a virtual DOM is becoming widespread. This architecture describes how to assemble the user interface from the app with declarative programming.

The virtual DOM has an algorithm to effectively update the user interface based on changes in the application. These updates are significant, but over the years they have taken various approaches with them. A typical example of these approaches is called Elm architecture which has a state update system and is adopted in Elm with an AltJS.

First, View constructs the user interface in the Elm architecture. The user performs an operation from the constructed UI and the operation conveys this as a message to the app. The app state update occurs based on this message and reconstructs the user interface to match its new state. This detaches the screen construction and app state management and keeps app development scalable. This modern front-end framework architecture has high-level abstraction to manage complexities.

Unfortunately, JavaScript expression is limited in how it controls every little quality of the app. Lately, TypeScript is in vogue. It makes use of type capabilities but has the limitations of its predecessor. I think that an exceptional high-performance language with a type system and tool chains like Rust is suitable to incorporate in web front-end which keeps getting more and more complex. There are already several front-end frameworks implemented on Rust with their basis in this architecture. Next, I’ll introduce front-end frameworks available on Rust. This is a list of 11 frameworks introduced on the ‘Rust Web Framework Comparison’ page.

The graph on the right shows GitHub stars. Yew, Percy, Seed, Dodrio, and Sauron are comparatively popular. They have more than 1000 stars. Within these Yew is by far the most well-liked, so we’ll cover it in more detail. Yew was developed when WebAssembly debuted and has a component-based framework like React and Elm.

It provides HTML macros like React and JSX and can construct a UI declaratively from the app state. It introduces state management system inspired by Elm architecture. It has various functions. The router is the most essential equipment for the front-end framework.

The embedded router enables a transition between multiple pages within the app. Yew is equipped with many functions needed in modern front-end web development. Currently, it is under active development as seen from the GitHub star rating.

Let’s look at a brief sample code for app development on Yew. This code has a simple counter with a plus and minus button. This model shows its components which are achieved by implementing the Component trait.

It uses HTML macro to mark up the components within the View function which is one of several functions. A noteworthy function is the Create function at the top. It initializes the component here. Here, the Value field is initialized. It holds this as a component state, so it can look up the current field value from within View and then display it. Next, let’s look at the state management system.

The Update function is implemented as a function to update the component state. The function receives messages and updates the component based on message’s type and content. There are two buttons constructed with View. When this is clicked, a message is issued from a click event. The sent message is received by the Update function and a state update is made for the value.

A ShouldRender value is rendered to determine whether the View function needs to be restarted with an update. This is abstracted with ShouldRender. The simplest method is rendering either true or false. If it renders ‘true’, then the View function is restarted. I focused on Yew due to time constraints, but most frameworks have UI construction and state updates. There are already several sophisticated frameworks like Yew. We know we’re getting close to achieving front-end development on Rust.

However, there are still many drawbacks when compared to the latest developments with JavaScript. I’ll cover these four topics that are of interest to me. The first is front-end multithread programming. A single thread, called a main or UI thread, is responsible for most functions displaying on a webpage. The HTML loaded by the web browser is stored on the browser with a structure called DOM.

The main thread performs many tasks: DOM operation, image plotting, event handling for the user operation, and finally running the JavaScript processing. When the main thread takes on too many tasks, several problems arise. For example, if long processing is required for the main thread while it’s managing event handling, the thread can’t immediately respond to the user operation during this long processing.

Animation processing also multiples on the web app. If the main thread is overloaded, issues arise like a degraded animation framerate. The concept called off the main thread has been proposed for this.

Workers like WebWorkers are a system to conduct multithreads on a web browser. The main thread can move JavaScript processing to an independent thread using this. Workers increase idle time and reaction speed for the main thread and smoothen animation. This leads to an improved UX.

For this, I’ll introduce Agents in Yew as an interesting approach to off-the-main-thread in Rust. Agents is a system that provides a service available from the overall application with an actor model. Agents provides various implementations with an abstracted interface including the use of WebWorkers.

This enables processing to be delegated from the main thread without being conscious of WebWorkers. We’ll look at this code on processing with Agents. A SentToWorker message is issued when you click on the button. Once it receives the message, it issues a GetDataFromServer request to Worker.

Worker receives this request and renders the processing results to the main thread. The processing results from Worker is processed with call-back and renders the call-back message. It issues a DataReceive message here. Then, the update function can reflect the processing results from that message in the state. Next is working with CSS which is indispensable in constructing a web app. As the front-end grows in scale, several issues arise surrounding CSS.

A typical example of this is when the CSS selector unexpectedly crashes and the website design breaks down. Performance is essential on recent browsers, requiring asset optimization to remove unnecessary style. Several approaches, like the CSS Modules and CSS-in-JS, have been undertaken in modern front-end development. I’ll introduce a few approaches for CSS on Rust. Firstly, several methods seem to have a similar approach to CSS Modules, in which they incorporate it in asset after generating other elements and unduplicated identifiers for the styles written within the front-end app on Rust.

It has an independent crate called CSS macro in Percy and CSSinRust and is applicable to this method. Let’s look at code using CSS in Rust. As you see at the top, first it wraps the style string then generates a style instance. The style instance generates a class name for the applicable element without duplicating other elements. The style itself is added to the head element in the output HTML. I’ll introduce a crate called RUSS as an approach to CSS like Rust.

This will assist with CSS coding on a Rust system which is prone to error. It can describe the pixel count or the RBG color value in Rust like in the code on the bottom of the screen. Next is Server Side Rending to create a more practical web application. As you may know, when SPA configuration is adopted, the HTML file doesn’t contain much content. JavaScript is increasingly run to generate the initial content.

Herein lies the problem. If the JavaScript isn’t completed, no content whatsoever can be displayed on the page. It has performance issues and issues with not displaying content in an environment that can’t process JavaScript. The Server Side Rendering (SSR) resolves these issues by constructing a UI on the webpage as SPA as well as constructing the initial UI on the server. Percy is designed for Isomorphic app construction, so it moves simultaneously on the browser and server.

Looking at the Isomorphic example that includes Percy, there are 2 place holders in the HTML file for its template. One has initial content to display on the page, whereas the other becomes the app state needed to construct this. When a request arrives from the browser, the server renders the generated results applying the template. The one on the browser makes this its initial state and operates the continuing app on the browser.

Currently, I believe, even front-end frameworks on Rust are becoming more aware of SRR. They’re taking into account the SRR compatibility with Yew. If we imagine the near future of front-end development, Jamstack will continue gaining traction as a system to achieve a high-performance web app with SRR. Jamstack is characterized by a configuration with a content delivery network to facilitate high-speed content to users. Next.js is a typical example of a framework for current Jamstack. Next.js supports SSR and static site generation with a framework based on React.

In the future, a single-step high-level framework may become necessary to construct a practical web app in Rust more so than the current ones. Finally, let’s discuss WebComponents. As many of you may know, WebComponents is a standard system to componentize websites. It’s configured from 4 specifications: Custom Elements, Shadow DOM, ES Modules, and HTML Template.

Incidentally, WebComponents has a connection to Rust. It needs to inherit a JavaScript class called HTML Element to implement Custom Elements. This inheritance through wasm-bidgen is under discussion, so you can’t directly implement Custom Elements on Rust. Personally, I think this’d be great, but let’s consider how you can write WebComponents with Rust. In this presentation, we’ve considered how to write the overall web application with Rust.

If we take this a step further, this will cover creating part of the interface on Rust and embedding this on the app. A trend that merits attention is micro frontends. The system splits the currently enlarged front-end into several micro frontends so that the backend app changes from a monolithic one to a microservice.

Then, this integrates a large web app. This is the trend for micro frontends. Interestingly enough, the micro front-end configuring the app could be disconnected from the implementation. These micro frontends could be written with Agular or with React. Micro frontends also include things that can be created with Rust and WebAssembly. WebComponents is not the only method to achieve micro frontends, but it’s an example of an effective tool for it.

Once WebComponents is possible on Rust, it surely has the potential to create part of the app user interface on Rust. To conclude this is an opportunity to leverage powerful language like Rust on complex front-end development. Front-end development with Rust is close to fruition with the debut of WebAssembly toolchains and frameworks.

There are still discrepancies, but we need to try out the best practices cultivated thus far on Rust in order to achieve full-blown front-end development on Rust. There are still many issues to address when you attempt to work on the front-end with Rust, so I’d like to challenge everyone here today to try your hand at tackling these. That’s it. Thank you.

2021-01-04

Show video