13 minutes read⏲️

May 11, 2024

How I render my web applications

When you're making a web app, you need to decide where is the page (HTML) going to be rendered.

You're either going to use javascript, and fetch all the needed data from a server via an API, or, you're going to do the opposite, do everything on the server.

CSR vs SSR

If you haven't heard about these two before, they stand for Client Side Rendering, and Server Side Rendering, respectively.

Client Side Rendering

With CSR, the process is following:

1. Initial page load - the load times can vary, since its dependent on the size of all javascript modules.

2. You request the data you need from a database via an API (REST/XML).

3. Process that data, possibly validate, sort, etc.

4. Display it, or pass it to the DOM, where it gets rendered along with its appropriate HTML and CSS.


The real power of CSR is however, is very good interactivity, since there's practically zero network traffic, and everything is rendered as SPA (Single Page Application).

This is often the case with popular JavaScript framework (React, Vue).

The big downside is SEO optimization.

Since you're page is dynamically generated by JS, the search engine crawler has hard times recognizing the document structure.

Server Side Rendering

Now, let's explore the SSR process:

1. Initial page load - the resource is requested.

2. Data is fetched, processed, and embedded into the document.

3. The whole page is sent back to the client.

4. The content is rendered in the browser.


As you can see, the process is more or less the same, but the difference is, that SSR pre-generates the HTML on the server, and then sends the whole thing back.

An obvious downside of this is the reduced interactivity, since you have to request each resource individually.

However, if you want to re-render just a part of a page, you can do so with AJAX requests.

And probably the biggest advantage: SEO.

When the crawler fetches the content of your page, it gets the whole static and complete document, with all the tags.

This obviously allows it to scan the entire page flawlessly, thus ranking it much better.

Which approach I use

I use SSR for everything.

For all my projects, I have PHP running on the server, and I generate all the HTML with Latte templates.

I use less popular template system, Latte, which has context-sensitive escaping, compared to other systems like Twig (Symfony) or Blade (Laravel), which lack that.

Latte offers great layout system, which allows all your templates to inherit from a parent (layout), include other templates, and more.

I fetch the data from database (usually Postgres), pass them into my template handler, and render.

Template example

Here's an example of a base layout file I might use:

                                 
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
        <link href="src/public/styles/tw_output.css" rel="stylesheet">
        <title>{block title}{/block}</title>
        <meta name="description" content="{block description}{/block}"/>
        <meta name="robots" content="index, nofollow"/>
        <link rel="icon" type="image/png" href="src/public/assets/logo.svg">

        <link rel="preconnect" href="https://fonts.googleapis.com">
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
        <link href="https://fonts.googleapis.com/css2?family=Crete+Round:ital@0;1&family=Lora:ital,wght@0,400..700;1,400..700&family=Montserrat:ital,wght@0,100..900;1,100..900&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
    </head>

    <body class="lg:px-body_lg md:px-body_md sm:px-body_sm">
        <nav class="pt-4 pb-4 flex flex-row justify-between items-center font-lora border-b-2 border-slate-200 min-w-3/4">
            {block navbar}{/block}
        </nav>

        <main class="py-8">
            {block content}{/block}
        </main>

        <script src="src/public/scripts/main.js"></script>
    </body>
</html>

                                 
                             

That's the layout file. To tell a template file you want to use it, use the {layout} tag:

                                 
{layout 'simple_layout.latte'}

{block content}
    <div class="absolute h-full w-full flex items-center justify-center flex-col gap-y-4">
        <p class="text-8xl font-bold text-slate-400">404 Not Found</p>
    </div>
{/block}
                                 
                             

And this is an example of how you might use the template, from a 404 not found page.

This template only implements the content block, since the other ones are not required to be implemented.

PHP Usage

In PHP, in every controller I just simply call a wrapper function, and pass the arguments from url and database:

code snippet

What should you choose

The decision of picking CSR or SSR ultimately depends on your project needs.

If you're aiming for more of a interactive based application, typically a SPA, you should probably opt for CSR. However, you have to understand the SEO capabilities.

On the other hand, if you're making a blog, or a less interactive app, you might consider SSR.

Or, you can pick a hybrid approach, using SSR for certain parts of the app (for example for initial page load), and CSR for some interactive parts.

Personally, I use SSR everywhere, and I think the interactivity can still be partially achieved with AJAX.

Conclusion

Choosing the appropriate rendering technique depends on several factors, and you should evaluate those before deciding on the approach you're going to take.

I can only recommend using SSR, since it yields great SEO results, and you're good to go with PHP and some basic vanilla javascript. Because if you're like me, i use JavaScript as little as possible, and don't want to overbloat my app with framework nonsense.

Thank you very much for spending your time reading this, and I hope you learned something valuable in post.