Java server side rendering

JSX — React JS+ Java server side rendering (SSR)

The article talks about interoperability between JSX Frontend libraries like React, Preact which are easily pre rendered on a Nodejs server but faces difficulty in server side rendering (SSR) when your server is in JAVA or .Net or any non JS based language.

NOTE: Article language is meant for Intermediate to Advanced readers.

Background of the problem

In recent years, a lot of development has been going on in Web frontend making it the top most contender everywhere be it desktop app, mobile apps or IOT devices. Javascript has come a long way. From building monolithic apps, the world moved on to build micro services and now to server less apps. At the core was the idea to keep Frontend separate from your backend. Backend is mostly responsible for providing data by exposing APIs and frontend or web sites are responsible only for user interface and rendering the data received via calling the APIs.

Читайте также:  getTitle(); ?>

Since web is ruled by javascript, we saw the rise of frameworks/libraries like Angular JS, React JS, Preact JS, Vue JS etc each trying to solve certain problems. All these frameworks kicked in on client side thus raising problems like:

So the web community decided to go with a hybrid approach doing a server side rendering for the first request and then doing client side rendering there on. And such apps were called Isomorphic and Universal apps meaning the same code was used to render on backend and frontend.

TL;DR

Universal apps try to use same codebase to be rendered on backend as well as frontend. All popular client side JS libraries come with Server side rendering modules for NodeJS which is also a javascript based server side language. But what about other popular backend languages like JAVA, .NET, ROR etc? The article talks about solving this problem. Java has server side JS engines like Rhino, Nashhorn and J2v8 that can be used for JS SSR. However their performance is really questionable when it comes to serving responses in a performant way.

I believe a real practical solution can be made at build time by using the below unique approach via which a JSX based component like those written in React JS or Preact Js can work with Java based languages for server side rendering. Lets dive in!

Welcome to the world of transpilers

A transpiler helps you convert code from one language into another. Babel is an example which aids the dev community to write code in ES7/8/9 even though some browsers still don’t support it. Now behind the scene it transpiles once codebase into another using a set of rules. You can create your own plugins for Babel giving you an opportunity to access the generic AST and modify it any way you like.

Читайте также:  Vs code классы php

I hope by now bells might be ringing in your minds about the kind of magic and innovation we can inject here. We can actually convert a JSX / React JS file into any template language supported by your favourite backend language like Java using this technique.

In case you are still wondering WTH am i talking about here, lets dive a bit deeper with below steps:

STEP 1 : JS to AST

Lets convert our React or Preact component written in JSX into an Abstract Syntax tree which is nothing but a representation of JS code into a simple tree/json. There are many libraries that can do this. For example, in below image you can see an AST generated using babylon library. You can play and experiment with below AST here

STEP 2: Transform AST and extract HTML template

Once you get the AST representation its time to modify the AST in whatever format you want. To keep it simple, lets change the value of div. To this we write transformers which reads the AST and modifies it. In the below example I am using babel transformer. Play with the below AST here

Cool. Isn’t it? Lets take it to the next level and completely remove the JS to keep only HTML template. See below and play with this transformer here.

STEP 3: Handling conditionals and loops

Now any template library in JAVA, .NET or JS is incomplete with if, else and loops. And all these template engines have a different syntax for handling conditionals and loops. For example: Java freemarker template engine has the following syntax for loops:

<#list sequence as item> 
Part repeated for each item

And below syntax for conditionals:

Whereas, in JSX you would have written the conditional and loop code like:

.
.
.
return (

Hello



Apurav Chauhan


>
return obj
>)
>


);

To solve this problem, lets generalize the syntax of conditionals and loops so that we can use the extracted HTML markup in any language. For example, lets write a transformer which will simply convert the above JSX into a generic HTML template like below:


PLUGIN-CONDITION data=”hasName == true” type=”&&”>

Apurav Chauhan


PLUGIN-CONDITION>
PLUGIN-LOOP data=”friends” type=”obj”>
$
PLUGIN-LOOP>

In this transformer, you will see the code which actually transforms the if condition into a generic HTML syntax condition. Play and check it here

STEP 4: Language specific server side HTML template

The final step is to convert your generic HTML you got from your React, Preact JS component into your preferred server side rendering language template like Java-Spring freemarker template.

Just like we converted JS/JSX into HTML, we can now convert our generic HTML into any library specific HTML. To do this we are gonna use something like posthtml which tranforms your HTML syntax. Using this we can now convert into below java Freemarker specific HTML


<#if hasName == true>
Apurav Chauhan


Practical Example

Enough theory! Lets write some code. Consider the below ReactJs component example, where we create a simple client side button clicking which you see a message “You like it”. Below is the gist. Run it and play on your browser.

To make it more clear, lets have a initial Loading … text as placeholder to see the problem.

  1. The server returned the page having only a Loading text div.
  2. After that client side library ReactJS takes some time to load on the browser.
  3. Once loading is complete, it does its magic and append the Like button component dom and events.

To solve this issue, libraries offer a server side rendering module for Nodejs based projects. These modules render the markup directly on server and returns a pre built page to avoid FOUC. And after the client side library loads, it simply attaches the events like onclick etc. And all this happens without changing your React / Preact JS component code defining a new terminology i.e Universal apps.

However, lets transpile our component to make it usable in any language other than Nodejs

Using this babel AST transformation concept , I have written this experimental utility that does the same thing. This utility works in 2 steps:

1. Convert JSX into generic HTML. For this, I have written this babel plugin.

2. The generic HTML is then converted into your language specific HTML template syntax. In the below example, I have written this posthtml plugin that converts generic HTML into Java freemarker template syntax. Now you can roll n number of such plugins that convert the generic template into your language of choice like .Net, ROR, PHP etc

3. The HTML spitted above can now be used in Java spring boot freemarker server side rendering project. We can simply replace the “Loading…” text in the above gist with the html converted above into the root div. The final HTML template that we will use in our Java freemarker project will look like below

DOWNLOADS

  1. Here is the complete example project showing React JSX component conversion to Java-Spring-Freemarker server side rendered project.
  2. Here is the babel plugin to convert ReactJS / PreactJS JSX component into generic HTML template
  3. Here is the posthtml plugin to convert generic HTML into freemarker syntax template.
  4. Here is the utility that combines the above plugins to convert jsx into java freemarker template

TODOS

This is just a proof of concept showing the potential of opening up channels for a complete interoperable library or framework. The demo utility currently only handles:

  1. A single ReactJS / PreactJs JSX class in a file having a render method
  2. The render method only has expression container to support conditional and loops.
  3. The render method jsx doesn’t call any other method internally. ONLY HTML and expressions
  4. No support of dynamic components include
  5. arrow function is required with an explicit return statement in map function
  6. our experimental plugin has skiptag support for logicalexpression as of now
  7. Component folder only one level deep with index.js in it
  8. Self enclosing tags not supported(HTML5 spec)
  9. return should be immediately followed by jsx/element/bracket and not in new line
  10. expression inside expression not supported. expression should simple return a jsx
  11. expression should have parenthesis inside to seprate out logic from outcome like <(a.value==true && b==false )|| >
  12. component lifecycle is not handled like componentdidmount etc because it should normally trigger to hit an API to fetch data, which can be done separately on server. For example: In our ftl example liked variable is set on server.

Источник

React.js server side rendering with Java [without Node.js]

Server-side rendering is a technique that allows React applications to be rendered on the server-side, rather than relying solely on the client-side JavaScript. This method is useful for improving performance, search engine optimization (SEO), and providing a more consistent experience across different devices.

In this guide, we will discuss how to perform server-side rendering for React.js applications using Java. We will also explore how to achieve this without relying on Node.js.

Prerequisites

Before we start, make sure you have the following tools installed on your computer:

  • Java Development Kit (JDK) version 8 or higher
  • Maven build tool
  • React.js application

Steps

  org.springframework.boot spring-boot-starter-web  org.jsoup jsoup 1.13.1  javax.xml.bind jaxb-api 2.3.1  com.fasterxml.jackson.core jackson-databind 2.12.3   
import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import org.springframework.stereotype.Component; import javax.xml.bind.DatatypeConverter; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.Base64; import java.util.Map; @Component public class ReactRenderer < private String renderUrl; private String authorizationHeader; private String cookieHeader; private String contentTypeHeader; public ReactRenderer(String renderUrl, String username, String password, String cookie, String contentType) < this.renderUrl = renderUrl; this.authorizationHeader = "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes()); this.cookieHeader = cookie; this.contentTypeHeader = contentType; >public String render(Map props) throws IOException < String propsString = DatatypeConverter.printBase64Binary(new ObjectMapper().writeValueAsBytes(props)); String url = renderUrl + "?props=" + URLEncoder.encode(propsString, "UTF-8"); HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection(); con.setRequestMethod("GET"); con.setRequestProperty("Authorization", authorizationHeader); con.setRequestProperty("Cookie", cookieHeader); con.setRequestProperty("Content-Type", contentTypeHeader); con.setInstanceFollowRedirects(false); Document document = Jsoup.parse(con.getInputStream(), null, renderUrl); Element body = document.body(); Elements children = body.children(); return children.html(); >> 
  1. In your Spring Boot application, create a REST endpoint that will call the `ReactRenderer` class to render the React application on the server-side.
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/render") public class RenderController < @Autowired private ReactRenderer renderer; @GetMapping public ResponseEntityrender() < try < Mapprops = new HashMap<>(); // add the necessary props for your React application String html = renderer.render(props); return new ResponseEntity<>(html, HttpStatus.OK); > catch (IOException e) < e.printStackTrace(); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); > > > 
  1. Build and run your Spring Boot application. Once it’s running, you can access the server-side rendered React application by calling the REST endpoint.
$ mvn clean install $ java -jar target/myapp-0.0.1-SNAPSHOT.jar 
$ curl http://localhost:8080/render 

Conclusion

In this guide, we have discussed how to perform server-side rendering for React.js applications using Java. We have also explored how to achieve this without relying on Node.js. By following these steps, you can improve your application’s performance, SEO, and provide a more consistent experience across different devices.

Источник

Оцените статью