Как вы оптимизируете загрузку и производительность Angular-приложения на проде?

Оптимизация загрузки и производительности Angular-приложения на продакшене требует комплексного подхода, охватывающего архитектуру, сборку, загрузку ресурсов, работу с данными и стратегию рендеринга. Ниже перечислены ключевые практики, применяемые для ускорения загрузки и повышения производительности.

1. Production сборка (ng build --configuration production)

Angular CLI при прод-сборке:

  • Минифицирует HTML, CSS, JS;

  • Удаляет console.log и debugger;

  • Применяет tree-shaking;

  • Включает Ahead-of-Time (AOT) компиляцию;

  • Генерирует файлы с хешами для кэширования.

2. Lazy Loading модулей

Lazy loading позволяет загружать части приложения только по требованию.

const routes: Routes = \[
{
path: 'admin',
loadChildren: () =>
import('./admin/admin.module').then((m) => m.AdminModule)
}
\];
  • Уменьшает размер initial bundle;

  • Улучшает Time to Interactive (TTI).

3. Preloading Strategy

Чтобы загружать ленивые модули после начальной загрузки, применяют стратегию preloading:

RouterModule.forRoot(routes, {
preloadingStrategy: PreloadAllModules
});

Или создают собственную стратегию на основе пользовательской логики.

4. Использование Standalone компонентов

С Angular 14+ можно использовать standalone-компоненты без модулей:

@Component({
standalone: true,
imports: \[CommonModule\],
template: \`<p>Hello</p>\`
})
export class HelloComponent {}

Уменьшается связность, ускоряется загрузка, снижается объем кода.

5. ChangeDetectionStrategy.OnPush

По умолчанию Angular использует ChangeDetectionStrategy.Default, что может привести к лишнему пересчету.

@Component({
changeDetection: ChangeDetectionStrategy.OnPush
})
  • Проверка запускается только при изменении @Input();

  • Уменьшает нагрузку на зону детектирования.

6. TrackBy для ngFor

Чтобы избежать перерисовки всех элементов при изменении массива:

<li \*ngFor="let item of items; trackBy: trackById">{{ item.name }}</li>
trackById(index: number, item: Item) {
return item.id;
}

Сохраняет DOM-элементы и уменьшает работу рендера.

7. Оптимизация изображений

  • Использовать ngOptimizedImage (Angular 15+);

  • WebP/AVIF-форматы;

  • Ленивая загрузка (loading="lazy");

  • Использовать CDN и srcset.

8. Code splitting и dynamic imports

Разделение кода на чанки для загрузки по мере необходимости:

async loadModule() {
const module = await import('./some-heavy.module');
// используем module.SomeComponent
}

Это снижает размер основного бандла.

9. Удаление неиспользуемого кода (Tree Shaking)

  • Не импортировать весь модуль, если нужен один компонент;

  • Избегать реэкспорта всего модуля (SharedModule);

  • Использовать ES модули, не CommonJS;

  • Строгий режим в tsconfig улучшает tree-shaking.

10. Оптимизация сторонних библиотек

  • Не подключать библиотеки целиком (import { map } from 'rxjs', а не rxjs/operators);

  • Проверять размер через webpack-bundle-analyzer;

  • Использовать легковесные аналоги (lodash-es, date-fns).

11. Использование defer и async

При вставке скриптов:

<script src="some-lib.js" defer></script>

Скрипты загружаются асинхронно, не блокируя рендеринг страницы.

12. Уменьшение количества зон (Zone.js)

Angular 16+ поддерживает signals и zone-less режим.

Это позволяет избежать лишних перерисовок и повысить производительность.

13. Серверный рендеринг (Angular Universal)

  • Быстрая первая отрисовка (First Contentful Paint);

  • SEO-дружественность;

  • Пререндеринг с ng run app:prerender.

14. Управление памятью и подписками

  • Всегда отписывайтесь от Observable:

    • takeUntil;

    • async pipe;

    • untilDestroyed.

Неправильные подписки приводят к утечкам памяти и деградации производительности.

15. Оптимизация формы и реактивной логики

  • Использовать FormControl вне шаблона;

  • Избегать сложных реакций в form.valueChanges;

  • Использовать distinctUntilChanged, debounceTime для throttle.

16. HTTP кэширование

  • Реализовать стратегию кэширования на уровне сервиса:
@Injectable({ providedIn: 'root' })
export class ApiService {
private cache = new Map&lt;string, Observable<any&gt;>();
getData(url: string): Observable&lt;any&gt; {
if (!this.cache.has(url)) {
this.cache.set(url, this.http.get(url).pipe(shareReplay(1)));
}
return this.cache.get(url)!;
}
}
  • Использовать браузерный Cache-Control и CDN.

17. Service Workers и PWA

  • Использовать Angular PWA (ng add @angular/pwa);

  • Service Worker кэширует статику;

  • Offline поддержка;

  • Precache и runtime-кэширование данных и API.

18. Анализ и инструменты

  • source-map-explorer и webpack-bundle-analyzer — анализ размеров;

  • Lighthouse, PageSpeed Insights — метрики производительности;

  • Chrome DevTools — FPS, memory, layout shift, JS профайлинг.

19. Inlining critical CSS

CLI в режиме production автоматически выносит critical CSS в <head>, чтобы избежать FOUC и ускорить рендеринг.

20. HTTP/2 + CDN + GZIP/Brotli

  • Активировать HTTP/2 для одновременной загрузки;

  • Использовать CDN (Cloudflare, Akamai);

  • Сжатие GZIP/Brotli для всех ресурсов.

21. Динамическая подгрузка i18n и переводов

  • Загрузка только нужных переводов (ngx-translate, @angular/localize);

  • Lazy loading модулей с соответствующим языком.

22. Пререндеринг роутов

ng run app:prerender

  • Генерация статических HTML для всех маршрутов;

  • Идеально для маркетинговых страниц, SEO.

23. Кэширование с версионированием

  • Angular CLI генерирует файлы с хешами (main.[hash].js);

  • Браузер кэширует до тех пор, пока хеш не изменится;

  • Это уменьшает сетевую нагрузку при повторных визитах.

Оптимизация Angular-приложения — это не единоразовое действие, а постоянный процесс, который включает архитектурные решения, работу с данными, настройку сборки и эффективное использование возможностей Angular CLI и Webpack.