The opening

Front-end isomorphism rendering architecture, give me the most intuitive feeling, this is the most complex front-end rendering a solution, but also to pursue perfection user experience have to do a try, even though the Node. Js, the introduction of fu can, SEO optimization is no longer the traditional front field is a problem, but it’s clear that these are just a by-product.

The problem

When God opens a window, he closes a door.

As we know, the traditional SPA, the single page application, the closer it is to the user, the more complex the interaction is, and the more obvious its disadvantages are. While we enjoy the no-refresh experience brought by JavaScirpt and the development efficiency brought by componentized, the disadvantages of “white screen” along with various advantages of SPA are forgotten. We have chrysanthemum schemes to mask the DOM before JavaScript builds it, and white screen monitoring schemes to report real user data for improvements, but we don’t get to the essence of the white screen problem, which is that “THE DOM was built by JavaScript, not a native browser.”

<html>
  <head><title /></head>
  <body>
  	<div id="root"></div>
    <script src="render.js"></script>
  </body>
</html>
Copy the code

In the above code, in the SPA architecture, the server side directly presents HTML that looks like this. After the browser finishes rendering the body#root node, the drawing area of the page is actually empty. Append to #root until render. Js builds the real DOM structure. At this point, when the first screen is displayed, it must be render. Js through the network request completed, and then add JavaScript execution completed.

Back in the early days of the front end, when JavaScript wasn’t so powerful, our server was spitting out all the HTML to the front end, and we were using jQuery to handle user interactions, which had many drawbacks but undeniably had the theoretical lowest amount of white screen time.

<html>
	<head><title /></head>
  <body>
  	<div id="root">
    	<div class="header">
        <img src="logo.png" />
      </div>
      <div calss="content">
        <div class="shopitem">
        </div>
      </div>
    </div>
  </body>
</html>
Copy the code

In the code above, in the straight out server render, the browser gets the final HTML directly, and the browser generates the DOM elements after parsing the HTML for rendering. So compared to SPA, server-side rendering looks intuitive:

  • Converting HTML to the DOM, browser native, takes less time than JavaScript to generate the DOM
  • Eliminates the request and compile time for JavaScript in SPA

支那

To solve

With node.js, the power of the traditional front end is greatly increased. The separation of the front end from the physical file is changed to the responsibility. Front-end developers are freed from the nightmare of pages, and most importantly, JavaScript can be executed on the server side. In enjoying these dividends at the same time, we will not consciously imagine a scheme, it has most of the advantages of SPA, but to solve most of its disadvantages, that is, the server side output HTML, and then by the client reuse the HTML, continue to SPA mode, it is not to solve the white screen and SEO problems, Inheriting the no-refresh user experience and componentization of development.

Well, if that’s the case, there’s a consistency issue. We have to reuse the HTML output from the server in the browser to avoid multiple sets of code. Traditional template rendering is possible by choosing a template engine that supports both the browser and Node.js. We write the template, prepare the data in Node.js, and then feed the data into the template to produce HTML, which is then exported to the browser and then interacted with by client-side JavaScript.

All problems encountered in software development can be solved by adding another layer of abstraction

Ideas here, we can discover, “template” is actually a kind of abstraction layer, while the underlying HTML can only run in the browser, but it can pass the top-level template template engine run in the browser and server at the same time, this is vertical, horizontal, template data and structural decoupling, data structure, and this kind of pumping, In fact, it’s a one-shot deal.

As time went on, the wave of componentization came, and its core concept, the Virtual DOM, made front-end developers happy with its declarative and high performance, but at its core, it was a layer of abstraction on top of HTML to solve the frequent manipulation of the DOM. Unlike templates, it interacted data with structures. Representative ones are the single data flow used by Facebook and MVVM data flow used by Vue. To simplify, we observe the function UI = F(data), where UI is the front-end interface of the final output, data is data, and F is the template structure or Virtual DOM. In template mode, F is executed only once, while in component mode, F is executed again every time data changes.

Therefore, in theory, both the template and component methods are ready for the front and back end isomorphism schemes. We obtain data at the Node.js end, execute F function, get HTML output to the browser, browser JavaScript reuse HTML, continue to execute F function, and wait until the data changes. Continue to execute the F function, and the interaction is resolved, perfect ~~~

The implementation of

However, due to the trend of componentization, the template scheme will be omitted in the following. We take Vue as an analogy, and the following figure shows its implementation idea:

Generic code

Since F needs to be executed on both the browser side and the server side, for the entire Vue App, we need to support both ends, that is, common code. Therefore, we need to transform the code of SPA architecture:

  • There are two entries, the server and the client, which introduce only the common code and then call the respective rendering functions in different environments. . Of course, on the client side ReactDOM render will generate a DOM structure, and the Server side through ReactServer. RenderToString will generate HTML, HTTP Server has to be pushed to the front, each at the entrance to solve the problem of specific environment;
  • In common code, it is not allowed to reference DOM, call window and document without determining the execution environment, and reference global process, which is server-side specific operations. This is often the root cause of node.js service problems.
  • To be compatible with both ends, you need to select libraries that support both ends, such as Axios, Lodash, etc.
  • React and Vue both have lifecycles. It is necessary to distinguish which lifecycles run in the browser, which ones run on the server, or at the same time. For example, if you use Redux or Vuex libraries, it is better to introduce asyncData hooks on the components to make data requests and use them on both sides.
  • Determining the different execution environments can be resolved by injecting process.env.exec_env, as follows:
if (process.env.EXEC_ENV === 'client') { window.addEventListener(...) ; }if (process.env.EXEC_ENV === 'server') {}Copy the code

Build and run

  • When using WebPack to build, it is necessary to package the public App part to form the common code, which is introduced and executed by the server side, while the client side can refer to the packaged common code, and then use Webpack to introduce the special processing.
  • The middle layer of Node.js needs to be introduced, which is responsible for requesting data, providing rendering capability, and providing HTTP service. Since THE HTML template needs to be introduced on the server, the CDN file needs to be processed by itself.
  • As for the use of Babel, it can be handled generally in the browser, and the server only addresses special syntax, such as JSX, vue Template;

The new world

At this point, the white screen problem seems to be solved. By putting the JavaScript rendering logic on the Node.js side, we’ve accelerated the first screen time, but considering the front-end capabilities of Node.js, we could probably do more.

Reconsider the first screen

Let’s move the perspective a little bit further and focus on the “output HTML from the server” part. The hidden implication is that we need to output all the HTML rendered by the App to the front end, which is not true. For example:

For example, on the mobile side, there is a page with a height of about 10 screens. If we output all 10 screens on the server side, it is actually a bit of a waste. We can output only the first screen, so as to reduce the render execution time and reduce the TTFB time, so that the page reaches the user faster. In practice, the general situation is that the output of about two screens faster, can handle the height of all models, the remaining 8 screen, in the browser side continue to render, gradually output content, the user is not aware of.

Resource control

Thanks to another meaning of node.js output HTML, we can directly perceive the client on first contact, which gives us enough flexibility. Here’s another example:

There is a script that is different for Android and iOS platforms as long as it is loaded. In the SPA case, we only have to wait for the JavaScript to execute to determine which platform it is on first. Then appendChild sends a script to the body, but if the server is aware of the first contact, we can take the userAgent decision platform directly from the HTTP request on the server and process it in the template according to the identifier. Obviously, this is stable.

In addition, if there are particularly complex calculations, there are more ways for the server to process the data faster and avoid the busy browser taking over.

The cache control

In general business scenarios, we need to get the data from the Intranet in Node.js, and then render the HTML through the render function (generally, we need to attach the data to THE HTML output for reuse). At this time, we can use the page access address and generated HTML string as the cache strategy. After caching (generally choose redis and other schemes), the next time directly output the same page directly to the front end, can greatly improve rendering performance.

However, this scheme also has many limitations, because you have to consider the page address, multiple platforms, whether the account is logged in, whether the page needs to be changed, and so on:

  • The latitude of the page address. At different addresses, the HTML output is inconsistent, so the URL can be used as one of the key elements.
  • In unlogged state, the page can be cached directly. If the platform specificity needs to be determined, it needs to be processed in node.js terminal.
  • In logged in mode, if the HTML of a logged in user has been cached, you need to delete the components related to login and replace them again, or directly give the page in logged out mode to the client for change.

challenge

Isomorphic rendering looks nice, but it does have more challenges than traditional SPA:

Node.js

Server-side rendering corresponds to traditional Node.js applications. RenderToString function is not only CPU intensive, but also different components have different requirements on machine resources, which requires more monitoring of Node.js indicators, log recording, error collection, and crash mechanism improvement. The additional key metric here is the renderToString time, which reflects the time used by Node.js to render. If caching is added, the hit ratio needs to be calculated, etc.

The code quality

In terms of writing common code, the requirements are much higher for developers than the SPA architecture, and we need to be very careful, because if we get it wrong, it can lead to memory leaks and CPU spikes that are hard to fix, and if something goes wrong, it’s like fixing a flying plane. Remember once in the similar componentWillMount wrote some browser-related code caused by the memory surge, there is a JSON. Stringify a large object caused by the CPU surge, unbearable. This is what the Alinode does very well, and it really fits into this type of airplane scenario.

conclusion

For the sake of efficiency, the front end has made great efforts. Whether in engineering, we make every effort to manufacture tools, or the introduction of componentization, we solve the efficiency of development, and whether it is the introduction of Virtual DOM to solve the DOM of frequent operation, or the use of SPA architecture to improve user experience, We are dealing with user efficiency, front-end performance. Isomorphic rendering is also a solution that introduces the complexity of Node.js and requires us to write more restrictive code in order to get the user to see the page faster and earlier, whether it’s 50 milliseconds or 10 milliseconds.


About us

We are ant Insurance experience technology team, from the Insurance business group of Ant Financial. We are a young team (no historical technology stack baggage), current average age is 92 years (remove a highest score 8x years – team leader, remove a lowest score 97 years – intern young brother). We support almost all of alibaba group’s insurance businesses. 18 years our output of mutual treasure sensational insurance industry, 19 years we have a number of heavyweight projects in preparation for mobilization. With the rapid development of the business group, the team is also expanding rapidly. Welcome to join us

We want you to be: technically grounded, deep in a specific field (Node/ interactive marketing/data visualization, etc.); Good at precipitation, continuous learning; Personality optimistic, cheerful, lively and outgoing.

If you are interested in joining us, please send your resume to [email protected]


In this article: Ant Insurance – Experience Technology Group – Moon Shadow

Gold address: Willow bank paste