Skip to main content

What's the Difference Between SSR and the JSP/PHP of the Past?

Free2020-10-18#Mind#SSG#static site generation#静态渲染#预渲染#服务端渲染

For a long time before the separation of frontend and backend, server-side rendering was dominant (JSP, PHP). Now it seems we've come full circle back to the starting point.

Preface

SSR (Server-Side Rendering) is not a novel concept. For a long time before the separation of frontend and backend, server-side rendering was dominant (JSP, PHP), generating complete HTML pages on the server.

(Excerpted from Exploration of Frontend Rendering Modes)

That is to say, after experiencing the great transformation from SSR to CSR, we are now exploring the possibilities of SSR starting from CSR... It seems we've come full circle back to the starting point. What happened in between? What's the difference between today's SSR and the JSP/PHP of the past?

I. SSR Was Dominant

Going back to the era when forums, blogs, and chat rooms were still hot, the industry best practice was dynamic websites based on JSP, PHP, ASP/ASP.NET.

Taking PHP as an example:

<?php if ( count( $_POST ) ): ?>
<?php include WTG_INCPATH . '/wechat_item_template.php' ?>
<div style="...">

  <div id="wechat-post" class="wechat-post" style="...">
    <div class="item" id="item-list">
    <?php
        $order = 1;
        foreach ( $_POST['posts'] as $wechat_item_id ) {
        echo generate_item_list( $wechat_item_id, $order );
            $order++;
        }
    ?>
    </div>
    <?php
    $order = 1;
    foreach ( $_POST['posts'] as $wechat_item_id ) {
    echo generate_item_html( $wechat_item_id, $order );
    $order++;
    }
    ?>
    <fieldset style="...">
      <section style="...">
        <p style="...">如果心中仍有疑问,请查看原文并留下评论噢。(<span style="font-size:0.8em; font-weight:600">特别要紧的问题,可以直接微信联系 ayqywx</span> )</p>
      </section>
    </fieldset>
</div>
<script>
    function refineStyle () {
        var post = document.getElementById('wechat-post');
        // ul ol li
        var uls = post.getElementsByTagName('ul');
        for (var i = uls.length - 1; i >= 0; i--) {
            uls[i].style.cssText = 'padding: 0; margin-left: 1.8em; margin-bottom: 1em; margin-top: -1em; list-style-type: disc;';
            uls[i].removeAttribute('class');
        };
    }

    document.addEventListener('DOMContentLoaded', function() {
        refineStyle();
    });
  </script>
</div>

<?php endif ?>

(Excerpted from ayqy/wechat_subscribers, a WordPress plugin for automatically generating WeChat public platform graphic messages)

During this period, webpage content was completely rendered on the server. The client (browser) received HTML fused with server data, along with a small amount of inline (form) interaction logic and style rules. This pure SSR mode supported a large number of early dynamic websites.

But as technical practice deepened, this mode gradually exposed some problems:

  • Poor performance: Every request requires re-executing data logic and view logic to dynamically generate HTML, even though a large portion of the content is the same.

  • High machine cost: The concurrent processing capability of application servers like Tomcat/Apache is far inferior to Web servers like [nginx](/articles/nginx-https 反向代理/), so more machines need to be deployed.

  • Difficult development/maintenance: Frontend and backend code are mixed together, personnel collaboration is a problem, and modifications and maintenance must be very careful (tag structure is easily broken).

Facing these problems, two ideas gradually became clear: separation of static and dynamic and separation of frontend and backend. The former solves performance and machine cost problems, the latter solves development/maintenance problems.

II. Separation of Static and Dynamic

To fully utilize the static resource processing advantages of Web servers while reducing the burden on application servers, resources are divided into two categories:

  • Static resources: Images, CSS, JS, etc., public resources unrelated to specific users.

  • Dynamic resources: Application logic, data operations, etc., resources closely related to specific users.

These two types of resources are deployed separately, static resources are deployed to Web servers or CDN, application servers only deploy dynamic resources. In this way, static resources respond faster (browser cache, CDN acceleration), application server pressure is reduced, everyone is happy.

However, we missed the view logic. Is HTML considered a static resource or a dynamic resource?

The separation of frontend and backend is to answer this question.

III. Separation of Frontend and Backend

The particularity of view logic lies in:

  • Closely related to data.

  • Both server and client can carry view logic.

That is to say, the creation and maintenance work of HTML view structure can be completed on the server or on the client, both relying on server data. But compared with the server, the client environment has some advantages:

  • Can update views without refreshing (re-requesting the page).

  • Free computing resources.

Therefore, view logic was divided to the client (i.e., CSR), with data interfaces as the boundary, divided into two layers: frontend and backend:

  • Backend: Provides data and data operation support.

  • Frontend: Responsible for data presentation and interaction functions.

Since then, frontend and backend each do their own job. Frontend is committed to improving user experience, backend focuses on business domains, parallel iteration, (when interfaces don't change) no impact on each other.

IV. CSR Was at Its Peak

After the separation of frontend and backend, entered the golden age of CSR, explored various code reuse solutions such as functional plugins, UI libraries, frameworks, components, and finally formed a prosperous component ecosystem.

Under the componentized development approach, pure CSR mode became increasingly popular:

<!DOCTYPE html>
<html>
<head>
    <title>My Awesome Web App</title>
    <meta charset="utf-8">
</head>
<body>
    <div id="app"></div>
    <script src="bundle.js"></script>
</body>
</html>

Under this mode, almost all page content is dynamically rendered by the client, including all work such as creating views, requesting data, fusing data and templates, and interaction functions, all handed over to a set of data-driven component rendering mechanisms to manage fully, without having to pay attention to DOM structure maintenance work below the components, effectively improving frontend production efficiency. But some problems also came:

  • Before the component tree is rendered for the first time, no content can be displayed on the page, including loading.

  • Data requests must wait until their belonging components start rendering before they can be sent out.

The root cause of these problems lies in the current component rendering process being synchronous and blocking, posing challenges to first-screen performance:

  • Low-end devices have low JS execution efficiency, long white screen time.

  • Weak network environments have slow data return, long loading time.

Although CSR utilizes user device computing resources, it is also constrained by uncontrollable factors such as its performance and network environment. So, everyone turned their attention back to SSR.

V. SSR Makes a Comeback

Under SSR mode, first-screen content is generated on the server. After the client receives the response HTML, it can directly present content without waiting for the component tree to finish rendering.

Although the core idea is to complete page rendering work on the server, today's SSR is very different from before, reflected in:

  • Starting point: To present first-screen content faster and more stably.

  • Maturity: Built on the mature frontend component system and module ecosystem, isomorphic solutions based on Node.js have become best practice.

  • Independence: Still maintains separation of frontend and backend, not strongly coupled with application services in the business domain.

That is to say, today's SSR is to solve frontend layer problems, combining CSR to optimize content loading experience, is an extension based on years of CSR accumulation, maintaining good compatibility with existing frontend technology ecosystem. While SSR in the past was more to implement functions, solve subsistence problems.

Looking at the several problems SSR faced back then:

  • Poor performance: Every request requires re-executing data logic and view logic to dynamically generate HTML, even though a large portion of the content is the same.

  • High machine cost: The concurrent processing capability of application servers like Tomcat/Apache is far inferior to Web servers like [nginx](/articles/nginx-https 反向代理/), so more machines need to be deployed.

  • Difficult development/maintenance: Frontend and backend code are mixed together, personnel collaboration is a problem, and modifications and maintenance must be very careful (tag structure is easily broken).

These problems come back after introducing SSR, but technological development over the years has provided new ideas for solving these problems:

  • Real-time rendering performance problems: The idea of separation of static and dynamic is still applicable, such as Static Generation.

  • Server resource cost problems: The development of cloud computing is expected to significantly reduce machine costs, such as Node FaaS.

  • Development/maintenance problems of SSR part and CSR part: Isomorphism provides a new idea for solving development/maintenance problems (the previous idea was separation of frontend and backend, but this time they can't be separated), maintaining the same code, running in different runtime environments outputting different forms of target products.

Among them, Static Generation (also called SSG, Static Site Generation) refers to generating static HTML at compile time (can be deployed to CDN), avoiding the performance overhead of real-time rendering:

Static Generation (Recommended): The HTML is generated at build time and will be reused on each request.

But not all pages can be statically generated at compile time. A feasible practice solution is to combine SSR with Static Generation, only using SSR for pages that depend on personalized data or are frequently updated, all other scenarios use Static Generation:

You should ask yourself: "Can I pre-render this page ahead of a user's request?" If the answer is yes, then you should choose Static Generation.

At this point, SSR that has been silent for many years has regained new vitality.

References

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment