Onefootball’s office

Server-side rendering frameworks

Diego Mosquera Soto
Published in
12 min readJun 13, 2019

--

You probably know Onefootball for our iOS and Android Apps. They provide an amazing experience with a large set of features to our users and they have been our main business focus over the last years, but at the same time we have not been giving enough attention to our website (onefootball.com). We hence decided to bet on a complete reboot of the project. This means an entire new “Consumer Web” team with dedicated engineers, designers, QA and product manager.

We are currently at an exploration and team-building phase where very important decisions need to be taken to set the foundations for the project. Regarding web architecture, we are taking some time to do some research on server-side frameworks.

Currently

At onefootball.com we are using Angular(5.2) and its Angular Universal package to serve our content to our users. We were blocked while updating to Angular v6 due to the RxJS library (v5 -> v6 upgrade) and some third party libraries that depended on this library.

Our current web app can be seen as a quite complex product. Due to the nature of our business we serve a large amount of data to our users. We have around 3000 possible routes in each of our 11 different markets and the difficult part here is that routing is dynamic and depends on external factors: our newsroom editors, 3rd party titles, competitions changing name every year, etc. Furthermore as our business is serving content, SEO is a fundamental pillar of our app. Our metadata needs to be always available, up-to-date and finally, every link needs to be navigable by search engine indexing bots.

When the decision to use Angular was taken, Angular2 was in its beta phase and the Angular Universal project was in early stages. It wasn’t even using the same version control number as the rest of the main Angular dependencies. This represented for us that we had to build several custom functionalities from scratch because they weren’t provided by Angular Universal (e.g. transfer state).

So far, our development experience was good in general and the Angular framework served its purpose. Once the basic foundations and “HOW TOs” were agreed on, the web app was developed in a fast pace. By following Angular style-guide and suggested architecture we managed to keep our code structured and organised. An advantage of going with a heavily opinionated framework.

However, we have encountered some issues in our current app that made us reflect on our decisions; some are Angular related and some are due to using Angular Universal in production in early stages. Just to name a few: dated dependencies, difficulty to track memory leaks, dated strategy on ngUniversalRenderingEngine, the way we serve our CSS files, etc. One might say probably the fastest way to go is by migrating the whole project to a newly generated Angular project from the cli.

Research

To date we have done research on three SSR frameworks: Next.js, Angular (v7-v8) and Svelte with Sapper.

There are known technical needs that every framework needs to solve in order to be considered as a preferred technology for the consumer-web project.

- Server side rendering.

- Ability to extend the node.js server to include middlewares and redirects.

- Read from different config files in server- and client-side, and production and staging data.

- Ease of translations and route localisation (dynamic routing).

- TypeScript is a big plus!

Disclaimer

It would be amazing to get some feedback from the community. I might be missing some information that can be considered essential for another fellow developer. So I would like to encourage a discussion to enrich the article and create a better knowledge base. Every input is encouraged!

Next.js

Next.js is an agnostic framework to generate server-side websites. It works hand-in-hand with React but as it says in the project description it can work with other technologies. It is created by Zeit, currently a market-leading company, focusing on serverless tools crafted for web developers.

Next.js pros

Server side rendering is handled in a straightforward way and it doesn’t require too much configuration to have a project running.

  • Translations handled by the library next-i18next. A good strategy that handles namespaces and this way the app doesn’t get bloated with translations files.
  • Class-based components and function components work properly with Next.js.
  • Different config files are easy to load in the app.

console.log(serverRuntimeConfig.mySecret) // Will only be available on the server-side
console.log(publicRuntimeConfig.staticFolder) // Will be available on both server and client
  • Next-i18next Library provides a way to a add `lang` property dynamically to the top level HTML node. This is something we couldn’t manage to have with Angular Universal out of the box and required a custom implementation.

Next.js cons

  • Route localisation. Next.js like Nuxt.js (Vue.js preferred framework to do SSR) it generate its pages using a file system strategy. It means that it creates routes based on the files inside the /pages folder.
— pages
|- index.js
|- about.js

Next.js matches the file’s name with the route and renders that page. so www.test.com/about will render /pages/about.js page. However, www.test.com/es/acerca will render a 404 because the file doesn’t exist in the pages folder. There is no strategy to add a placeholder like {lang}/{about} and determine the route name dynamically.

Solutions:

1. Use a third party library next-routes to map the routes to the existing pages. The last commit in the repository is a year old, so it seems dated to me. Additionally, this approach will send the entire routes manifest to the client side app and it will bloat the app.

2. Create a custom middleware to map the routes and change the framework’s routing system in client side as well. It can be difficult to maintain in the long term. Resources: Custom-server-and-routing.

  • TypeScript is not a first class citizen in React or next so it requires more configuration. However, it was easy to set up and there are plenty of resources to set up and run this project.

Next.js conclusion

I will try to use it but my only concern is the routes localisation. Once it is solved there is no constraint. Coming from Angular development, the file architecture and having HTML inside the JavaScript file can be perceived as disorganised. However the React community has solved a lot of these problems using patterns like HOCs (High Order Components), moving non-view logic to Redux actions or helper functions. Since the end of 2018, with the release of React Hooks and the Context API, it is a lot easier to do what HOC used to do.

Angular

Angular is a JavaScript framework built by Google. It provides APIs for HTTP transactions, routing, service workers, metadata, etc. With this approach, Angular focuses in providing a complete ecosystem to develop SPAs. With the use of Angular Universal’s package users can build server-side rendered apps.

Angular Universal uses the Angular engine to generate a HTML page in the server and send it to the browser. It appends the JavaScript files needed to keep running the application client side.

Angular Pros

  • We have a lot of experience doing server-side rendering with Angular.
  • Angular style guide to keep consistent code.
  • RxJS and TypeScript as first-class citizens.
  • Translations handled by the library ngx-translate. No namespaces and all app’s translations must be in a single file per language. (No translations by namespaces like in next). Route localization with localize-route is an easy way to provide dynamic routing.
  • Modules can be loaded by lazy modules.
  • Different config files are easy to load in the app and injected via a config service.
  • No way to provide “lang” property to top level HTML node. But it is easy to do on the server-side when building the HTML.

Angular Cons

  • Relies on class based components (no JSX function components like React/next).
  • No idea if it will be compatible with Angular’s new rendering engine out of the box. This will stagnate dependencies’ updates.
  • Some developers prefer to work with React based frameworks. (Not a big con).
  • JavaScript libraries need to be encapsulated in an Angular way so it can be used. This limits the amount of libraries that can be used or makes the process slower if they are needed.

Angular Conclusion

Angular framework is our current framework of choice, one main advantage being that we’re already well experienced with it (we know caveats and almost every how-to). Choosing it would be “risk free”. However, we also know its downsides, and our decision should be motivated by technical arguments.

Angular heavily uses the Object-Oriented Programming (OOP) paradigm. This can discourage some JavaScript developers, as the JS community has lately been pushing towards adopting Functional Programming (FP), given it being helpful to avoid mutability problems. However, I don’t consider this to be a big issue for us; we believe that any experienced developer understands the advantages of the OOP paradigm and this debate shouldn’t be a blocker in choosing the framework to use.

Very important to consider here is the upcoming release of a new rendering engine (Angular Ivy) that can affect Angular Universal (the Angular package for server-side rendering). If Angular Universal is not up to date with the new engine we may have to avoid updating packages until everything is compatible.

Svelte with Sapper

Svelte takes another direction on the way to create web apps. It doesn’t provide a framework with APIs but all the logic happens at compilation time. This has an advantage that the delivered app is not bloated with the framework’s code but is plain parsable JavaScript. The downside is that you have to stick to certain specific Svelte conventions to compile the code.

Sapper is the framework Svelte uses to create complex apps. It follows the pattern of creating one page by main route. However it went beyond Next.js approach and also used some conventions to modularize APIs and server-only endpoints. Routing Svelte.

Svelte with Sapper pros

  • Current big hype and aims to provide the best experience to developers while avoiding framework bloating.
  • Open source development and community discussed features and direction.
  • Reactivity, the component is updated when a top level property has changed its value. This approach encourages functional programming and avoids bugs based on mutability.
  • Server-side rendering works like a charm.
  • You can use Express, Polka or happy to run your node.js server and this server is highly extendable.

Svelte with Sapper cons

  • Difficult to find a big project that is using Sapper. Not battle-tested.
  • i18n and route localisation: Is in planning stage since the beginning of 2019.
    i18n and route localisation. Thread.
  • No 100% TypeScript support. Main Svelte’s repository to showcase TS compilation doesn’t compile at first try (I needed to add some new properties to the app instantiation to be able to compile a test project) and it is some minor versions dated. Additionally, Sapper with ts-process compilation doesn’t accept basic Svelte’s reactive patterns $: remaining = todos.filter(t => !t.done).length;. In conclusion, TypeScript doesn’t support Svelte’s conventions from scratch and the plugin stays behind the current dev.

Svelte with Sapper conclusion

I wouldn’t go for Svelte with Sapper at this moment. The project is evolving quickly and there is a strongly motivated community working on it but it seems to me not mature enough for what we need. Svelte’s philosophy is another way to go in the era of frameworks and you can see how committed the community is to provide the best developer experience + better development. Even though Svelte’s current hype is helping for the community to be bigger, I don’t consider it big enough for the complexity of our project and the challenges that we might encounter. I18n strategy out of the box is in discovery stage and TypeScript compilation breaks when using Svelte’s reactive conventions $:.... In conclusion, we have the feeling that we will spend more time solving more technical problems than product problems.

Conclusion

There is no framework that can provide us everything out of the box. Each framework has powerful features that can help us in the development of the next onefootball.com but somehow they are also lacking in features that we would like to have. It is surprising how i18n and dynamic routing are such complex topics that happens to be a pain point for every framework. Finally, it seems that whatever it is the tool that we decide to use, we have a future full of exciting coding challenges.

More info about the frameworks

License

Next.js: MIT.

Angular: MIT.

Svelte with Sapper: MIT.

Stability

- How old is the tool/framework?

Next.js: 8 years ago.

Angular: 14 September 2016. 2 years ago.

Svelte with Sapper: First release was in the 20th of november 2016. v0.0.2.

- Who is maintaining it?

Next.js: Zeit.

Angular: Google > Angular team.

Svelte with Sapper: Rich Harris.

- How often new features are introduced?

Next.js: based on the latests big releases. Next4 (10.2017), Next5 (2.2018), Next6 (5.2018), next7 (9.2018) and current next8 (2.2019). Based on this we can see they have bigger releases every 3 two 4 months. Also try to keep up to date with React’s latest changes. No roadmap found in their blog. Thread-no roadmap.

Angular: Big releases every 6 months more or less. Roadmap.

Svelte with Sapper: Version 3 was release during Easter 2019 (21st-April). V2 was released in the 19th of April, 2018 (Apr 19, 2018).

- Does it follow the standards?

Next.js: Latest JS features by the use of babel transpilation.

Angular: Modern JavaScript using TypeScript.

Svelte with Sapper: Modern JavaScript using Babel, Functional js.

- What are similar production use cases?

Next.js: Zeit.co, jetm, Sumup, and more.

Angular: Angular Showcase website, Santander BR, Delta, Forbes and several google products.

Svelte with Sapper: Sapper.

Community

- How big is the community?

Next.js: 37k stars in Github. 188 open issues / 3844 issues closed. Backed by well known faces in the js community. some former moo tools developers.

Angular: 48k stars in Github /2,4k issues, Angular-Universal: 3,2k stars in Github / 60 issues.

Svelte with Sapper: Svelte: 17,2071 stars in Github /301 issues
Sapper: 2,117 stars in Github / 152 issues

- Who are the leaders (a company, some independent developers, a group, an
association, etc)?

Next.js: Zeit. Tim Neutkens — project lead, Guillermo Rauch and more.

Angular: Google. Pete Bacon Darwin — Core team], Victor Savkin, Igor Minar, Tobias Bosch and more.

Svelte with Sapper: Rich Harris, Emil Tholin, Conduitry and more.

- Does the community contribute to discovering and fixing bugs?

Next.js: 197 open issues / 4002 issues closed.

Angular: 188 open issues / 3844 issues closed.

Svelte with Sapper: 302 open issues / 1305 issues closed.

Features

- Extendability: how is it possible to add features?

Next.js: Custom node server. Keeps up to date with React latest releases. Ability to have a custom node server. Very extendable.

Angular: Very extendable as long as you use express/hapi/aspnetcore in the server.

Svelte with Sapper: Very extendable as long as you use a node.js server.

Integration with other tools/tool agnostic: how is it possible to integrate other frameworks?

Next.js: It renders exported js modules and doesn’t necessarily needs React.

Angular: Angular app can only work with other Angular apps/libraries. Very limited.

Svelte with Sapper: Sapper only works with Svelte.

- Documentation: is it complete? easy? understandable?

Next.js: Basic documentation is easy to grasp. Dynamic routing is difficult to understand but it exist. there are also community resources like authentication etc.

Angular: For Angular as a SPA, documentation tends to be complete and the main website provides handling for different cases. However, documentation for server-side rendering is limited and fragmented. A lot of resources can be dated and some
practices are discouraged now.

Svelte with Sapper: Documentation for basic introduction to Svelte is complete and full of examples. When digging into more complex problems, the examples sometime don’t compile at first time or the resources are running with dated versions of svelte.

- Follows the standards: does it follow the standards? does it introduce new patterns?

Next.js: No TypeScript as first citizen, no RxJS. I would say more into a React js way to write apps. Once TypeScript is set up you can use modern js and stop caring about js compatibility.

Angular: TypeScript as first citizen. RxJS. Opinionated architecture that encourages separation of concerns. Heavily use of object oriented paradigm. Component driven architecture.

Svelte with Sapper: Vanilla JavaScript as first citizen and new patterns for the compiler to understand. these patters are easy to get but the skills can’t be transferred to other frameworks or languages. component driven architecture / One file per component.

- Specific features / Key features: what are the main capabilities?

Next.js: Server side rendering and component driven architecture.

Angular: Server side rendering and component driven architecture. RxJS and style guide provided by Angular developers so the every Angular project is consistent.

Svelte with Sapper: Server side rendering and component driven architecture. Framework works at compilation time and it is not served to the client.

- Are there some known anti-patterns?

Next.js: Don’t know. The documentation is straight forward. Everything needs to compile to node modules. Some typings don’t exist for third party libraries.

Angular: For some people Angular is heavily opinionated by OOP paradigm. This isn’t necessarily bad however, JavaScript community tends to encourage functional programing to avoid data mutability issues that are hard to debug.

Svelte with Sapper: Routing. For small applications this strategy is really straight forward. However, for complex apps with dynamic routing the strategy turns out to be limited and another approach is required. The pattern to declare reactive properties `$: …` is not common to JavaScript language either.

Tooling

- Debug, what are the available tools?

Next.js: On the client side the React-devtools extension works so you can explore components and its props.

Angular: Augury browser’s extension.

Svelte with Sapper: There are no debugging tools expressed in the website or easily discoverable. However, there is a Discord groups where people are constantly willing to solve developers’ problems. It is a thing to admire that the community is willing to support other users, however more tools for Svelte need to be offered so the developers can feel empowered.

--

--

Diego Mosquera Soto
OneFootball Tech

Engineering Manager at Onefootball. I Love films, food, climbing and running.