When was the last time a website’s button shifted just as you were about to click it, causing you to select the wrong option? Or perhaps you’ve experienced frustration waiting for a page to load? These issues become even more pronounced in rich, interactive applications. As front-end code grows to support complex features, the size of data sent to browsers increases, negatively impacting performance.
At Dropbox, the web performance engineering team has recognized these challenges and identified a significant factor contributing to them: the module bundler.
Miller’s Law suggests that the human brain can only process a limited amount of information simultaneously, which is why modern codebases, including Dropbox’s, are divided into smaller modules. A module bundler consolidates these various components—such as JavaScript and CSS—into bundles that browsers download when a page is accessed. Typically, this results in a minified JavaScript file encompassing most of a web application’s logic.
Dropbox’s initial module bundler was developed in 2014, coinciding with the rise of performance-oriented bundling methods popularized by tools like Webpack and Rollup. However, this early version lacked many performance optimizations and proved cumbersome for engineers, hindering both user experience and development speed.
As it became evident that the existing bundler was outdated, Dropbox opted for a replacement. This decision aligned perfectly with their migration to Edison—the new web serving stack—offering an opportunity to seamlessly integrate a modern bundler into their static asset pipeline.
Existing Architecture Challenges
While the previous bundler was efficient during build time, it resulted in large bundle sizes and posed maintenance challenges for engineers. The reliance on manual definitions for script bundling led to several issues:
- Multiple Versions of Bundled Code: The custom architecture known as Dropbox Web Server (DWS) segmented each page into multiple pagelets (subsections), resulting in multiple JavaScript entry points per page. This setup occasionally caused inconsistencies due to differing backend code versions across pagelets.
- Manual Code-Splitting: Code-splitting allows browsers to load only necessary parts of the codebase for specific pages. Without this feature in the existing bundler, engineers faced complexity in defining packages manually. The packaging map grew unwieldy, leading to unnecessary code being loaded.
- Lack of Tree Shaking: Tree shaking is an optimization technique that removes unused code from bundles. The absence of this feature meant that many packages contained excessive unused code, prolonging load times.
Choosing Rollup
After evaluating various solutions over time, Dropbox determined that their primary requirements included automatic code-splitting and tree shaking capabilities. Rollup emerged as the most mature and flexible option available, making it an ideal choice for integration into their existing build pipeline.
Utilizing Rollup also minimized engineering overhead since teams were already familiar with its quirks from previous use in bundling NPM modules.
Rollout Strategy
Implementing a new module bundler safely required careful planning. Dropbox divided the rollout process into four stages:
- Developer Preview Stage: Engineers could opt-in to use Rollup bundles within their development environment for early QA testing.
- Dropboxer Preview Stage: Rollup bundles were served to all internal employees for initial feedback and performance data collection.
- General Availability Stage: Gradual rollout to all users occurred once Rollup packaging was thoroughly tested.
- Maintenance Stage: Addressing any technical debt accrued during the project while iterating on Rollup usage for ongoing optimization.
To facilitate these stages, Dropbox employed both cookie-based gating and their internal feature-gating system for quick toggling between Rollup and legacy packages.
Challenges Encountered
The simultaneous operation of two module bundlers proved more resource-intensive than anticipated. Issues arose with Rollup’s tree-shaking algorithm requiring substantial memory usage during analysis. Additionally, integrating Rollup into existing infrastructure limited caching capabilities, leading to timeouts during continuous integration (CI) builds.
Some bugs related to tree shaking were discovered during early testing phases but were resolved without impacting users. Furthermore, compatibility issues with strict mode in JavaScript required an extensive audit of the codebase.
Results Achieved
Upon completing the rollout of Rollup across all users, Dropbox achieved significant results:
- A 33% reduction in JavaScript bundle sizes
- A 15% decrease in total JavaScript script count
- Improvements in time-to-visible content (TTVC)
Additionally, front-end development velocity improved due to automatic code-splitting, alleviating engineers from manual adjustments with each change. This transition modernized their bundling infrastructure and addressed years of accumulated technical debt.
The adoption of Rollup not only provided immediate performance enhancements but also paved the way for future optimizations within Dropbox’s architecture. By revealing bottlenecks such as render-blocking RPCs and inefficient loading processes, Rollup’s extensive plugin ecosystem offers opportunities for further advancements.
In summary, embracing Rollup as their primary module bundler has led to substantial gains in both performance and productivity for Dropbox while setting the stage for continued improvements down the line.
Read more such articles from our Newsletter here.