 Hi, shall I start? OK, yeah. Hi, good afternoon all. Thanks for coming this talk. And myself is Anu Singhla, and my friend, Akshay Gupta. So we are working in Red Hat as a front-end developer. And we are mostly using React and Angular in our projects. So firstly, we will discuss why we are here. So in nowadays, we are using React applications, React framework, Java-based framework, basically Angular, React, Vue, and we are using a lot of JavaScript libraries, like loaders, TypeScript, and many more. So for that, we are loading a lot of JavaScript in browser. So if we are loading a lot of JavaScript in browser, definitely it hits the performance. And if it's a performance, then we are losing money for that. And we need to pay for this. So as per the research, if our application, it takes more one to three seconds, then we lose customers around 21 to 50%. So as per the research by abandoned group, so this is the desktop for blue one and the mobile for green one. So if the application takes one second, then we lose 6% to 5%. And if it takes two seconds, then 7% to 14%, and three seconds, then 21 to 20%. So nowadays, we are shifting our application to mobile application. So it's very challenging for the developers to make the website which load within one second. So there are three factors which hits the performance. First thing is amount of JavaScript we are loading in the browser in the initial load. The second one is amount of CSS we are downloading in the browser. And the third thing is amount of network request we are making on the initial load. So we can check there are different tools which we will discuss later, how we can measure, how we are loading the data, and all things. So now we have seen there are problems. Now how we will solve these things. So there are different bundling tool, but we will discuss Wepec, but there are like partial roll up. So Wepec is the JavaScript bundling tool which help us to bundle the JavaScript. And it creates the graph dependency as per our configuration. And second one is parcel also the JavaScript bundling tool. And the roll up is also the JavaScript bundling tool. But as per the JavaScript community, there are some code like Wepec we can use for web application. And the roll up we can use for library. But it is not defined, but it's code by the JavaScript community. OK. So now why Wepec? Why we choose the Wepec? So there are different reason for this. Easy to configure. So Wepec we can configure very easily. There are file like Wepec.config.js. And in the Wepec 4, if you don't provide the entry point, then Wepec is by default take it like source.index.js. Otherwise, we can provide it. And second one is the whole module replacement. It's very important in the development. Like I will give you one example. Suppose you are debugging some application and you made one change in the file, then it load only that file in the browser, not all the application. So it helps you to maintain the state of that application because you did not refresh the page. And the async chunk loading and magic command. So what are chunks? Chunks is the amount of JavaScript or the CSS you are loading in your browser as per your requirement. And the magic command we use for the give the chunk name or prefetching pre-loading, we will take it later. And Wepec also take care about performance by default. We just need to define the mode. Either it's a development mode or the production mode. And it also support many asset like font image styleset. And the next one is it's had a good communicative support. Suppose you want some feature, you can add as an issue. And then there is one website which is by the Wepec VORTS. So you can give the VORTS to your feature like you want this feature, the website Wepec VORTS. OK, now how the Wepec works. So firstly, we need to mention the entry point. I have already explained you. So if we don't give in the Wepec VORTS version, then it by default takes the src.index. If you mention it, then it will take as per our configurable. So entry point is used means Wepec start from the building from that location. And this is the loader send plugin in the Wepec. First one is the loader will run. Then loader is the transformer which helps you to convert, like, load the CSS in the browser or convert your TypeScript in the JavaScript. There are different types of loader, like CSS loader, TS loader, Babel loader, and all things, OK, and the plugins. Plugins are the backbone of the Wepec. And even Wepec is also based on plugins. And there are different types of plugins, like mini CSS plugin, HTML CSS plugin, OK, which help you to convert or minimize CSS plugins. There are different types of plugins. And in the end, the output, OK. So it gives you the output as per your configuration again. It gives you the one bundle file, all the chunks as per your configurable, and all things, OK. Now, hand over to me. Can everyone hear me, OK? All right. Before we actually start investing our time into looking at the solutions of all of these problems, looking into optimization, we need to set a benchmark. We need to measure our performance, which brings me to my next topic, measuring performance, OK. Now, there are a bunch of matrices that you can use to measure your performance, such as speed indexing and the time it takes for your website to load and interaction and et cetera, and a plethora of tools, such as Lighthouse, Pingdom, and Google Page Speed Insights. So today, we are going to talk about Lighthouse. It's an open source project developed by Google. And it measures a bunch of matrices, such as performance, page speed, SEO, and accessibility, et cetera, et cetera. So let's actually look at an example and how to actually use it, OK. So we're just going to measure the performance of our GitHub website. So to measure the performance, simply go to the website, right click. You can either use Inspect, or you can use one of the other shortcuts, such as Control Shift C, to open Chrome Developer Tools. In modern browsers, in latest Chrome, Google Chrome browsers, Lighthouse is actually shipped with the browser. So you can simply go to Chrome Developer Tools, go on audits, and there it is, Lighthouse. So as mentioned, it measures a bunch of matrices. You can also choose the device that you're going to use, or whether you're developing specifically for desktop or for mobile, and which audit are you going to perform. So we are only choosing performance here, because that's the focus of our talk. And you can also throttle the application based on, let's say, network. So you want to test for a slow 4G network on a smaller device, on a smaller mobile device, or you can choose that as well. And just simply click on run audits, and Lighthouse will start doing its thing. It measure takes the performance data from that already existed in the performance tab earlier, and presents it in a more digestible way. This might take a minute. OK, that seems a real poor performance. I think this is more affected by the Chrome extension to extensions. So I would suggest you do this. You run this in Cognito for a better and more accurate data. Now, Lighthouse gives us a number based out of 100, giving us a performance square of 12, which is very, very low. And it also gives us the matrices I first talked about, such as speed index and first color, full plane, et cetera. What do these actually mean? If you want to go into more details, you can click on this detail button, and you get a little more details of exactly what Lighthouse is talking about. Only not just not that. Lighthouse also gives you exactly what you can do to improve this performance, improve this number. So you have opportunities here. If you were to expand this tab, Lighthouse will tell you exactly which file you can remove or work on. So in this case, GitHub can remove some of the unused CSS to get a better performance score. We will also be talking about one more tool that is Source Map Explorer. I'll be giving a demo for that later on. So what are the solutions? Now, there are a bunch of solutions. There are a whole lot of solutions that are out there for webpack optimization. But we chose some of the popular ones, such as code splitting, and using webpack magic commands to pre-fetch some of the assets, optimizing your code in production, and my personal favorite shipping ES6 code in production, and tree shaking. So code splitting. Modern websites would often combine all of their JavaScript and CSS files into one large bundles. You will see that some of the time that you will take all of the CSS wouldn't combine into one CSS file or one JS file for all of your JavaScript needs. That results in very, very large files, such as 300 KBs or more than almost an MB sometimes. And browser has to download all of those files, then compile them, and then parse them, and then render them. That takes time. And time is our key for performance. The more time it takes, the worse the user experience become. So what is the simplest solution? The simplest solution is to split your code or send only what the browser needs when it needs them. That brings us to code splitting, which is just basically a simple solution allows you to split your code into a bunch of smaller, smaller files, or as we like to call them, chunks. One of the other reasons you want to split your code is browser caching. It's a little-known issue. But browsers, what will they usually do is cache your code. And if you were to then go change just one word in your entire code, just one line, the bundle will have to be rebuilt again, and the entire bundle has to be downloaded again. But if you were to split your code, then only the part that has changed will have to be downloaded. So a smaller part is, let's say, the 10% of what you downloaded before. So how to actually split your code? We have three main methods, using entry points, using split chunks plugin, and using dynamic imports, which is the most popular one. Let's look at entry points. Entry point is where the pack looks first to start bundling your code. Usually, as my colleague mentioned, you can provide a simple entry point to your code, and a single bundle will be created. But if you were to provide multiple bundles, multiple entry points, the webpack will look at those entry points, and will create bundles accordingly. Let's actually look at an example. So first, I'm going to show you one of the basic conflicts that we did. This is as simple as that. We'll be explaining each of these as we go along. Here, we just provided one entry point and one output point. And one of the rules for parsing our Babel, sorry, parsing our JavaScript down to ES5 or more codes we are using Babel loader. So let me run this and see what happens. I've already set up commands for running everything. So this will just basically run our config file. And a new folder was created. Just let me zoom in a bit. So zoom in. An index bundle is created, just a single bundle for the entire code. This could be up to 400 kb or more. The pack reminds us that this is 362 kb, which is much more than what the size limit that we have, 244 kb. As you might notice, there is one more file called dot map. This is called a source map. Source maps are basically used to map your bundled and minified code back to the way it was the original way. And you can use it to see exactly what's inside your code after bundling it. So how do we do that? We have a tool called Source Map Explorer. Let me run this. Source Map Explorer. You just provided where your JavaScript files are. So inside the distribution folder, start.js, simply press Enter, and voila. Source Map Explorer gave you a simple HTML file and tells you exactly what was inside the folder. We'll be using this going head to show you what's inside the code. So that brings us to entry points. We have created multiple branches so that one of our codes does not affect the others, because we have a lot to present. Let me go to my branch. Code splitting. Inside, you'll find a folder, code splitting, webpackconfig, and the entry point. The only change between this entry point config and webpackconfig is just that there is now a second entry. So what will webpack do? Let's run this and see. You can find all of these commands that I'm running in package.js on. OK, the pack has something for us. And as you can see, two different files were created compared to the last time. It's an index.js, and there is an app.js. The same goes for CSS. Our CSS was also split between these two files. I'm going to see what's inside them. Using Source Map Explorer, we have now two different files. Combined, they represent 4, 528 kb, and that brings me to the problem of this approach, duplication. If you notice, libraries such as yup, loadash, formic, are duplicated between the index bundle and the app bundle. You can see formic here and here. Same goes for loadash. So that is the first problem with the solution. The second problem is flexibility and scalability. As your application grows, it will be difficult to keep track of all of the entry points that we have created and loading them accordingly. So the pack has a solution for us in the forms of split chunks plugin. This plugin allows you to move certain parts of your application into different, different bundles. So if you have a dependency such as loadash or formic, and you've used that multiple times, you can extract it and take it into a single separate file. How does that work? Simply go to your webpack config. We have removed the entry point now. We've added this piece of code. Optimizes split chunks all. Let me show you what it does. So we have something. This time, there were also two files created, but the difference is that we have an index.js file and a vendor's index.js file. So by default, what the pack did, it took all of those vendor files and put them inside the vendor's index.js file. So if you were to have more entry points or more files, they would simply be split into two. Let me show you the source map. The vendor's index file only contains dependency and not the code we have written. However, the index files contains the code that we have written, the small to-do app. You can also customize the split chunks plugin to a very fine degree, such as you can use this, you can do this by cache groups. So simply write cache groups, the name of the bundles that you want, and when there's tests, you can provide it a test attribute which represents what you actually want to split. So if I were to write node modules, the webpack config will create a new vendor file as it did, which is what it did by default, and take all of the node modules and put them inside a single file. You can also do this for, let's say, have a bunch of utilities. You can create a new vendor, a new cache group user test, simply provide it the path, and the bundles will be split. OK, there are a lot more options and a lot more finer control that you can go on and find them on the webpack's website. I'm not going to go them into here. So now the final and third point is dynamic imports. JavaScript provides us with an import syntax that you can use to load modules on demand when exactly, when you need them. This is the most popular method for code splitting. So let me go to my branch, code splitting import. This time, the import config had very little difference. If you were to just take the basic config, that would work. The difference is in our Babel RC file, we have to tell Babel to expect a syntax called the import syntax. So what did we actually change? How do we actually use it? So we come to our app.js files, and we have split our app based on the routes we're using. I'm going to explain that in a minute. So we're importing our, by using the import functions and text, we can import the files as and when we need them. Let me show you that. OK, I have to install the plugin that I just used. I will put all of that information in package.js on. So I'll just save time and build it. Let me serve this. I'm going to serve this with a simple HTTP server. OK, so this is our simple app. At this point, three files were fetched, index 1 and 3. Now if I were to log in and go here, click on summit. As you see, I went to a separate route and a new JS files was fetched on demand. That is the benefit of using code splitting. So we started the monolithic bunch, and we split that code into smaller and smaller chunks as we went along. OK, thank you, Akshay. So my friend, Akshay has explained what are the code splitting, how we can do code splitting in a different way. He has explained dynamic code splitting, entry point code splitting. So now if you see, we are giving the index name to the chunks, like 1, 2, 3, but we don't know which chunks are loading. So we can give the valuable name to that chunk, or we can also tell the webpack when we need to load that chunk, like with the help of prefetch or postpack or the preload. So I will explain it with the help of example. OK, so for that, I have created the branch for this. And I'm just building the code. So I'm just building the code. And it will create the disk folder. And if you see here, the name of the chunk is 1, 2, 3, 4. But we don't know what are the name of the chunk. So we can give the name with the help of magic comments. This is the import way for creating the chunk. And this is the way which is provided by the webpack. So what is the name of this one? Webpack chunk name is like login button. This is the login form. We can give any name. OK, it's a text string. Or how it will load the webpack prefetch or the preload. OK, so we can give any like true or false to that. And we can give the same thing to all the imports. OK, now see the. Now if you see, it gives the proper name, which chunks is this, like footer, or the login form, or the to-do app. And the one thing is, we can make the chunks to the default components. But we can also give, if the component is not default, like import default, then we can give like this, a syntax of this. Means we can treat like this. Default is module.to-do app. If the component is not by default importing. I will explain. If you see this, this export module is export default. And the module name is valid login form. And if you see the to-do app, this is only the export, not the default. So how the syntax for this is? Like import, dot then module. And the name module.to-do app, the name, and the default. Means we treat like it's a default module. And the second one thing is, what is the difference between prefetch and preload? So prefetch means it load the chunk when the browser is idle. And the preload means it load the chunk with the main bundle. It's load parallely with the main bundle. And when we will use the preload and the prefetch, suppose there is one button on the page. So the model will open on click or that. So for that, you can use the prefetch, because we need this chunk in the future. And the second example of preload, you can use, suppose there are two button you need to show, the login or the sign up. So for that, you can use with the help of the main page, home page. So you use parallely the login sign up button and for the means login perform. Now, next one is the production optimization. So we have seen how we can make the chunk and all things. Now, the next one is the production optimization. So we need to make our bundle optimized. Like in the development mode, we use the commands, spaces in our code. But we don't need this in the production. There is no use. So there are different ways we can do to remove these things. So we have already explained the mode. So there are two things. Either you can give the production mode or the development mode. So by default, perform some operations like minify your code and all things. And the second one is the mini CSS extract plugin. This is also useful to extract the CSS from the different JavaScript. Or it depends on the configuration. Either you want different CSS file or the one CSS file. And the third one is very useful is optimized CSS asset plugin. So it helps you to optimize the CSS. For example, you have used four classes of CSS. But you are using only two. So it removed the extra two classes because you are not using that. And next one is if you want to extract all CSS in one file, you can use kase group optimization. And next one is the tree shaking. So tree shaking means remove the dead code from your application. We will see how practically how we will do this. So this is the way you can use the plugin like optimize CSS asset plugin. The first one I explain you. And the second one is if you want to extract all CSS in one file, this is the optimization kase style. And the third one is if it's a production environment, and then you can use a mini CSS extract plugin. And if it's the normal development mode, then you use the style loader, CSS loader. Because for that, we are debugging our code. So let's see with the help of example. So if you see here, we are not creating any CSS file. And it's all included in the bundle file. So now how we will extract this? I'll use different plugins which I have explained you. So in my script, I am providing the environment.modis production. So I'm doing the production environment. So now just building our code. I need to install it. If you see here, it extracts all the CSS in one file, style.css, but it is not minified. So how we can minify this? Now if you see, it minifies all the CSS and all things. OK, so this brings us to my favorite point, shipping ES6 code, ES6 plus code in production. So JavaScript every year brings out the ECMAScript standard, which introduces new and new features every year, such as Async Await, classes, fetching, et cetera, et cetera. But we still transpile down our code down to ES5, the oldest standard. And we add polyfills to account for these features in some of our legacy browsers. We took a look at our analytics data and see what browsers the users were using. And it turns out that 95% of our users were using modern browsers, the latest ones, evergreen browsers, such as Google Chrome, Mozilla Firefox, et cetera. So what we were essentially doing is shipping unused code to production. How do we solve this issue? We can simply create two different builds, or multiple different builds, depending on the browser we use. We can remove transpilation and selectively add the polyfills that we need at runtime. I've been talking a lot about modern browsers, so let me define what I actually mean. We've selected these four browsers, anything Chrome above 61, and Safari above 11, and above. So we've selected this data based on caniuse.com. And that basically tells you which browser support which features. Most of these browsers support all of the modern ES6 plus features, so you don't have to transpile down your code for these browsers. So how do we actually do it? Using script type modules. So the script tag has a new attribute called type equals to modules. And it basically will tell the browser to load JavaScript as modules. And browsers that usually support this feature type equals to module also support ES6 features. So if you were to create two bundle files and add those tags, such as these one, in your index.html, the modern browsers will look at this type of modules and download this modern MGS files, module files. But all the legacy browsers will ignore this and only download the no-module files. Let's look at an example on how to generate two different webpack builds. So we added a new folder in our webpack config. One webpack config for EFI files and one for ES6 files. What's the difference? We use a plugin called Babel Preset Environments. What it does is allows you to create your code according to a browser environment. So in ESI 5, we provided that you create a build for or transpile down, transpile our JavaScript for these browsers, for Firefox, extended support, the last two versions for browsers, and et cetera. The same thing we did with the ES5, ES6 config, and there we provided the modern browsers list. So the Babel Preset environment will not transpile down your code and actually look at these browsers and what features they support and see what it will transpile or not transpile. OK, let's actually run this and see what happens. I forgot to end this talk again. Sorry. This might take more than a minute, so I'm going to go ahead and look at some of the other things. OK. So what happened in our distribution folder? We created two different builds, one for legacy and one for modern. And let's look at the index.html. And a script type equals to models were added for the modern build. How did we do this? We used something called the script xhtml webpack plugin. It basically will modify the script tag and add the type equals to module if you were to provide this particular property, module, as mjs. So what did we actually benefit? Let me run this. First, I want to talk about the pitfalls of this method. Using the type equals to module at attribute will work in almost every browser, except for IE edge and Safari 10. The issue is that IE edge and Safari 10 will download the module mjs files, but they will not execute them. So they will not ignore the script type equals to module file. And edge is even worse. It will download both of these files, but only execute the legacy files. So how do we solve this problem? We can selectively serve the modern or the legacy bundle based on the browser's user agent. So how do we do that? We created our own simple express server. Some of you might have seen this. Any request that comes in gets checked, its browser agent against our modern list. So if it is modern, then serve the modern files. If it is not, serve the legacy files. Let's look at this in action. So I'm just going to run the server file. Okay, our React app. As you can see, our React app is now serving .mjs files. It's 84.3kb, and so I'm gonna switch the user agent using Chrome extension to IE 10, and the browser now switched to .js files. So you can selectively serve which bundle you want exactly to which browser. There's one thing to keep in mind. You have to make sure that the mine type of .js and .cs files is exactly correct. Otherwise the browser will simply not execute the .mjs files. The second is selectively adding polyfills. We add a number of polyfills for our ES6 features such as Async Await classes, and for web platform features such as fetch and promises. So what you can do is add those polyfills at runtime depending on the browsers. Now a service like polyfill.io exists for this very purpose, but it has a pitfall that it runs at runtime, mainly blocking the rendering thread, and you are also depending on a third party services. So if a polyfill does not exist on polyfill.io, you simply cannot use this. So ES6 polyfill, if you were to provide Babel preset environments and use the property, use built-in entry, what it will do, it will take what is generally used for polyfills, import Babel polyfill. Figure out the environment and serve only the polyfills that the browser needs. Also, to selectively serve the web platform features such as fetch, we created two different index entries. So index.es5.js, it will contain the es5 polyfills, and index.es6.js that only contains all of the stuff that some of the modern browsers need, such as intersection observer. So you can build this by simply changing k. Two builds were created. So looking at the source map of both of these files, sorry. This is the legacy file that contained 416 kb's, and the modern file which contains a smaller build 387. It may not seem much of a difference right now, but as your application grows, this becomes much, much more useful. I'm going to hand it over to my colleague, Anuj for the free shaking part. OK, yeah, thank you. So now next topic is tree shaking. Tree shaking means remove the unused code which we are not using in our application. So for example, we have used one helper file, which has two methods, and we are only using one method. So if you are loading another method in the production, then there is no use for that, and it increased the bundle size. So the tree shaking help us to remove that one function from your application, from your bundle. So webpack is already providing by default. Just we need to inform the webpack, you can do the tree shaking for us. Like there is one property in the packet.json, we need to provide side effect, and you just need to give the false, and then it will do all the things for you. So we will take this example. So I have created one utility class, and which has square and cube method. OK, and in the index app.js, I'm just using the square method, only one method. OK, so now we will check how it works. Firstly, I will mention the, you should not minimize that code, because I want to see how the webpack will work. OK, we will see now the bundle file. If you see the bundle file, and just search for that function, like I have used the console.loop for easily find, and if you see here, the webpack is added, like there one comment is unused, harmony export is cube, because we are not using that method. OK, so now, and we have also mentioned to the, the side effect is false to the webpack, you can do the tree shaking for us. Now I will do the development mode, then just build the code. Now, if you see here, there is only one square method is used, the second one is removed from our final bundle file. OK, so now we have sort of time, just final course and then question. So there is a ton more that we wanted to cover, such as especially compression. You can use GZ compression or broadly compression, which is something new to compress down your files, and exactly serve smaller and smaller files. There is also, yes, for in shipping ESX plus code, you can also remove some of the CSS prefixes from using auto-prefixer plugin to remove some of the CSS prefixes for the modern browsers that don't need them. Questions? One more thing, webpack is a very big topic. You can check on YouTube and all things, and there are very good documentation on the webpack site, you can just check and all things. There is one tutorial on front-end master website, so you can, this tutorial is created by the founder of the webpack, yeah, so that's it. Any questions? Yes, what was the Lighthouse core? Yes, sorry. So what was the Lighthouse core after we did the webpack optimization? OK, so we did have an example that we wanted to present, but due to certain internet issues that we had, we had to remove some of those code. But we experienced almost a 40% increase in our Lighthouse core. I remember it was 52, and we were at 83 or 84 or something after our optimization. So yes, there is a lot you can do. And compression is the best ones, the single biggest improvement you can do. Most servers that will serve your files such as Apache or Engines will have Gzip compression by default enabled, specifically designed for browsers. There is also a new one called Protli that you can use. And we are also checking how much code we are shipping in the initial load. There is code coverage in the DevTool you can check and just optimize that code. And the second one is there are back-end APIs, means we are getting the network calls, you can figure out how many network calls we are making. So if you are not used of that network call in the initial load, you will do after five seconds, like we are doing. Suppose we need the five call in the first second and then another 10 after five seconds. So we have added in the set time out and just call after five seconds. So that the browser will load the JavaScript and all things. We are doing these types of tricks also. Anyone else? Anyone else? Yes. Yes. So the tree shaking is much more granular. It actually looks into each functional of your code. So there are no plugins that I'm aware of or tools that I'm aware that can tell you exactly what tree shaking is using. But you can still use Lighthouse and that will tell you exactly that you can remove there is unused code on your, unused code that is loaded here right now. Or there is also for CSS there is dead coding elimination plugins that available. But for JavaScript I'm not aware of there are any tools available. Anything else? Thank you. Thanks all for your valuable time. Thanks for coming.