 Hi folks, we're here today to talk about transitioning to modern JavaScript in order to get better value and performance out of every byte I'm Hussain and I'm Jason Hussain. Are you ready? Ready for what? Ready to play is it modern to show where I quiz contestants on whether a piece of JavaScript is modern or not? Modern Hussain your lucky contestant today. Let's begin for question one. We have these two lines of code What do you think Hussain modern or not modern? Hmm. I see months is declared using bar, and I'm pretty sure index of was introduced in ES5 So this is not modern Correct. There's no inherently new syntax being used here. So it's not modern on to question two Another two lines of code. Is this modern? Along the same lines object out of sign isn't a relatively new syntax or anything. So again, I'm going to go with not modern You're right not modern. All right, last question this piece of code is a little larger and I promise It's not a trick question. What do you think modern or not modern taking a look here I don't think there's anything modern regarding the promise syntax But I do see a variable being declared with const and constant let wasn't introduced until much later So this has to be modern code. Oh tricky block scoped let and const are actually supported in Internet Explorer 11 There's a few bugs to keep in mind We can run this code Wow, okay. I guess I learned something new today. Um, are you really gonna be doing this the whole time Jason? No, but that kind of begs the question. What exactly do we mean when we say modern code? Well for starters modern JavaScript is not ES 2015 syntax or ES 2017 or even ES 2020 It's code written syntax that is supported in all modern browsers Right now chrome edge Firefox and Safari make up 90% of the browser market And then another 5% of usage comes from browsers based on the same rendering engines which support roughly the same features That means 95% of visitors to your site are using a fast modern browser The browsers that make up majority market share are also evergreen Which means that they get new JavaScript features over time But how do we write or generate code for a moving target? The easiest way is to look to the features that are already widely supported First up classes which have over 95% browser support Arrow functions 96% Generators also have 96% browser support Probably the most underused JavaScript feature in particular this six line generator implements a lazy binary search over the DOM Yeah, to be honest, I can't think of ever having to write a generator by hand. This might have been my first Blockscoped constant let declaration save us from bar hoisting issues and have 95% browser support And like we mentioned earlier, this is actually partially supported in some older browsers So if we're careful, we could almost call this 97% support Destructuring has 94% support REST parameters and race spread also 94% Object shorthand which was easy to forget that this wasn't in the language before ES 2015 now has 95% browser support and Finally a single way, which even though is an ES 2017 feature has 95% browser support This is easily my favorite feature of the language. Oh really not a non generators We're using a term browser support quite often And it's worth clarifying what that means You can think of browser support as a percentage of global web traffic from browsers that support a given feature To get a full picture of modern JavaScript browser support We can take the lowest common denominator of the features we just saw And we can see that all these features are supported in 94% of browser traffic Now keep in mind. This is even higher for newer sites and apps as an example The total here would be 97% for visitors only from the US Yeah, so while it's actually pretty useful to have a rough idea of the browser support for language features You're going to use most of us aren't writing code that gets delivered totally unmodified to run in browsers We rely pretty heavily on Transpillation say I wanted to have a function that returns promises resolving to the number 42 I might write a little async error function like this one In order to have that code run in the last 5% of browsers that don't support async error functions I might transpile it to something like this Or at least I might try in reality Most current tools are going to take my 21 bytes of source code and transpile it to something like 583 bytes of source code Plus a runtime library that the generated code depends on which actually brings us up another six and a half kilobytes to 7,000 bytes Obviously the transpiled code will take longer to load than the original version. It's larger But the dramatically larger compiled code also runs significantly slower once downloaded JavaScript code gets compiled to instructions that are executed by a virtual machine And we can count those to estimate how much work is required to run a given program So our original async function compiles to 62 instructions, whereas the transpiled output compiles to over 1100 We can also benchmark these side-by-side and the transpiled version executes more than six times slower And this size increase is actually relatively consistent across modern features Pulling all of those earlier syntax examples into a single module is about 780 bytes when minified using tercer to remove white space If we then transpile that the generated code is six kilobytes that seven times more And the only benefit we got was that it could run in Internet Explorer 11 if we add another 10 kilobytes of polyfills that it depends on Theoretically, we also support Opera Mini's extreme rendering mode Although in reality most transpiled apps still won't work in that mode because of other limitations Now we know that the code in the left here works in 95% of browsers And a lot of us are already writing modern code like this So it's tempting to say well, that's fine. I'll just ship that modern code that I wrote to browsers Well, you can think that you can change all the code in your application But if we actually take a step back and look at what makes up our website code We'll find that the majority of our code base comes from third-party dependencies Data from HW archive shows that half of all websites ship almost 90% more third-party code than first-party Right, so I did some really rough napkin calculations, which is always dangerous But working back from global web traffic, we can estimate that the overhead of shipping legacy JavaScript accounts for around 80 petabytes per month of internet bandwidth That extra bandwidth shipping unnecessarily polyfilled and transpiled code Produces something like 54,000 metric tons of carbon dioxide into the atmosphere We'd have to plant 30 million trees to offset that much carbon dioxide These are obviously super approximate numbers, but they kind of help paint a picture of the scale of the problem Yeah, and a big part of that scale comes from how prevalent this issue is on npm If we take a look at the top thousand frontend modules on the npm registry The median syntax version is es5. The average is also es5 In fact, less than 25% contain any syntax newer than es5 Only 11% of modules use the browser field and 90% of these point to es5 2% of modules have a js next main field and all but one are es5 And only 9% of modules use the module field So why is this? A big part of the reason is that package authors can't rely on application bundlers to transpile dependencies to ensure browser support We estimate that only half of build tools transpile dependencies at all Which means that modern code published to npm gets bundled as is by the remaining tools And that unexpectedly breaks browser support for those users Thing is package authors came by this honestly as modern javascript got popular packages still published in es5 because it could be hand tuned Where general purpose transpilers have to be spec compliant so they don't break valid code Package authors could transpile to more efficient output by making assumptions specific to their source Maybe i'm using classes, but I only use the bits that transpile to simple functions and prototypal inheritance As we found ourselves using more and more modern javascript syntax over time those possibilities for lossy transpilation faded away Thankfully, this is now a solvable problem Historically npm packages declared a main field pointing to some common js code, which as we know is generally assumed to be es5 Recently node and a number of bundlers have standardized a new field called exports It's great does a lot of things, but it has one very important attribute which is that it's ignored by older versions of node This means that modules referenced by the exports field Imply a node version of at least 12.8 and node 12.8 supports es 2019 That means that we have to assume modules referenced by the exports field are modern javascript Going forward. There's at least two types of npm packages. I expect to see We have modern only where there's just an exports field and that implies an es 2019 package And then packages with both exports and main fields where main provides an es5 and common js fallback for older environments What does this all mean? The bottom line is that soon if you don't transpile package exports There's a high likelihood that you'll ship modern code by accident And maybe shipping modern code is okay The key is that you define a version of modern that strikes the right balance between js features and browser support Our research has shown that es 2017 is a sweet spot here Since it has 95 browser support offers huge improvements over es5 and is still really close to what we all think of as modern syntax Yeah, we're not saying that you should only write es 2017 Much the opposite es 2017 is a great transpile target Transpiling the most recent es 2020 syntax features to es 2017 is generally extremely cost effective Transpiled outputs like this for a weight loop are the kind of thing we're looking for the overhead incurred here is only four bytes But maybe you do need to support internet explorer 11 or opera minis extreme mode Thankfully, there's a really solid way to support older browsers without impacting newer ones First generate es 2017 bundles for your application and serve those to modern browsers using script type module Then generate polyfill es5 bundles and serve those to legacy browsers using script no module There's no expensive server setup or user agent snapping required and it lines up really nicely with our es 2017 sweet spot There are two ways to generate these two sets of javascript files The first is to compile your application twice And the second is to compile your application for modern and then transpile the output With the first technique we run a build of the application as if we were only going to support modern browsers Each source module gets transpiled to es 2017 by something like babel or typescript then code is bundled Then we run a second full build of the application But this time with the transpiler configured to convert modules to es5 and add polyfills The results is independent sets of javascript bundles that we can load modern and legacy browsers The second approach flips things around a bit. We run a single build to generate es 2017 bundles for modern browsers Then we transpile those bundles down to es5 with polyfills One great advantage of this approach is that all code including any dependencies can be es 2017 Since the whole build assumes modern code all code can't be modern It'll all be transpiled when generating the legacy versions of bundles Now this is all really important because i11 is a tax we and our users don't have to pay Consider cost as you think about your site's performance If you need to support i11 be careful not to degrade the experience for the majority of visitors in order to get there We hope we've made the case for why modern javascript is so important We also want to make this as easy as possible to adopt So we've published a how-to article that provides configurations for popular build tools to get you started Yeah, and depending on your setup this can be as easy as installing a plugin If you're curious what kind of impact turning on modern javascript would have on your website today, we're launching a tool for that Load the tool enter the URL of a page and it will analyze the javascript of that page in order to calculate How much smaller and faster that page would be if it leveraged modern code Go check it out. Let us know what you think. We're also working on something similar for npm packages And any feedback for this version helps make that one better too Thank you, and we hope you enjoyed listening as much as we enjoyed giving this presentation. Thanks for watching