December 13, 2017
mikesefanov
How to Make Your Web App More Reliable and Performant Using webpack: a Yahoo Mail Case Study
<p><a href="https://yahoodevelopers.tumblr.com/post/168507556083/how-to-make-your-web-app-more-reliable-and" class="tumblr_blog">yahoodevelopers</a>:</p><blockquote>
<p><figure class="tmblr-full" data-orig-height="1524" data-orig-width="3916"><img src="https://66.media.tumblr.com/81da10d7fe4e203f74c1fd5e2d316f5b/tumblr_inline_p0v7s7CoR61rgj0aw_540.png" data-orig-height="1524" data-orig-width="3916" alt="image"/></figure></p>
<p>By Murali Krishna Bachhu, Anurag Damle, and Utkarsh Shrivastava<br/></p>
<p>As engineers on the Yahoo Mail team at Oath, we pride ourselves on the things that matter most to developers: faster development cycles, more reliability, and better performance. Users don’t necessarily <i>see</i> these elements, but they certainly feel the difference they make when significant improvements are made. Recently, we were able to upgrade all three of these areas at scale by adopting <a href="https://webpack.js.org/">webpack</a>® as Yahoo Mail’s underlying module bundler, and you can do the same for your web application.</p>
<p><b>What is webpack?</b></p>
<p>webpack is an open source module bundler for modern JavaScript applications. When webpack processes your application, it recursively builds a dependency graph that includes every module your application needs. Then it packages all of those modules into a small number of bundles, often only one, to be loaded by the browser.</p>
<p>webpack became our choice module bundler not only because it supports on-demand loading, multiple bundle generation, and has a relatively low runtime overhead, but also because it is better suited for web platforms and NodeJS apps and has great community support.</p>
<p><a href="https://s.yimg.com/ge/default/691231/Webpack1.png"></a></p>
<a href="https://s.yimg.com/ge/default/691231/Webpack1.png"><figure class="tmblr-full" data-orig-height="330" data-orig-width="662" data-orig-src="https://s.yimg.com/ge/default/691231/Webpack1.png"><img src="https://66.media.tumblr.com/2e1b45e34e326495e0b82f8b2755aa18/tumblr_inline_pek5dnzPV41rgj0aw_540.png" alt="image" data-orig-height="330" data-orig-width="662" data-orig-src="https://s.yimg.com/ge/default/691231/Webpack1.png"/></figure></a><center><address dir="ltr">Comparison of webpack to other open source bundlers</address></center>
<br/><p><b>How did we integrate webpack?<br/></b></p>
<p>Like any developer does when integrating a new module bundler, we started integrating webpack into Yahoo Mail by looking at its basic <a href="https://webpack.js.org/concepts/#output">config</a> file. We explored available <a href="https://webpack.js.org/plugins/">default webpack plugins</a> as well as <a href="https://github.com/webpack-contrib/awesome-webpack#webpack-plugins">third-party webpack plugins</a> and then picked the plugins most suitable for our application. If we didn’t find a plugin that suited a specific need, we wrote the <a href="https://github.com/webpack/docs/wiki/how-to-write-a-plugin">webpack plugin ourselves</a> (e.g., We wrote a plugin to execute Atomic CSS scripts in the <a href="https://yahoomail.tumblr.com/post/162320728976/a-cleaner-faster-and-more-powerful-yahoo-mail">latest Yahoo Mail experience</a> in order to decrease our overall CSS payload**).</p>
<p>During the development process for Yahoo Mail, we needed a way to make sure webpack would continuously run in the background. To make this happen, we decided to use the task runner <a href="https://gruntjs.com/">Grunt</a>. Not only does Grunt keep the connection to webpack alive, but it also gives us the ability to pass different parameters to the webpack config file based on the given environment. Some examples of these parameters are <a href="https://webpack.js.org/configuration/devtool/#devtool">source map options</a>, <a href="https://webpack.github.io/docs/hot-module-replacement.html">enabling HMR</a>, and uglification.</p>
<p>Before deployment to production, we wanted to optimize the javascript bundles for size to make the Yahoo Mail experience faster. webpack provides good default support for this with the <a href="https://github.com/webpack-contrib/uglifyjs-webpack-plugin">UglifyJS</a> plugin. Although the default options are conservative, they give us the ability to <a href="https://github.com/mishoo/UglifyJS2/tree/harmony#minify-options">configure the options</a>. Once we modified the options to our specifications, we saved approximately 10KB.<br/></p>
<p><a href="https://s.yimg.com/ge/default/691231/Webpack2.png"></a></p>
<a href="https://s.yimg.com/ge/default/691231/Webpack2.png"><figure class="tmblr-full" data-orig-height="345" data-orig-width="1999" data-orig-src="https://s.yimg.com/ge/default/691231/Webpack2.png"><img src="https://66.media.tumblr.com/05e8cdb5ac293f4aac51d653a681b92a/tumblr_inline_pek5dnlfJP1rgj0aw_540.png" alt="image" data-orig-height="345" data-orig-width="1999" data-orig-src="https://s.yimg.com/ge/default/691231/Webpack2.png"/></figure></a><center><address dir="ltr">Code snippet showing the configuration options for the UglifyJS plugin</address></center>
<br/><p><b>Faster development cycles for developers<br/></b></p>
<p>While developing a new feature, engineers ideally want to see their code changes reflected on their web app instantaneously. This allows them to maintain their train of thought and eventually results in more productivity. Before we implemented webpack, it took us around 30 seconds to 1 minute for changes to reflect on our Yahoo Mail development environment. webpack helped us reduce the wait time to 5 seconds.</p>
<p><b>More reliability</b></p>
<p>Consumers love a reliable product, where all the features work seamlessly every time. Before we began using webpack, we were generating javascript bundles on demand or during run-time, which meant the product was more prone to exceptions or failures while fetching the javascript bundles. With webpack, we now generate all the bundles during build time, which means that all the bundles are available whenever consumers access Yahoo Mail. This results in significantly fewer exceptions and failures and a better experience overall.</p>
<p><b>Better Performance</b></p>
<p>We were able to attain a significant reduction of payload after adopting webpack.</p>
<ol><li>Reduction of about 75 KB gzipped Javascript payload</li>
<li>50% reduction on server-side render time</li>
<li>10% improvement in Yahoo Mail’s launch performance metrics, as measured by render time above the fold (e.g., Time to load contents of an email).</li>
</ol><p>Below are some charts that demonstrate the payload size of Yahoo Mail before and after implementing webpack.</p>
<p><a href="https://s.yimg.com/ge/default/691231/Webpack3.png"></a></p>
<a href="https://s.yimg.com/ge/default/691231/Webpack3.png"><figure class="tmblr-full" data-orig-height="330" data-orig-width="1160" data-orig-src="https://s.yimg.com/ge/default/691231/Webpack3.png"><img src="https://66.media.tumblr.com/66e381b447cbc177c645ce84938a456e/tumblr_inline_pek5dolB9m1rgj0aw_540.png" alt="image" data-orig-height="330" data-orig-width="1160" data-orig-src="https://s.yimg.com/ge/default/691231/Webpack3.png"/></figure></a><center><address dir="ltr">Payload before using webpack (JavaScript Size = 741.41KB)</address></center>
<br/>
<p><a href="https://s.yimg.com/ge/default/691231/Webpack4.png"></a></p>
<a href="https://s.yimg.com/ge/default/691231/Webpack4.png"><figure class="tmblr-full" data-orig-height="330" data-orig-width="1160" data-orig-src="https://s.yimg.com/ge/default/691231/Webpack4.png"><img src="https://66.media.tumblr.com/b6e25ffe404e6de05227cd4f5e81e168/tumblr_inline_pek5doTcEC1rgj0aw_540.png" alt="image" data-orig-height="330" data-orig-width="1160" data-orig-src="https://s.yimg.com/ge/default/691231/Webpack4.png"/></figure></a><center><address dir="ltr">Payload after switching to webpack (JavaScript size = 669.08KB)</address></center>
<br/>
<p><a href="https://s.yimg.com/ge/default/691231/Webpack5.png"></a></p>
<a href="https://s.yimg.com/ge/default/691231/Webpack5.png"><figure class="tmblr-full" data-orig-height="794" data-orig-width="1898" data-orig-src="https://s.yimg.com/ge/default/691231/Webpack5.png"><img src="https://66.media.tumblr.com/0a8f7b1b52b616f882b11fcf3ea697fe/tumblr_inline_pek5doGNIV1rgj0aw_540.png" alt="image" data-orig-height="794" data-orig-width="1898" data-orig-src="https://s.yimg.com/ge/default/691231/Webpack5.png"/></figure></a><br/><p><b>Conclusion<br/></b></p>
<p>Shifting to webpack has resulted in significant improvements. We saw a common build process go from 30 seconds to 5 seconds, large JavaScript bundle size reductions, and a halving in server-side rendering time. In addition to these benefits, our engineers have found the community support for webpack to have been impressive as well. webpack has made the development of Yahoo Mail more efficient and enhanced the product for users. We believe you can use it to achieve similar results for your web application as well.</p>
<p><b>**Optimized CSS generation with Atomizer</b></p>
<p>Before we implemented webpack into the development of Yahoo Mail, we looked into how we could decrease our CSS payload. To achieve this, we developed an in-house solution for writing modular and scoped CSS in React. Our solution is similar to the <a href="https://github.com/acss-io/atomizer">Atomizer</a> library, and our CSS is written in JavaScript like the example below:</p>
<p><a href="https://s.yimg.com/ge/default/691231/Webpack6.png"></a></p>
<a href="https://s.yimg.com/ge/default/691231/Webpack6.png"><figure class="tmblr-full" data-orig-height="668" data-orig-width="1464" data-orig-src="https://s.yimg.com/ge/default/691231/Webpack6.png"><img src="https://66.media.tumblr.com/aa1604d46e1f71b9a6648d226a205611/tumblr_inline_pek5dplyN61rgj0aw_540.png" alt="image" data-orig-height="668" data-orig-width="1464" data-orig-src="https://s.yimg.com/ge/default/691231/Webpack6.png"/></figure></a><center><address dir="ltr">Sample snippet of CSS written with Atomizer</address></center>
<br/><p>Every React component creates its own styles.js file with required style definitions. React-Atomic-CSS converts these files into unique class definitions. Our total CSS payload after implementing our solution equaled all the unique style definitions in our code, or only 83KB (21KB gzipped).<br/></p>
<p>During our migration to webpack, we created a custom plugin and loader to parse these files and extract the unique style definitions from all of our CSS files. Since this process is tied to bundling, only CSS files that are part of the dependency chain are included in the final CSS.</p>
</blockquote>