Running an Angular Universal app on Google Cloud

Gregor Srdic
3 min readDec 26, 2018

I have been struggling quite a lot trying to get the Ibex website to play nicely with SEO. Concept of SSR is quite established in the Angular world by now, thanks to Angular Universal, but I encountered several difficulties trying to run the real-world Angular application with Server Side Rendering on Firebase Cloud Functions.

After a lot of research, I have established that there are three ways of achieving Search Engine Optimisation in JavaScript frameworks.

Server side rendering
Instead of hosting the Html shell and JavaScript source files on a static web server, we can deploy the JavaScript app to a Node.js server (e.g. Google App Engine, AWS Lambda, …) and have it serve already processed html files upon request. Client will receive a nice html file to display and will not need to execute JavaScript in order to show first meaningful paint. Server however will have to take some time to render the content of each page, particularly if it needs to fetch the data from the remote source (e.g. database).

Static pre-rendering
This approach generates static Html files for all possible routes in the JavaScript app prior to deployment. Deployed files are static Html and JavaScript — so static web hosting is the simplest and most efficient solution. However, if you have a lot of dynamic pages — for instance, Ibex has about 280 hikes in the database — this means a lot of overhead each time you are changing any little detail of the page.

Dynamic pre-rendering
Services like Prerender.io or Rendertron can help you pre-render your JavaScript app in real-time and also offer caching of pages to provide faster loading time. In theory, this solution is great, as it requires no changes to the SPA application whatsoever, but configuration of the service is not the simplest task and I was not yet able to really test it myself.

Other JavaScript frameworks offer similar solutions for Server Side Rendering — React has Next.js and Vue has Nuxt.js.

To create a clean solution for my project, this time I started from scratch with Angular Universal Starter. This project includes configuration for server side rendering as well as static pre-rendering out of the box.

Both work well with demo angular application, but once I added the content of the Ibex website, the things started to go south. Some external libraries, particularly @angular/fire, @agm/core, and @ngx-translate were causing problems and I was not able to get the server side rendering or pre-rendering to work.

@agm/core — this library does not play well with Angular Universal and it was blocking both server side rendering and pre-rendering. Therefore I had to remove it and use plain Google Maps JavaScript API.

@ngx-translate — I was noticing strange [Error] logs in console during server side rendering and pre-rendering of the app. It turned out that they were caused by @ngx-translate/http-loader that I was using to load translation files over http. I replaced that with a static loader which made the errors disappear, however my server side rendered html still includes translation key strings (e.g. “home.title”) instead of translated text :(.

@angular/fire — after including this library to retrieve hike details from database, the pre-rendering functionality stopped working properly. The console process never finishes and though html files get created, they do not include properly updated meta tags — static pre-rendering isn’t working for me.

Based on this experience, my decision was to use Server Side Rendering and deploy it to Google App Engine.

Finally, deployment.
To deploy the Angular Universal app to Google App Engine, you first need to install Google Cloud SDK. After that, I’ve added app.yaml file to the root of my project.

In your main package.json file, you need to update the “start” script to run the node.js server. Using gcloud cli you must set a target project — I have used the Firebase project for the app. Finally, I have added a “deploy” script that will build required projects and publish the project to the Google App Engine.

The result is SEO compatible page with dynamic meta tags.

--

--

Gregor Srdic

Founder, lead front-end developer at Nomnio — passionate about Hybrid and Web applications development