4
Chapter 4 Build Frontend User Interfaces
Luyao Zhang
I. Build a Frontend on the Internet Computer
There are three steps to build a frontend on the Internet Computer: first, the frontend web assets are programmed; second, the frontend is connected to the backend canister; and third, DApps are deployed. If a bare-bones interface is satisfactory, then the default Candid interface can be used. Otherwise, we could program a simple HTML page using raw HTML and JavaScript or utilize a frontend framework, such as React.js, Gatsby.js and Vue.js, for advanced attributes.
Now, let us take the dfx default project as an example and examine the data structure. Type the following command and view the demo in VS code.
dfx new hello
cd hello
code.
Figure 4.1.1 represents the frontend code in html. This file is under the folder “src>project-name-assets>src.” The frontend assets that the code refers to are stored under the folder “src>project-name-assets>assets.” This file defines the basic elements and structure of the user interface. The <label> line instructs the users to “Enter your name” as an input. The <button> line represents a button for users to click.
Figure 4.1.1: Frontend Code
Figure 4.2.1 represents the intercanister call between the frontend and backend actor under “src>project-name>main.mo.” Let us examine the code line-by-line.
import { hello } from "././declarations/hello";
The above line introduces the backend actor “hello.” As mentioned in the previous chapter, the IC provides a unique functioning for canisters to exchange programs. In contrast, in traditional web development, the connection between the frontend and backend is usually through an HTTP request, where a direct cross-reference is not possible. The rest of the code is an updating call that interacts between the frontend and the backend.
Figure 4.1.2: Frontend and Backend Communications
Figure 4.1.3 represents the backend actor file main.mo under “src>project-name.” The actor defines a function “great”: when “name” is input, the function returns a sentence “hello, name!”
Figure 4.1.3: Backend Actors
Now, return to the second part of Figure 4.1.2. An event is added by “addEventListener” to the button object when the button is pressed.
const name = document.getElementById("name").value.toString();
The above command assigns the input by users to a constant variable “name.”
const greeting = await hello.greet(name);
The above line of code calls the “greet” function in the backend and then passes the string variable “name” as the input of the function. The output is stored in the “greeting” variable. Finally, the following command updates the text content for id “greeting” on the user interface.
document.getElementById("greeting").innerText = greeting;
Finally, we can start a local replica, deploy the DApp and view the user interface in the browser by typing the following code:
dfx start --background --clean
npm install
npm audit fix
dfx deploy
npm start
Figure 4.1.4 shows the user interface after inputting the name “sunshine.”
Figure 4.1.4: User Interface
Now, view the project folder using VS code again. The new folder “declaration” is now shown under “src,” and two subfolders that represent the deployed backend canister “hello” and frontend canister “hello_assets” and how they interact with each other is also shown.
Figure 4.1.5: Candid Declarations
II. Connect the Frontend to the Backend: A Comparative Study
Figure 4.2.1 shows a comparative study of connecting the frontend to backend on different platforms. A comparison between Ethereum and the IC shows that on the IC, both the backend and frontend are deployed in canisters and communicate through canister calls and the HTTP API; in contrast, on Ethereum, in general only backend is deployed as a smart contract hosted on Ethereum nodes while the frontend is hosted on web servers, with the two communicating via Web3js. For centralized applications, the backend is hosted on centralized servers, communicating to the user interface on a web browser via the HTTP API. A centralized application can be developed by a combination of the frontend and backend or full stack frameworks. In the figure, we illustrate an example for applications created by Django, a full stack web development framework.
The governance for different types of platforms differs significantly. Ethereum improvement proposals (EIPs) define standards for Ethereum blockchains. The governance for Ethereum happens off-chain with a variety of stakeholders involved in the discussion, and it is implemented by code according to the EIP status. Governance for IC is an on-chain voting mechanism, namely, the Network Nervous System. The standards for the current internet are informal and documented in a memorandum named Request for comments.
Figure 4.2.1 Connect the Frontend to Backend: A Comparative Study
At first glance, the 4 GB canister memory limit might sound like a major drawback. In this case, developers will have to decompose the DApp to multiple canisters and design cross-canister calls. However, this design seems to be a microservice in Web 3.0. Microservice architecture style, a collection of small, autonomous and self-contained services, became a trend before IC existed. For example, multiple applications can be created under one Django project. Moreover, it seems that microservices on ICs can overcome the issues of current microservices. First, the current microservice is criticized for the inconsistency between languages and frameworks. In contrast, on the IC, all microservices are deployed as canisters with consistent structures. Second, governance for current microservices is difficult to coordinate, while on the IC, we can program governance canisters for the autonomous governance of the whole microservice. Finally, latency and network congestion might cause troubles in asynchronous communications between services. Instead, IC offers the unique features of intercanister calls.