Ускорение начальной загрузки приложения

  1. Следите за зависимостями. Уже писал об этом ранее, но хочу рассказать про другой кейс, что ещё интересного можно увидеть в сборке (не «удалите moment.js», о чём пишут в 99 % статей на тему анализа зависимостей). В этот раз воспользуемся инструментом source-map-explorer.

    Меня сильно смутили эти es5 в части, занимающей треть всего бандла, учитывая "target": "ES2022" в tsconfig.json. Более того, в node_modules на каждый пакет есть две папки: es5 и es6. Написал разработчикам, признались, что это из-за их package.json, пообещав однажды его изменить. Но можно это исправить сразу, не дожидаясь обновления.

    Итак, нам нужно немного поменять процесс сборки, для этого в devDependencies добавляем пакет @angular-builders/custom-webpack. Далее правим angular.json:

    "architect": {
      "build": {
        "builder": "@angular-devkit/build-angular:browser",
        "builder": "@angular-builders/custom-webpack:browser",
        "options": {
          "customWebpackConfig": {
            "path": "./extra-webpack.config.js",
            "replaceDuplicatePlugins": true
          },
      ...
      "serve": {
        "builder": "@angular-devkit/build-angular:dev-server",
        "builder": "@angular-builders/custom-webpack:dev-server",

    И создаём конфиг вебпака, в котором прописываем алиасы для всех пакетов:

    const path = require('path');
    
    module.exports = {
      resolve: {
        alias: {
          '@ag-grid-community/client-side-row-model': path.resolve('./node_modules/@ag-grid-community/client-side-row-model/dist/esm/es6/main'),
          '@ag-grid-community/core': path.resolve('./node_modules/@ag-grid-community/core/dist/esm/es6/main'),
          ...
          'ag-charts-community': path.resolve('./node_modules/ag-charts-community/dist/esm/es6/main'),
        }
      }
    }
    

    Пересобираем всё это дело.

    В результате сэкономили 390 KB в прод-сборке.

  2. Следите за нетворками.

    Вот этот огромный запрос на тысячи записей и сотни килобайт для селектов на старте приложения кажется избыточным, поскольку нам они не нужны все сразу. Сюда же хочется добавить и подпункт «следите за алгоритмами», поскольку изначально в коде была следующая логика: полученный массив сохранялся в стор, и из него готовились десятки списков для каждого из селектов путём банального array.filter(). Т. е. по одному и тому же массиву пробегались десятки раз. Благо это тысячи, а не миллионы записей, не столь критично, но ресурсы всё равно расходуются.

    Меняем логику, чтобы запрашивались лишь необходимые данные, самих запросов будет больше, но работать это будет быстрее. И, конечно же, дабы не ходить повторно в сеть, сохраняем полученные данные, но не в стор, а в собственный сервис, используя Observable с shareReplay(1).

    (На главной странице нет ни одного селекта, поэтому данный запрос вообще исчез из нетворков, значительно ускорив загрузку приложения.)

  3. Используйте ленивые модули и предзагрузку. Допустим, у нас есть приложение на 10 мегабайт, в котором 10 разделов. И довольно долго целиком загружать и парсить такой бандл. Используем lazy-loading, получаем 10 модулей, и теперь для первоначальной загрузки нам надо загрузить 1 мегабайт.

    Но теперь при переходе в другие разделы нам приходится ждать загрузки соответствующего модуля. Чтобы такого не было, мы можем предзагружать эти модули заранее. «Но в чём смысл этих двух манипуляций, мы одинаково загружаем те же самые 10 мегабайт на старте?», — спросил меня коллега.

    А смысл в том, что сначала мы загружаем модуль текущего раздела, следовательно, парсить код начинаем раньше, и в целом этого кода для парсинга гораздо меньше. А другие модули загружаются уже после того, как мы загрузили всё необходимое для инициализации приложения, в фоне. Причём это поведение можно настроить, например, если у пользователя в настройках стоит экономия трафика, или просто плохой интернет, то мы не будем загружать то, что не требуется в данный момент.

    Синяя линия — это DOMContentLoaded, красная — Load, а дальше уже тот самый preloading модулей, которые могут понадобиться при работе с приложением.

{{ message }}

{{ 'Comments are closed.' | trans }}