angular
March 25

Разбор файлов Angular Cache

Начиная с Angular 13, в исходном коде появилась новая папка .angular. Она хранит в себе набор кэшей для Angular CLI, а так же позволяет ускорить время сборки проекта. Рассмотрим, что же там внутри.

Перед тем как идти дальше стоит ознакомиться с официальной документацией Angular. Приведу переведенный отрывок.

Настройки кэша

По умолчанию кэширование на диске включено только при локальной разработке. Значение может быть одним из следующих:

all - разрешает кэширование на диске на всех машинах.

local - разрешает кэширование на диске только при разработке.

ci - разрешает кэширование на диске только на системах непрерывной интеграции (CI).

Настройка осуществляется с использованием команды
ng config cli.cache.environment all/local/ci


Разберем подробнее, из чего состоит кэш

Angular CLI создает две папки в каталоге .angular/cache, а именно angular-webpack и babel-webpack. Эти папки будут находиться внутри папки с названием версии Angular - в данном случае это версия 16.0.6.

Папка angular-webpack содержит бинарные файлы, которые мы не можем просто прочитать в редакторе. Однако папка babel-webpack содержит текстовые файлы в формате .json. Давайте их рассмотрим.

Рассмотрим на примере

Создадим standalone компонент с именем DashboardComponent со своими собственными файлами .html и .ts. Вот исходный код этих файлов.

// dashboard.component.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-dashboard',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class DashboardComponent { }

// dashboard.component.html
<p>dashboard works!</p>

Далее рассмотрим содержимое кэша детально

Babel-Webpack

При выполнении команды ng serve после добавления компонента в папке babel-webpack будет создан .json-файл с произвольным именем для DashboardComponent. В моем случае это был файл с именем a20f3a66c16f4139bce3c683fa26d4d34a146eb4dc65e9d8d1f2b491f95a9d62.json. Вот его содержимое:

// a20f3a66c16f4139bce3c683fa26d4d34a146eb4dc65e9d8d1f2b491f95a9d62.json
{
    "ast": null,
    "code": "import { CommonModule } from '@angular/common';\nimport * as i0 from \"@angular/core\";\nexport class DashboardComponent {}\nDashboardComponent.ɵfac = function DashboardComponent_Factory(t) {\n  return new (t || DashboardComponent)();\n};\nDashboardComponent.ɵcmp = /*@__PURE__*/i0.ɵɵdefineComponent({\n  type: DashboardComponent,\n  selectors: [[\"app-dashboard\"]],\n  standalone: true,\n  features: [i0.ɵɵStandaloneFeature],\n  decls: 2,\n  vars: 0,\n  template: function DashboardComponent_Template(rf, ctx) {\n    if (rf & 1) {\n      i0.ɵɵelementStart(0, \"p\");\n      i0.ɵɵtext(1, \"dashboard works!\");\n      i0.ɵɵelementEnd();\n    }\n  },\n  dependencies: [CommonModule],\n  styles: [\".container[_ngcontent-%COMP%] {\\n  display: flex;\\n  justify-content: center;\\n}\\n/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8uL3NyYy9hcHAvZGFzaGJvYXJkL2Rhc2hib2FyZC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNJLGFBQUE7RUFDQSx1QkFBQTtBQUNKIiwic291cmNlc0NvbnRlbnQiOlsiLmNvbnRhaW5lciB7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbn0iXSwic291cmNlUm9vdCI6IiJ9 */\"],\n  changeDetection: 0\n});",
    "map": {
        "version": 3,
        "names": [
            "CommonModule",
            "DashboardComponent",
            "selectors",
            "standalone",
            "features",
            "i0",
            "ɵɵStandaloneFeature",
            "decls",
            "vars",
            "template",
            "DashboardComponent_Template",
            "rf",
            "ctx",
            "ɵɵelementStart",
            "ɵɵtext",
            "ɵɵelementEnd",
            "styles",
            "changeDetection"
        ],
        "sources": [
            "/Users/balramchavan/Documents/projects/angular-videos/ng-what-ifs/src/app/dashboard/dashboard.component.ts",
            "/Users/balramchavan/Documents/projects/angular-videos/ng-what-ifs/src/app/dashboard/dashboard.component.html"
        ],
        "sourcesContent": [
            "import { ChangeDetectionStrategy, Component } from '@angular/core';\nimport { CommonModule } from '@angular/common';\n\n@Component({\n  selector: 'app-dashboard',\n  standalone: true,\n  imports: [CommonModule],\n  templateUrl: './dashboard.component.html',\n  styleUrls: ['./dashboard.component.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class DashboardComponent {\n\n}\n",
            "<p>dashboard works!</p>\n"
        ],
        "mappings": "AACA,SAASA,YAAY,QAAQ,iBAAiB;;AAU9C,OAAM,MAAOC,kBAAkB;AAAlBA,kBAAkB,C;mBAAlBA,kBAAkB;AAAA;AAAlBA,kBAAkB,C;QAAlBA,kBAAkB;EAAAC,SAAA;EAAAC,UAAA;EAAAC,QAAA,GAAAC,EAAA,CAAAC,mBAAA;EAAAC,KAAA;EAAAC,IAAA;EAAAC,QAAA,WAAAC,4BAAAC,EAAA,EAAAC,GAAA;IAAA,IAAAD,EAAA;MCX/BN,EAAA,CAAAQ,cAAA,QAAG;MAAAR,EAAA,CAAAS,MAAA,uBAAgB;MAAAT,EAAA,CAAAU,YAAA,EAAI;;;iBDMXf,YAAY;EAAAgB,MAAA;EAAAC,eAAA;AAAA"
    },
    "metadata": {},
    "sourceType": "module",
    "externalDependencies": []
}

Разберем его содержимое

ast: Абстрактное Синтаксическое Дерево. Это дерево создается и используется компилятором Angular для токенизации исходного кода, проверки на наличие синтаксических ошибок. Файл кеширует информацию, необходимую для его построения
map: По моему пониманию, это отображение пар ключ-значение, используемое Angular CLI для поиска и замены исходного кода токенами из массива имен. Например, ключевое слово DashboardComponent_Template может использоваться для поиска определения в свойстве кода.
code: Это скомпилированный исходный код компонента Dashboard. После форматирования значения свойства кода вы можете видеть, что у нас есть весь код из файла dashboard.component.ts

// "code"

"code": "import { CommonModule } from '@angular/common';\n
import * as i0 from \"@angular/core\";\n
export class DashboardComponent {}\n
DashboardComponent.ɵfac = function DashboardComponent_Factory(t) {\n
 return new (t || DashboardComponent)();\n
};\n
DashboardComponent.ɵcmp = /*@__PURE__*/i0.ɵɵdefineComponent({\n
  type: DashboardComponent,\n
  selectors: [[\"app-dashboard\"]],\n
  standalone: true,\n
  features: [i0.ɵɵStandaloneFeature],\n
  decls: 2,\n
  vars: 0,\n
  template: function DashboardComponent_Template(rf, ctx) {\n
    if (rf & 1) {\n
      i0.ɵɵelementStart(0, \"p\");\n
      i0.ɵɵtext(1, \"dashboard works!\");\n
      i0.ɵɵelementEnd();\n
    }\n
  },\n
  dependencies: [CommonModule],\n
  styles: [\".container[_ngcontent-%COMP%] {\\n
  display: flex;\\n
  justify-content: center;\\n
}\\n
/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8uL3NyYy9hcHAvZGFzaGJvYXJkL2Rhc2hib2FyZC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNJLGFBQUE7RUFDQSx1QkFBQTtBQUNKIiwic291cmNlc0NvbnRlbnQiOlsiLmNvbnRhaW5lciB7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbn0iXSwic291cmNlUm9vdCI6IiJ9 */\"],\n
  changeDetection: 0\n});",


На второй строке вы видите скомпилированную версию исходного кода.

import * as i0 from \"@angular/core\";\n
--
import { ChangeDetectionStrategy, Component } from '@angular/core';

Далее стоит обратить внимание, что компонент DashboardComponent был преобразован в чистую функцию JavaScript. Свойства декоратора @Component, которые мы указали, были переданы этой функции. Есть пара вещей, на которые я бы хотел обратить внимание в этом случае: стили - даже несмотря на то, что у нас был отдельный файл .scss, в кэшированной версии был добавлен класс .container в массив стилей декоратора Component.

Второй элемент - это sourceMappingURL. Когда вы включаете свойство sourceMap в файле angular.json, это значение используется для загрузки исходного кода в браузере, чтобы вы могли просматривать исходный код во вкладке исходного кода браузера в DevTools, вставив ключевое слово debugger в свой исходный код или явно установив точку останова в браузере.

  • Source: Массив файлов для кэширования. Обратите внимание, что файл Dashboard.component.scss отсутствует, так как его содержимое уже помещено в компонент
  • SourcesContent: Массив строк, в котором каждое значение содержит исходный код файла с тем же индексом в свойстве Source ранее без каких-либо изменений
  • sourceType: Обычно устанавливается на модуль для схем Angular, таких как компоненты, сервисы и т. д. Для сторонних библиотек, таких как moment.js или rxjs, устанавливается на script
  • metadata и externalDependencies: Я не смог найти пример, чтобы увидеть, что генерируется в кэше, но я вернусь к этой статье, как только найду что-то.

Ошибки при работе с кэшем

Когда вы работаете над большим проектом, файлы кэша Angular CLI могут доставить немало проблем. Возможно, вы получите ошибку в файле, в котором нет ошибок, или браузер выдаст ошибку любую другую ошибку, хотя исходный код исправен. Первое, что вы сделаете, - попытаетесь найти проблему в исходном коде. Первым делом всегда стоит почистить кэш командой angular cache clean, а затем снова запустить команду ng serve.

Если кэш каким-то образом сильно замедляет работу компьютера, кэширование можно отключить используя команду ng cache disable или ng cache off.

Перед отправкой кода в удаленный репозиторий папку с кэшем обязательно исключить из индекса

Удалите папку .angular cache перед тем как поделитесь исходным кодом (или внесите в .gitignore), чтобы сократить размер передаваемых файлов (а так же количество проблем при запуске на другой машине).

Это вольный перевод материала