How we migrated Weedmaps to React and cut our load times in half

Charlie King
WM Engineering
Published in
6 min readJul 2, 2018
Weedmaps c. 2015 (Left), Weedmaps c. 2018 (Right)

In 2015 Weedmaps.com was a Monolithic Server Rendered Rails application that was not mobile friendly. To address rising mobile demand, the team introduced a full split of the application and created mobile.weedmaps.com as an AngularJS Single Page Application (SPA).

As it turns out, it was much easier for the engineers to maintain complex application state in AngularJS due to the opinionated structure of AngularJS apps. So we started migrating most of our pages to the Angular codebase, deprecated the mobile.weedmaps.com domain, and started making weedmaps.com a responsive SPA.

However, this came at a cost. We were shipping a massive amount of JavaScript to the client, and not showing any real content until that script was downloaded and parsed.

Loading… 544KB of JavaScript

This was a decent experience on the fastest laptop CPUs, but the experience was below our standard for our mobile audience.

It wasn’t just bad UX: our analytics showed this performance could have negative side effects on advertiser engagement. Users were complaining about the experience and bounce rates were climbing. We knew we could do better.

React

After evaluating the JavaScript landscape in late 2016, our Front End Engineering team knew we could solve many of these issues by moving away from our AngularJS application. We created an internal project using React and fell in love with its small footprint (in bytes and API surface), its functional inspirations, and the amazing community that was built around it. It also didn’t hurt that almost all of our engineers were already using React in their past and personal projects.

Switching to React by itself isn’t a silver bullet and can quickly bloat to have all the same issues. So we made some clear goals to solve three problems that were hard to solve with our AngularJS application.

  • Code Splitting (delivering smaller chunks of JS on demand)
  • First Contentful Paint
  • Total Bundle Size

NextJS

Given our goals, we evaluated a few solutions. We created a small blog project by building our own server-rendered React app using Typescript, Express, and Webpack. While successful, it was obvious our methods to manage the data-fetching logic and hydrate the server state on the client wouldn’t scale well. Then we checked out react-server by Redfin. This project was super interesting because it forked ReactDOM to provide streaming HTML rendering. However, we had some concerns about the community not being active enough. We needed a project that had a thriving community so we wouldn’t get stuck with tech-debt that isn’t maintained. Then we found NextJS.

https://github.com/zeit/next.js

Next’s design provided just enough of an API to solve the tricky parts of server-rendered React apps. The best part: the community around it was already thriving thanks to the fantastic people at zeit.co.

Code Splitting

AngularJS and its dependencies make up a significant chunk of our JS bundle and have to be included in the “common” bundle. NextJS conventions allowed us to start splitting our JS code per-page. As a first pass, this allowed us to get our main bundle down from 544KB to 325KB!

This is better, but our goal was to get our main bundle as small as possible. We need to take it a step further. Luckily Next 3.0 introduced dynamic imports. We started using this to make sure only the bare-minimum JS is loaded to make the page interactive.

NextJS Dynamic Import

First Contentful Paint

Our AngularJS app was great at showing an initial “shell” application, but you still had to wait a lengthy amount of time to see any meaningful content (besides a loading indicator). Our server-rendered NextJS app solved this by rendering real content in the HTML. This not only improved our First Contentful Paint times, but made it easier to achieve our SEO goals (we now use a complicated pre-rendering setup currently).

AngularJS SPA

You can see in the figure above, on a 3G network with CPU Slowdown, our AngularJS application doesn’t show “meaningful” content for over 17 seconds 😱! Compare this to our new React application -

React NextJS Application

Our React application shows the user real content at ~1.5 to 2 seconds 🎉. This is a massive improvement in actual and perceptual speed.

Bundle Size

Despite our work on code-splitting and server rendering, the best way to have a performant JS app is to ship less JavaScript. We reached a wall in how small we could make our AngularJS application. A typical AngularJS page at Weedmaps weighs in ~630KB of JavaScript. Our new React app is currently weighing in ~340KB. This is partly due to React’s smaller size, and overall improvements to front-end build tools we use at Weedmaps.

Rollout

It was important that we be able to roll out the re-write to React without slowing down product development. We decided to use a reverse-proxy in front of our apex domain to route traffic between the old application and the new one. This allowed us to carve off specific pages to be written in React.

This is more maintenance on the team, but the trade-off was worth it to address our tech debt but still move quickly on new features.

Results

So far, the results have been dramatic. According to our measurements, our page load time for the React application pages have dropped in half, while being much more consistent.

Average Page Load

At the same time our “Sessions per user” for our React pages has gone up.

Sessions per user

This means we are converting more users on the new React application than we were previously in our AngularJS app!

What’s Next

We have a long way to go before we are satisfied with the performance of the site, but we are making improvements in leaps and bounds due to React and NextJS. This year we are tackling migrating the rest of the site to React, using more dynamic imports to trim our bundle down, image optimizations, and making Weedmaps a full Progressive Web App using the power of Service Workers.

Weedmaps Deals

The first major page to go live using React is our Deals page. Check it out here and claim a deal! Thanks for reading and stay tuned for updates as our Front End Engineering team makes more improvements.

--

--