node package manager




AngularJS is an awesome framework designed to run Web Applications. SEO is usually not a requireemnt for web applications, and AngularJS is bad at SEO for the reason that the client doesnt see anything when the client receives the requests from the server.

Comparing server prerendering with no prerendering

MEAN.js HTML with Angular.js MEAN.js HTML with Angular.js

MEAN.js HTML with Angular.js-server MEAN.js HTML with Angular.js-server

You can check this out by yourself at this url:

Implication for Angular and SEO

Now that all web crawlers can parse the real content of the page, they can index it and show previews in their results.

Angular.js can now be used to create and design performant websites, and is not limited anymore to web-apps.

Pros & Cons


  • It is quicker to develop a website from scratch with Angular than traditional Server Side technologies
  • You have to slighly modify your existing code base to enable server side $http caching.
  • Your website, once the page loaded, will behave as a web application - which means a much richer user experience
  • You can server side cache REST API and templateCache and replay them them in your client with (


  • This is a new concept built on a rather old technology. Angular 1 is now 4 years old, and AngularJS2 will have server side rendering built-in - but at this time of writting, ng2 is still in rc.
  • This is not unit tested (yet).
  • It is quite hard to debug Angular Errors when these happens on the server side.
  • There are many server side functionalities and performance optimisations missing . To cite a few:
    • Benchmark are missing
    • Logging is missing
    • URL rewritting support
    • ui-router & ng-router integration are missing. For example, it would be better to configure the pre-render config inside these two routers as well as URL rewriting
    • Redis caching
    • URL cache invalidation library: for ex: onUserUpdate: function(id) { cache.invalidate([ /user/([0-9+])/]); }



Your angular app must use html5mode. The reason behind this requirement is that browsers don't send the hashbang fragment to the server.

So for example, rendering on the server side will just render

Custom build of Angular

You must use a modified version of AngularJS ( while I get the time to write the tests to contribute to Angular source code. )

So far the only version of angular available is 1.5.7, available here:

Why do I need a custom build of Angular?

In order to have the prerenderer working, I need to make sure that all the initial templates are loaded, and all the REST api calls are completed. In short, I have to make sure that the Angular application is in IDLE state. And Angular1 doesn't trigger (yet) this idle state event.

You can check how this is done at this URL:

All tests passes, but the $EngineQueueProvider hasn't been tested.



So far, it only supports file caching, but modyfing the source code to use Redis instead is straigh forward.

Caching is made trough URL Regex, and supports two caching mode ( never, always, and maxAge ).

$http caching

When rendering the HTML on the server, every templateRequest and REST call are cached and injected into the client before the angular app runs. Then all the requests are instantly replayed, increasing considerably the client page load.

URL filtering

You can decide which URLs will be pre-rendered, and uses either of the two strategies include or exclude by providing an array of Regexes to match URL against.


Not implemented (yet)

How to use


npm install angular.js-server

Config object

var path = require('path');
module.exports = {
    name: "myApp",
    log: path.resolve( __dirname + './../logs'),
    server: {
        domain: 'server.example',
        port: 3000,
        timeout: 15000
    cache: {
        type: 'file', // possible values: none, file
        fileDir: path.resolve( __dirname + './../cache'),
        cacheMaxAge: [{
            regex: /.*/,
            maxAge: 10
        cacheAlways: [],
        cacheNever: [],
        cacheTimestamp: []
    render: {
        strategy: 'include',  // possible values: include, exclude
        rules: [
            /.*/, //pre-render it all !


timeout is the number in seconds before the server consider the request timed out. If it is reached, the current (and possibly incomplete) rendered HTML will be sent to the client.


This is a very basic cache engine that takes 4 types of caches

cacheMaxAge is an array of objects of type:

    regex: regular Expression
    maxAge: integer (Seconds)

cacheAlways and cache Never are array of js objects

    regex: regular Expression

cacheTimestamp: TODO To be implemented


This is the name of the angularJS application present in the ng-app tag.

Manually prerender

var AngularServer = require('angular.js-server');
var renderer = new AngularServer(config);
var renderedPromise = renderer.render(html, url);
renderedPromise.then(function(html) {
}).fail(function(errorHtml) {
// renderedPromise is a Q promise


var AngularServer = require('angular.js-server');
var renderer = new AngularServer(config);
app.get('/*', renderer.middleware, function(req, res, next) {
   //your code here 
// or


var jadeHtml = jade.renderFile('./views/index-classic.jade', {});
var renderedPromise = angularServer.render(jadeHtml, req.url);
renderedPromise.then(function(result) {
}).fail(function(err) {


var tpl = swig.compileFile('./views/index-classic.html', {
    cache: false
var prehtml = tpl({swigVarName: value});
var html = angularServer.render(prehtml, req.url);
html.then(function(result) {
}).fail(function(err) {



var renderer = new AngularServer(config) throws an error if the config object is invalid using jsonschema


middleware is the function(req, res, next) used for middleware injection.

render(html, url) takes two strings as parameters, and returns a Q promise ( .


They are located in test. To run them, you must edit your /etc/hosts file and add the following lines:   noserver.example    // render the app witouth server rendering   server.example      // render the app with server rendering and caching (if enabled)   api.example         // the api url

All the client code is written in ES6.

cd tests/server
node test-app.js


This work is incomplete and totally in progress - DON'T use it on prod.