Uber.com
Two long years of optimizing performance and refactors
Uber
Marc Balaban
Victor Buchinski
Wasif Zaman
Ruby Williams
Ryan Wong
uber.com
React
Fusion
Styletron
Baseweb
Webpack
Cloudinary
Software Engineer
Dec 2018 ~ Aug 2019
Summary
Uber.com is like no website I’ve ever worked on in my past. It touched every line of business at Uber, it had over 4 million pages, and was translated in 50 languages. The start of this project was difficult for me on so many levels. In my previous experiences, I’ve always worked on behalf of an agency and this is important because agencies rarely get the opportunity to work on higher level projects like web performance. So when being tasked by my boss, to focus on the performance for uber.com, I started extremely lost on what was expected of me. Over the next year, I set and iterated on a few goals that led me to success. In this writeup we’ll be covering three major topics: All that went into to running and maintaining uber.com. My larger contributions to uber.com. How my contributions lead me to being successful at uber.
Breakdown
- -
Who & What is Uber.com
- -
Technology & Architecture
- -
Block Systems
- -
Content Management Systems
- -
Testing and Monitoring
- -
Javascript Optimizing
- -
Image Optimization
- -
Retrospect
Who is Uber.com






What is Ubercom












Translated in over 50+ languages
Technology & Architecture
Uber.com technology is seriously the largest bowl of buzzword soup I’ve had the pleasure to eat. In respect to time, I won’t beable to explain the entirety of the Architecture but only feed you small spoonfuls.
🥞 Stack
Golang
Microservices
Database
HTTP / RPC
NodeJS
Server
All Purpose Programming
JSX/HTML/CSS
Templating & Styling
Javascript
Everything
FusionJS
Isomorphic Koa
Dependency Injection
SSR React
React
UI
State Manager
Styletron
CSS-IN-JS
Atomic CSS
CMS
Block CMS
i18n Integration
JSON Schema
Site
Marketing Site
Webpack
Components
Storybook
Jest
Lerna
Optimizely
A/B Testing
GCP
Hosting
Edge Caching
Cloudinary
Media Hosting
Media Optimizations
Architecture


Page Renderer
The Block System
Uber.com was made of many small components. We composed together into what we called “Blocks”. Blocks are simply a composition of components and a Schema file. Below is a deep dive into the more than 160 Blocks that make up uber.com.
Component Architecture

Shared Components

Dynamic Blocks


Storybook

Block Schema

Content Management System

I18N
Being a global company Uber.com had a very tight workflow for translations. Translations were kicked off through Chameleon and within a week or so a page could be translated in over 50 languages.

Shipping Code
Updating uber.com was pretty tedious. It required 3 sequential code reviews across the three repositories: components, CMS, sites. Landing code on to master ran through continuous integration to run unit tests, type checking and linting.

Visual Regression Testing

Automated E2E Testing

Monitoring

Optimization
A base FusionJS app is roughly 60kbs and our app was a whooping 1.2mbs this gave me a the confidence to set a pretty straightforward goal: - 50% reduction in JS Bundle The bundle size of uber.com kept growing deployment after deployment. Before my first optimization our bundle had reached 1.2mbs! At the time, I knew that I was no performance engineer and 50% bundle reduction was an aggressive goal. That said, I’ve never in my life worked on a marketing website that had such an enormous bundle size.

Bundling, transpiling, & module systems.
The module systems inside of javascript are a nightmare, There are too many standards, none of them play well with another and they all have pros and cons. That said there is a clear winner in terms of performance and that is the Ecmascript module or ESM for short. Uber.com is a fusion application that is bundled javascript into small chunks using webpack. Components are simply transpiled using babel. The key for the best optimization when feeding a library that’s transpiled into a service that will be bundled using webpack is to preserve the esm or import syntax. Problem here is that ESM isn’t (until super recently) supported in nodeJS. So for everything to play nicely between dev and production, we needed transpile both CJS and a ESM from the Component Monorepo. There tons of other small gotchas inside the package.json like adding the module type and side effect: false. That said, when properly exporting esm modules our javascript bundle inside uber.com went down 30% because components could now be properly treeshaken!

Image Processing with Lazy loading
Our first optimization was to leverage a service Cloudinary. Cloudinary has some killer features that can make image optimization a breeze. Cloudinary is a file storage cdn with a graphic service layer in front. I like to describe it as “Photoshop in the cloud!” Let’s take this first example image on the current homepage of uber.com.

Each field above could be improved. Starting with dimensions, imagine that the user is viewing the website from a WXGA (1366x768) resolution, our image’s dimension would be unnecessarily large. Cloudinary offers width and height flags that you pass in the img src url.

A JPG file type is pretty optimized relative to png and gif; however, webp is a well supported image format that’s compression is superior to jpg.

Well so far so good, but we can do better! Let’s talk about image quality/compression. Inside cloudinary there are tons of things you can do. The example to the left makes quality extremely low and therefore you can see the artificating. however, best and simplest is a flag `q_auto:eco`.

Finally using Intersection Observer I was able to decrese initial page download by 40% by lazyloading images that exsisted below the users viewport.

Networking
Full HTTP/2 Support All of our JS and images were served on cloudfront edge over HTTP2. That said there were dozens of resources still coming from origin that were HTTP1.1. I admittedly didn’t do this work; however, I had to work with Infra at Uber for over a year to get this deployed into production. It is difficult to measure the performance here but statistics say that there can be up to a 30% decrease in network latency going fromHTTP1.1 to HTTP2. L2 Edge Caching Uber.com has over 4 million pages and to build these pages it relys on dozens of 3rd party services for content, localization, and geolocation etc. Each one of these at any time could go down and potentially take down pages of our website. GCP caching is amazing because it will cache responses from origin and put them on the edge. That said implementing GCP caching comes with a bunch of gotchas. The biggest of which is that your server cannot use Set-Cookie in the response headers otherwise GCP will ignore it as a cache key. I implemented GCP caching on www.uber.com/airports. GCP caching reduced our Time to first Byte (TTFB) by 1.2s.
Results
For nearly six months I focused most of my effort on performance of uber.com. In then end, I was able to results my own expectations! - 50% reduction in Page Download - 50% reduction in JS Bundle - 50% reduction in TTFB - 50% reduction in TTI
