Latest news about Bitcoin and all cryptocurrencies. Your daily crypto news habit.
As developers we all tend to have our own views regarding technologies, languages and frameworks. We argue a lot about code style, indentation and best practices. However, If there is one thing that we can all agree on, it is that performance is of the upmost importance.
As we know the average timespan of a person tends to get lower and lower. We focus on sending a loader or something as soon as we can so we can grab the userâs attention and prevent him from bouncing from our page. It doesnât matter how good our code is if the user doesnât get the chance to even load the app in the first place.
Front-end development is incredibly dynamic. Thanks to that, we now have an abundance of incredible tools that can help us improve the performance of our web applications.
While some of the concepts in this article is focused on Webpack and React, they can be applied to applications built with Angular, Vue or other JS frameworks.
What to Optimise
When we are talking about web performance we need to take two different processes into account. The first is how and what code are we sending to the user. The second is how well this code works when it is executed in the userâs browser.
When a user wants to open our app we will send him some amount of HTML, CSS and JavaScript. How fast those arrive and how fast they are parsed and executed is the first thing we need to take care of when it comes to performance.
Then, we need to examine the code we are writing and how fast it will work once itâs actually running in the browser. Because it doesnât matter how fast we send files over the web if our app is slow.
Where to Start?
Okay, so weâve got a web app and we want to make it a little bit faster. We want it to load fast and we want to have snappy UIs. The app needs to have a good user experience on mobile and desktop devices and SEO and Accessibility are considered a big plus.
Instead of blindly making improvements where we deem them necessary we can use Lighthouse to tell us what we are doing wrong. In the Chrome developer tools, go to Audits and perform an audit of your app.
This will take a couple of minutes and it will run a variety of tests on the page you currently are. Then it will give you a score and point out particular places in which you need improvements. The audit is quite exhaustive and it will give you feedback for the time to first meaningful paint, time for the app to be interactive and even correct font sizes on mobile.
Reducing Code
The best way to minimise the time in which those files reach the user is to minimise the amount of code you are sending at a single moment. This is a general concept that will be true in the foreseeable future. Modern devices tend to be really fast when it comes to parsing and executing code, but they canât do any of that until the code is actually there.
Uglifying Code
Proper code formatting is necessary only for good developer experience. When it comes to actual execution, the engine doesnât care if all you code is jammed into a single line. Thatâs why we can uglify it.
This technique will remove the unnecessary blank spaces in our code and basically squash everything in as little space as possible. It will discard certain things like variable names and use shorter ones like a and b. This reduces the amount of characters our files contain therefore reducing the overall size of the file weâll be sending.
In Webpack this is done as simply as adding the uglifyjs-webpack-plugin in your configuration.
Bundling
We should now consider how we group our files together and how we send them to the user. The most common practice is to put all the JavaScript into a single file called bundle.js and send everything together.
This is a perfect solution for medium to small apps. But as it grows larger in size, the larger our bundle will be. It will also contain more library code and assets that will accumulate in time.
At one point we will be sending too much code on the userâs first request, while he will only need a part of that to load the site. We donât want to send him everything if we can give him only the bare minimum and then load the rest when he needs it.
In React this is easily achievable using dynamic imports. Instead of importing a component in the normal way, we can use the import() function which returns a promise. This allows us to load certain components only when we actually need them.
There is no benefit in dynamic imports if we still bundle everything together, so whenever we use import(), Webpack will know to split the other component in a separate bundle.
To give an example, if our application has three different routes we can import() them separately. Webpack will then generate 4 different bundlesâââone main and one for each route. Now if a user lands on one of our routes we will give him the main bundle and the one for the route.
Code splitting is easy to understand and easy to implement. However, like everything else there are catches. You need to be wary of what your bundles contain or you can end up with 3 bundles each one importing the same components or libraries.
Prefetching and preloading
Now that we know what code splitting is we can look at additional optimization techniques like prefetching and preloading.
We may end up with four or five different JS files which the user will request only when necessary. In certain situations, however, the chances of him requesting a certain bundle will be high. If he is on a page that lists some resources, his next step will most likely be to open a resource and request its bundle.
Since we know the flow of our app, we can do some further optimisations and provide the user the code he will need in the future, so when he needs it it will already be there.
Prefetching is one of the techniques we can use. With it we can signal to the browser that it should load certain scripts while itâs idle. This is used for things that the user may need but we donât want to send them while he is waiting for the page to load.
In Webpack context we can signal it by adding a comment inside the import statement: import(/* webpackPrefetch: true */ '../Resource').
The second technique is called preloading. It is meant to be used for resources of higher priority. By specifying that a component needs to be preloaded we tell the browser that the user will absolutely need that file but we neednât block the layout while loading it.
Like in the prefetching example we can signal that we want this component to be preloaded by adding a comment in the import statement:import(/* webpackPreload: true */ '../Resource')
React Loadable
Now that we understand code splitting and the different techniques that we can use to optimise the user experience we can look at a solution that packs all that functionality. react-loadable is possibly the most widely adopted library when it comes to code splitting.
We can wrap our component into a Loadable and it will get split into an additional bundle. We can also specify a loading component that the user will see while weâre loading and other useful options.
The Loadable component also provides you with the ability to prefetch it. If you are sure that the user will need that component you can use the static .preload() method to signal that you need that bundle. For example, you can start prefetching a component when the user hovers over a button instead of waiting for him to click it.
As an addition to that, react-loadable will take care of the configuration when it comes to splitting common logic between components. If you have components that have common dependancies it will try to bundle those together and load them only when they are required.
If two of your components rely on a library and they are in two separate bundles, react-loadable will make you another bundle which will get loaded the first time one of those components are called.
Unless you need some custom behavior and configuration I would strongly advice you to use this or one of the other libraries that provide everything out of the box.
Separating CSS
Depending on your configuration or the boilerplate that youâre using you can end up in a situation in which your CSS is bundled together with your JavaScript.
This is not necessarily a bad practice. Some people swear by splitting them, other are advocates of keeping them together. It depends on your setup. You can use the mini-css-extract-plugin to extract CSS out of the bundle when you are building for production and have them separated. As a bonus, if you have separate bundles you will get a CSS file generated for each one of them.
The pros of this approach is that will further lessen the amount of code in your files and their overall size. Also you will be able to send them concurrently.
As for cons, it makes the setup more complicated so you need to consider if this is a trade off you are willing to make.
Code Execution
Our code is now performantly delivered to the user so we can focus on how it works once itâs running in the browser.
As we all know, React is fast. So when we are talking about optimising React applications, we should be talking more in terms of optimising the code we write.
The library works fast enough on its own but we as developers sometimes make mistakes or donât have a good enough understanding of how things work, so we can introduce performance issues.
Premature Optimization
There are a lot of articles that can give you performance tips. How to properly bind functions to avoid creating multiple ones when rendering or how to avoid binding functions at all.
If I can give one solid tip in this section then it should be to avoid optimising anything before you see an actual problem. Working around non-existing issues can often do more harm than good.
This doesnât mean not to write your apps with performance in mind. There are considerations that you need to make when you are deciding how to build your components and those are exactly the ones we will take a look at here.
Measuring Performance
We mentioned briefly that you need to measure your performance before you start optimizing anything, so letâs discuss how to actually do that. The React ecosystem has a lot of great tools that you can use from the browser.
If you have the React browser extension you can open your app in development mode and click the âHighlight updatesâ checkbox in the dev tools. When this is enabled React will highlight any components that rerender. Depending on how often they rerender the color of the highlight will go more towards red.
This is by far the best way to debug your appâââtaking the actions that a user would and seeing how it behaves. What you are striving for here is to have only the components you are interacting with highlighted. If you are typing something in a form and the whole page blinks then thatâs a signal thatâs probably a rerender that you can avoid.
You can read about performance measuring in the official React docs here.
Rendering Components
In my opinion the biggest performance hit your app can take is the unnecessary rerendering of the UI. React does a lot of work under the hood to make sure our components behave as they should but there are times in which your components will rerender even though you expect them not to.
What we want to achieve is to minimise the amount of times that the components call their render method so we need to have some things in mind and implement fail-saves where necessary.
As we know a component is rerendered when it changes its state or it receives new props. So while we can control when we are running `setState` internally in the component, we would also like to have more control over the props the component receives.
The way to do that is to implement the `shouldComponentUpdate` method. It receives the new props and new state as arguments and expects a boolean value to be returned. The return value signals React whether to rerender or not. Essentially what we want to do in this method is validate if the incomming props are different than the ones we currently have.
We may be receiving three or four different props but our component relies only on one of them after the initial render, so we neednât re-render it every time one of the others change. If you have any sort of logical dependancy between your state and props this is also a good place to check if a rerender is really necessary.
Unless you have some specific logic, shouldComponentUpdate tends to be a routine task and can result in a long list of checks especially if your component expect a lot of props. In order to avoid writing repetitive logic, we can have our component extend React.PureComponent instead of React.Component. There is no difference in the behaviour of the class, with the exception that it will implement shouldComponentUpdate by default. It will run a shallow equality comparison between the current and the new props and render only when there is a difference.
Responsiveness
We usually talk about responsiveness in the context of design. However, making sure our apps look good on different screens and devices is just one of the steps we can take towards responsiveness.
Screens of mobile devices provide a lot less real estate than laptops so we usually show a lot less information. Some elements may be hidden or completely removed from the screen in order to provide the user with the essential functionality that will fit on his device.
In cases when the differences between mobile and desktop devices is big, we can use two different components. We neednât send more code if the user needs only half of it. To be honest, sometimes the difference between screens is so big that using two completely different versions is easier than fitting everything with CSS.
We can get information about the device the user is using from window.navigator.userAgent. This gives us further flexibility if we want to send different functionality to users of different devices.
Images
Following the topic of responsiveness, itâs also good to consider how our application will handle large images. I donât need to stress how big of a bottleneck improper handling of images can be.
If we know that the user is accessing our app from a mobile device we should show him a smaller image. With image hosting services like Cloudinary this is painless. It handles all image cropping and transformations for us, so all we need to do is send the proper size with the request.
We should also consider lazy loading if we have a lot of images off screen when the user loads the app. Tools like react-lazyload do the heavy lifting for us, by wrapping the images we will be rendering.
Improving the Performance of JavaScript Applications was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.
Disclaimer
The views and opinions expressed in this article are solely those of the authors and do not reflect the views of Bitcoin Insider. Every investment and trading move involves risk - this is especially true for cryptocurrencies given their volatility. We strongly advise our readers to conduct their own research when making a decision.