This week we updated https://Twitter.com  to send a "modern" bundle to newer browsers.

This means a ~6% reduction in the amount of code needed to run the site for most users, with just some webpack config tweaks.

I wanted to share a little more about how... 1/
Previously Twitter had a single ES5 build. We used a babel.config file, and a webpack.web config file which is fairly large.

In order to produce the same build, with a different babel config, we added a params to webpack.web({ legacy: true/false }). Now we can just call it twice
From there, we did basic tweaks in webpack config like changing the output folder and setting safari10: false in terser based on that param.

Additionally, we passed that param to our babel-loader:
options: {
caller: {
ES5: !legacy,
},
},
And over in Babel config land, we have:
targets: api.caller((caller) => caller && caller.es6)
? babelTargets.legacy
: babelTargets.modern
),
Building two targets wasn't too bad, but we need to be able to dynamically serve modern or legacy to different users at runtime.

Initially, I planned to use esmodules (<script type="module">) to just render both into the page and let the browser decide https://web.dev/codelab-serve-modern-code/#using-es-modules-with-babel
However, there were a few quirks that steered me on a different path:
- What about when I want to move newer features into the modern bundle, we'd have to rewrite again
- Our SW would have to cache both sets of modules or have code added to differentiate which bundle you used
Instead, we converted to using a https://github.com/browserslist/browserslist config file, and using that for both the babelConfig (shown earlier) and on the node server.

This keeps the two in sync (i.e. we serve the right files to browsers it was built for) and provides an easy upgrade path.
Literally a day before I merged this, they added support for feature detection via caniuse, so the babel.targets file is basically:
module.exports = {
modern: ['supports es6-module'],
legacy: ['defaults']
}

I really love that because it will provide a solid upgrade path.
Hopefully all this works and makes it easy to upgrade to future ES versions in the future. Ask me again in a few months how it turns out...

Finally, to share a post-mortem learning. Make sure to either not use "loose" mode in babel, or only do it on heavily tested code paths.
You can follow @CharlieCroom.
Tip: mention @twtextapp on a Twitter thread with the keyword “unroll” to get a link to it.

Latest Threads Unrolled:

By continuing to use the site, you are consenting to the use of cookies as explained in our Cookie Policy to improve your experience.