Angular Application Optimization

Original author: J Stepanyan
  • Transfer
Angular is the most popular framework for developing single-page web applications, although this does not mean that Angular applications can contain only one page. With this framework, you can create sites consisting of dozens of pages. The latest version of Angular, thanks to the efforts of the development team and the community of enthusiasts, is well optimized. However, when it comes to a specific application, we must not forget about some things that affect its performance. In the material, the translation of which we publish today, six directions of optimization of Angular-applications will be revealed.





1. Lazy loading and optimization of the main bundle


If the lazy loading is not used when preparing the production version of the application, then most likely distyou will see the following files in the folder .

polyfills.js
scripts.js
runtime.js
styles.css
main.js

The file polyfills.jsallows you to ensure the compatibility of an application written using the latest features of web technologies with different browsers.

The file script.jscontains the scripts described in the scriptsfile section angular.json. Here is a simple example of such a section.

"scripts": [
   "myScript.js",
]

The file runtime.jsis a Webpack loader. It contains the Webpack tools needed to download other files.

The file styles.csscontains the styles declared in the stylesfile section angular.json. Here is an example of this section.

"styles": [
  "src/styles.css",
  "src/my-custom.css"
],

The file main.jsstores all application code, including components (TS, HTML and CSS code), pipelines, directives, services, and imported modules (including third-party modules).

As the application grows and develops, the file size main.js grows . This can turn into a problem, because, in order to form a page, the browser, besides solving other data visualization tasks, needs to load and parse the file main.js. If this file is large enough, its processing will be a difficult task not only for mobile, but also for desktop browsers.

The easiest way to solve this problem is by dividing the application into several modules, with which the lazy loading technique is used. With this approach, Angular generates a separate file for each module, which will not be loaded until it becomes necessary (usually, when a certain route is activated).

In order to demonstrate the application of the lazy loading technique, two components were created - app.componentand second.component. Both of them are in the module app.module, lazy loading does not apply when working with them.

The component is app.componentextremely simple. He displays two buttons, one of which is responsible for the transition to second.component, and the second leads back to app.component.


Component App

The component templateSecondcontains a very large fragment of text with a volume of approximately 1 MB.


Component Second

Since the lazy loading technique is not used here, our application will have amain.jslargefilecontaining the codeapp.componentandsecond.component.

If you open the Chrome developer tools and look at the Network tab, you can estimate the file sizemain.js. Namely, it is 1.3 MB.


Analysis of file sizes by means of Chrome developer tools.

The problem here is that most of the time when working with our project, the user will be on his main page, and not on some other one, so downloading all the code as a single file is not a good idea. . The code of the second component can be transferred to a separate module, which will be loaded only if the user navigates to the appropriate page. This is reflected in a significant reduction in the filemain.js, which gives a very fast first loading of the main page of the site.

When using the lazy loading technique, after the project build process is completed, a file like this will be created.4.386205799sfghe4.js. This is where the code that does not load when the site first loads will be stored. As a result, if you now open the site and analyze it, it turns out that the dimensions main.jsare only 266 KB.


Reducing the size of main.js

A large additional file of 1 MB in size is loaded only after going to the appropriate page.


Downloading an additional file

We have applied the lazy download, but one cannot say that we are completely satisfied with this solution. The fact is that such an approach slows down the user's first transition to the page, for output of which a separate large file is needed. Fortunately, Angular provides a means to solve this problem. Namely, we are talking about technology PreloadingStrategy .

Using it, we can tell the framework that, after the main module (filemain.js)is loaded and processed, it would load, in the background, other modules. As a result, when the user navigates to a page that previously needed to download a large file, it turns out that this file has already been downloaded. Here is a sample code to preload all modules.

import { PreloadAllModules, RouterModule } from'@angular/router';
RouterModule.forRoot(
[
 {
    path: 'second',
    loadChildren: './second/second.module#SecondModule'
 } 
], {preloadingStrategy: PreloadAllModules})

When applying lazy loading when optimizing Angular applications, it is recommended to strive to break the project into as many modules as possible. In addition, you need to pay attention to their preloading. This will make the file main.jshave a small size, which means faster loading and displaying the main page of the project.

2. Analysis of bundles using Webpack Bundle Analyzer


If even after dividing the project logic into multiple modules it turns out that it main.jsis still too large (for small and medium-sized applications, the author of this material suggests to consider a large 1 MB file), you can continue to optimize the application using Webpack Bundle Analyzer. This npm package allows you to visualize the results of the Webpack work in the form of a tree structure that supports zooming the view. In order to use the Webpack Bundle Analyzer, we will install it in the Angular project as a development dependency.

npm install --save-dev webpack-bundle-analyzer

Then we modify the section of the scriptfile package.json, adding the following text to it.

"bundle-report": "ng build --prod --stats-json && webpack-bundle-analyzer dist/stats.json"

Please note that the file address dist/stats.jsonmay be different in your project. For example, if you are ready to bundle files in the folder dist/browser, you will need to re-write the above line as follows: dist/browser/stats.json.

Now run the analyzer.

npm run bundle-report

After executing this command, the production assembly of the application will be generated and the statistics for each bundle will be displayed. Here is the result of the visualization of this data.


Project analysis using Webpack Bundle Analyzer

Now you can analyze the composition of each bundle. This is a very useful tool that allows you to identify dependencies, without which you can do.

3. Create several small modules for sharing


Modules that share different parts of an application contribute to the implementation of the DRY principle , but sometimes even such modules, as the application develops, become more and more. For example, if we have a certain module SharedModulecontaining many other modules, components, pipelines, importing such a module app.modulewill increase the size of the bundle main.js, since such a move will lead not only to the import of what is needed main.js, but also all that is SharedModule. In order to avoid such a situation, you can create another module, something like HomeSharedModule, intended to be shared by the main module and its components.

The presence in the project of several modules intended for sharing is better than the presence of only one such module, usually having large dimensions.

4. Using lazy loading for images that are not visible on the page.


When you first load the main page of the application, it may be that there are images on it that are not visible to the user (they are outside the viewing area). In order to see them, you need to scroll the page. But these invisible images are loaded when the page loads. If there are a lot of them, it will affect the page loading speed. In order to cope with this problem, you can apply a lazy loading technique to images, loading them only when the user gets to them. There is one useful JS tool, Intersection Observer , which makes it easy to implement lazy loading of images. Moreover, in order to reuse, on the basis of it you can create an appropriate directive. Details about this can be found here .

5. Using virtual scrolling for long lists


In the seventh version of Angular there is the possibility of using virtual scrolling . This technology loads elements into the DOM and unloads them based on how much of the list is visible to the user. This greatly speeds up the work of applications that use long lists.


Only visible list items are displayed on the page.

6. Use of FOUT strategy for working with fonts instead of FOIT strategy


Many sites use non-standard fonts. They usually look very attractive, but their use creates an additional load on the browser, as it has to download these fonts and prepare them for work. When using non-standard fonts, say, downloaded from a third-party service like Google Fonts, the following two scenarios are possible:

  1. The browser loads the font, processes it and only then displays the text. Until the font is ready for use, the text typed in this font will be invisible. This is called FOIT (Flash of invisible text).
  2. The browser initially displays text using a standard font, while performing the loading of the external font. When this font is ready for use, the standard font changes to that particular font. As a result, it turns out that the text on the page will be displayed in a standard font until a special font is loaded, after which the text will be displayed again, but in a new font. This is called FOUT (Flash of unstyled text).

Most browsers use the FOIT strategy when working with non-standard fonts, the FOUT strategy is used only in Internet Explorer. In order to use FOUT instead of FOIT, you can use a descriptor font-displayfor @font-face, and tell the browser whether we want the text to be first displayed in standard font, and then ours, or we are satisfied with a certain period of invisibility of the text. If you are interested in the topic of fonts - take a look at this material. In particular, here you can find information about the features of the work of the fonts and recommendations regarding the choice of the FOIT or FOUT strategy.

Results


Here we looked at several techniques for optimizing Angular applications. In fact, there are many more. In particular, we are talking about server rendering, the use of service workers, AMP pages. The expediency of optimization and the choice of its methods depend on the specific project - on its features and goals.

Dear readers! What approaches do you use to optimize Angular applications?


Also popular now: