Using Server-Side Rendering (SSR) with Angular 6 Universal and Firebase

Gregor Srdic
4 min readOct 7, 2018

--

Recently, I was working on Ibex Website — a web app where you can find inspiration for your next outdoor adventure. The web app is built in Angular6 framework while back-end is running on Firebase Database and Firebase Cloud Functions. Great project setup, provided by angular-cli with typescript and webpack, enables easy generation of minified and well-optimised source files out of the box. And using the Firebase hosting it is easy to get the web page online in no time.

Caveats of Angular Apps (and any other JavaScript single page application — SPA)

After the initial release of the web app, we’ve started evaluating the page performance and finding ways to attract more users to the website. Here are links to a few useful tools that we’ve used:

Using those tools, I have noticed a few shortcomings of the initial web app:

  • Initial .html file, retrieved from the server, doesn’t contain any information about the page content — it is all generated in the client browser.
  • Meta Tags* are static — the same for every site in SPA — and can not be changed (using angular meta service won’t work without server-side rendering).
  • Page Speed Insights rating was adequate (thanks to previously mentioned project setup) but the rendered page does not show any content.
  • Crawlers fail to automatically identify buttons as navigation targets and subsequently many sub-pages do not get crawled.

*Meta Tags affect SEO and social sharing options (sharing website content on Twitter, LinkedIn, Facebook, …).

PageSpeed Insights without SSR — app performed excellent but the initially rendered screen is completely blank.

Implementing Server-Side Rendering

Thanks to my existing knowledge it was obvious that Server-Side Rendering with Angular Universal is the appropriate way to deal with the first three above-mentioned caveats. The idea is simple: web app is pre-rendered in JavaScript engine on server and browser initially receives a fully-featured .html file that can be immediately displayed.

After some research I’ve identified the following challenges, related to the Ibex Website app:

  • Web app loads data from Firebase.
  • Home screen displays 9 random hikes that differ each time you refresh the page.
  • Hosting an Angular Universal App requires Node.js server unlike regular Angular App that only requires static web hosting.
  • Global JavaScript objects — like window and document — are not available on SSR, same goes for DOM elements and setTimeout function.

I’ve set to implement the solution following this Angular Universal & Firebase tutorial that explains how to configure the server-side rendering and also publish it using Firebase Hosting and Firebase Cloud Functions. It was not the easiest task, but thanks to detailed instructions I have managed to get it to work — kind of:

  • Some npm packages, particularly @agm/core in this case, do not play well with SSR — they have to be removed.
  • All of npm dependencies need to be installed in the functions folder as well and published to Firebase Hosting — deployment is much more time consuming compared to static web hosting.
  • Page loading experience in browser is visually disturbed — although page is initially displayed faster it is later refreshed as app is rewired to the local browser instance and different random hikes are displayed.

Nevertheless, SSR did actually bring some improvements, worth mentioning:

  • Each page can have specific Meta Tags content, even retrieved from database or Instagram image — this significantly improves social sharing ability and SEO — google search engine uses these tags when looking for relevant content and displaying link previews in search results list.
  • Initial .html contains fully featured content of the page — this allows crawlers to better index the page content — however at least Google seems to be able to crawl SPA equally well to regular web sites.
PageSpeed Insights with SSR — initial render is significantly improved but app loading performance has regressed equally.

Other SEO and crawler’s optimisations

  • To make the site optimised for crawlers, we could replace any navigation buttons with links. Alternative solution was to generate a sitemap.xml file that contains a list of every page on the site and register it in Google Search Console and robots.txt file.
  • I got a very useful recommendation to replace generic links with meaningful hike names. For instance https://ibexapp.com/hikes/h001 was replaced with https://ibexapp.com/hikes/doaglalm-easy-982m that already contains some information about the hike in the URL.

Conclusion

In the end, my conclusion is that although very promising, Angular Universal is not yet an out-of-the-box solution to SEO and Social Sharing challenges in SPA applications. It looks to me that dynamically generated Meta Tags just don’t weight out the configuration, deployment and hosting complexity and even degraded user experience.

I imagine the difficulty of transitioning from the server rendered app to the client rendered one after the initial load but I would expect the server to be able to render the Angular App .html file just as any other browser JavaScript engine.

However, this was my afternoon project and due to limited time it is quite possible that I might have missed something. If you have different experience, I would be glad to hear about it. Thanks!

--

--

Gregor Srdic

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