Michaël Gallego

This is my blog. What can you expect here? Well... Zend Framework 2, Amazon AWS...

Twitter

Google+

LinkedIn

Github

Last.fm

Questions and thoughts about client-side rendering from a ZF 2 developer

Disclaimer: I’m completely new to client-side rendering and, in general, to JavaScript. This article is just here to share my initial thoughts about client-side rendering and get help from people that better understand it.

Everything began last week on a sunny monday, when Marco Pivetta (aka ocramius), my dear #zftalk friend, talk to me about client-side rendering (he’s building a CMS).

To be honest, I’ve never took time to investigate client-side rendering before, so I was quite lost. But after one week of research, I’m kinda feeling stupid. I feel like I just discovered a completely different way of thinking websites, and how to make them. I hope this article will make people realize this new trend, because it really does sounds exciting and you could be asked to use it rather sooner than later.

For those who know me, I’m a Zend Framework 2 contributor, so I may refer to Zend Framework, but of course it applies to any server-side technology.

Client-side rendering vs server-side rendering

Server

There are chances like, that me, your workflow when thinking website was similar to this:

Workflow with server-side technologies

This is easy to understand:

  1. Client makes a request to your server.
  2. The framework dispatches the request to an action.
  3. Your action may load a lot of different objects (in this example I use a forum - because I’m making a Zend Framework 2 forum module (check it out and help us if you want !): categories, threads in the categories…
  4. Those data are sent to your server-side templates, renders it, and returns everything to the client.

As a consequence, as soon as the page is loaded, the user already has access to all information. And it’s SEO friendly too. Of course, when the user changes page, this round-trip to the server has to be made again, which slows done the user experience.

Like me, you have surely played with jQuery to make Ajax query. And, I suppose you understand me when I say that it is painful. Basically, you end up to bind a lot of elements and doing a boilerplate code that quickly becomes unreadable and unmaintenable. I won’t show you my JS code in my current website for your mental health…

Client

Client rendering, on the other hand, is a way to reduce this round-trip to the server, so that your webpage (nearly) never reloads. Of course, it won’t work this magically. Most of the time, you will be using a Javascript MVC framework that offer you a MVC pattern in Javascript. Some popular frameworks are ExtJS, Ember.js, Knockout, AngularJS… I’m personally trying to use AngularJS.

Here is how it works with client-side rendering:

Workflow with client-side technologies

As you can see, this is not as intuitive. Here are the steps that happen:

  1. Client makes a request to the server.
  2. Most of the time, whatever the request (/forum/categories/1, /forum/threads/4…) the request will be dispatched to the same action, that will just returns a minimal HTML (most of the time, just the layout).
  3. Your JS framework will be initialized, and your JS framework will “route” the request (notice that routing is moved from server-side to client-side too…). For instance, the URL /forum/categories/1 may be bound to a specific controller in JavaScript and a specific HTML template.
  4. The JS framework will make a request to a REST API (or any other endpoint, but REST plays really nice) to get the categories, and another one to get the threads (you could return both at once, but this may lead to a bad API design).
  5. The server will returns the data as JSON/XML.
  6. The browser will parse the JSON, and bind the JSON data to a JavaScript template.

There are a lot of things that I really had a hard time to understand. First of all, if you have JavaScript disabled, you’ll basically receive an empty page. If you return a layout, you will have a minimal layout, but nearly nothing more. This means that the user have to wait until he can actually sees data. If your page depends on a lot of different data (this means making different REST calls), the page may appear in “chunks”. Of course, you can just implement a “spinning icon” while all the data has not been loaded, but it is completely different to what I used to know before. Furthermore, this means that SEO is harder and you need to use some tricks to make it crawlable (more about this in this article - this is targeted to AngularJS but may apply to any other JavaScript framework -).

As a consequence, instead of one single-request that would load everything, with client-side rendering you will have several small HTTP requests that are made to the server. Depending on the context, I suppose this may be slower.

BUT there are some advantages to client-side rendering:

  • Less work to the server. It does not have anything else to do other than sending back JSON data. It does not have to take care of the rendering.
  • When the user changes pages (for instance, when he goes to the second page of categories), instead of reloading the whole page, the JavaScript framework will just make another Ajax call to your REST API, and just update the part of the page that needs to be updating.

The hard parts

What confused me a lot, is that templating is not done on PHP side, but on JS side. This means that you just do PHP, because the templates are just fetched by the JS framework directly and “compiled” by JavaScript. Obviously, there are things that I don’t know how to do yet in client-side.

Complex conditional renderings

In one of my application, I have a part that is rendered according to “complex” criterias (if the user is logged, show this, if he is logged AND is the author, show this…). Such conditional renderings use several entities, and I don’t really know how to efficiently map this to client-side rendering and REST API, that basically returns one kind of resource.

i18n (internationalization)

When using server-side template and a framework like Zend Framework 2, internationalization is easy. You have some view helpers that will fetch translation, for instance, in a Gettext file. This means that it is really easy to extract the strings to translate from your website, send the file to translators, get back the file, update the translations…

On the other hand, it’s much harder in JavaScript. Some JavaScript frameworks like AngularJS have a built-in component t o translations, but translations strings have to be put in a JS file. This is really a pain in the ass, as people have to download another JS file (and what if there are hundreds/thousands of strings to translate ? It’s going to be super-slow to download !).

Authentication

Obviously, authentication is not as easy to do. On server-side, using Zend Framework 2 identity helper, you just can do something like this:

<?php if($this->identity() === null): ?>
    <p>Not logged in</p>
<?php else: ?>
    <p>Logged in as $this->identity()->getFirstName(); ?>
<?php endif; ?>

It’s not as easy in client side.

Some solutions to the above problems

One of the problem that annoyed me the most is that when you are going to an URL, let’s say /forum/categories/2, you’ll basically have an empty page without any content. This is sad because, after all, an initial request is made… just to return, at most, a stupid empty HTML layout. Why not use this request to load some data and bind it to the view ? It appears that I’m not the first one asking myself this but it’s not that easy to do (I didn’t manage to do this using AngularJS, while some other manage to do it natively).

The thing is that, to me, it appears that it’s a “everything or nothing”. You either render your template in server-side, or in client-side, but you can’t do both.

So… when to use client-side rendering ?

I’m asking myself this question. On the website I’m working, it’s really a “standard” website. Some pages have very complicated conditional rendering, with data coming from several tables in the database… I just fetch all the data I need in one action, render it and voilà ! I don’t really see how I could integrates this to my website. I’ve found some solutions, but they rely on complex solutions (for instance using another JS library like PhantomJS that would render the JS templates in the server).

One solution I’ve thought about is doing a “hybrid” approach. I didn’t try this approach yet, so give me feedbacks if you think it would work or not. My idea is to have two URLs. For instance, let’s go back with my categories forum example. I would have to different routes :

  • /forum/api/categories/2 : this is a purely REST URL. It would be the API and would simply returns JSON data.
  • /forum/categories/2/my-category : this is a “standard” action, dispatched using ZF 2 router, and with a more SEO-friendly URL. It would act as a “normal” action, so it would load not only the category 2, but also all the threads of this category, so that the server renders a completely constructed page.

Of course, if the user navigate to page 2, I would like NOT to reload the whole page, but being able to use my JS framework ! In AngularJS, I could use something like that. I would attach an event handler to the /forum/categories/2/my-category?page=2 link so that when the user click it, it makes the Ajax request, and replace the actual content using, this time, an Angular template ! When the user goes to page 3, as this is already an Angular template, you have nothing to do.

The drawback of this approach is that you have to maintain 2 templates (and 2 routes, one for the API and one for the “first-time request”) : one template that would be rendered by the server (with code), and one using AngularJS binding mechanism. But on the other hand, I think that having a correct REST API is cool too, as you could use it for anything else (desktop application, native mobile application…).

Of course you have more work to do, but I think this approach would allow to have the best of both worlds, although I really hate duplicating the templates. But I’m not sure if this would work completely =)…

How to use Zend Framework 2 for client-side rendering applications ?

As you can imagine, using a Javascript framework delegates a lot of work from the server, to the client. This means that you will be using less-features of the server-side.

AbstractRestController

You will be using this a lot. And fortunately, it’s pretty good and intuitive. Instead of extending from AbstractActionController, your controllers will extend AbstractRestfulController. You will need to implement 5 abstract functions (getList, get, update, post and delete).  Those functions will be automatically call by ZF 2 depending on the HTTP verb action (POST, GET, DELETE and PUT). If a parameter named “id” is matched, it will select get function (/forum/api/categories/2 for instance), otherwise it will select getList (/forum/api/categories for instance).

Forms

You will no longer use forms too (haha, quite ironic for me as I am one of the maintainer of the Zend\Form component ^^). In fact, as you will most likely render your form on client-side, you won’t be able to generate them using ZF 2 view helpers.

HOWEVER, you will still need to validate data ! In ZF 1 it was problematic because the validation rules were defined in the Form object itself. In ZF 2, this task was delegated to the InputFilter object. Therefore, you are encouraged to use the Zend\InputFilter component to validate/filter your data on your server-side. As a consequence, if you want to use client-side framework, instead of defining your input filter by implementing the InputFilterProviderInterface in your fieldsets:

namespace Application;

use Zend\InputFilter\InputFilterProviderInterface;
use Zend\Form\Fieldset;

class MyFieldset extends Fieldset implements InputFilterProviderInterface
{
    public function getInputFilter()
    {
        return array(
            'username' => array('required' => true)
        );
    }
}

Just define your input filter in a different class that extends Zend\InputFilter. This will allow you to create form but only to instantiate the InputFilter and use it in your REST actions (most likely update and create).

Hydrators

You’ll likely still use hydrators, most of the time in your REST actions to convert array data to an object, that will be consumed by your services.

Conclusion

Do you think client-side rendering should be only used for web-app (I mean, applications that look like desktop/mobile applications), or do you need that it could be used in standard website too ? Of course, it would make the user experience so much smoother, but there are a lot of things I don’t really figure how to make them properly using a client-side library.

My friend and me are still thinking about what to use for our ZF 2 Forum module, so please give me some feedbacks on this ;-).