Skip to main content

Angular SPA Preset

Preset file: presets/angular-spa.toml

Works with Angular 14+ in both standalone and module-based configurations.

Overview

Angular applications bootstrap into an <app-root> component and use Zone.js to track asynchronous operations. Angular's compiler generates _ngcontent-* and _nghost-* attributes for view encapsulation, and ng-* attributes for framework directives.

Key Configuration

[render]
wait_for = "networkidle"
timeout_secs = 15

[render.postprocess]
enabled = true
strip_scripts = true
strip_noscript = true
strip_comments = true
strip_event_handlers = true
strip_hydration_attrs = true # Removes ng-*, _ngcontent-*, _nghost-*
resolve_lazy_images = true

[render.content_validation]
enabled = true
min_text_length = 100
require_title = true
min_html_bytes = 1024

Zone.js and networkidle

Angular uses Zone.js to track all asynchronous operations (HTTP requests, timers, promises). The networkidle wait strategy works well with Angular because Zone.js ensures that all data fetching completes before the framework considers the view stable.

If your Angular app has background polling or WebSocket connections, these can prevent networkidle from resolving. In that case, use a selector wait:

[render]
wait_for = "app-root .content-loaded"

Hydration Attribute Stripping

With strip_hydration_attrs = true, PRISM removes:

AttributePurpose in AngularWhy It's Stripped
ng-versionAngular version markerDebugging only
ng-reflect-*Template binding debug infoDevelopment mode only, but sometimes leaks to prod
_ngcontent-*View encapsulation scope IDOnly meaningful with Angular's emulated CSS scoping
_nghost-*Host element scope IDOnly meaningful with Angular's emulated CSS scoping

Before:

<app-root _nghost-abc="" ng-version="17.0">
<div _ngcontent-abc="" class="container">
<h1 _ngcontent-abc="">Products</h1>
</div>
</app-root>

After:

<app-root>
<div class="container">
<h1>Products</h1>
</div>
</app-root>

Angular Universal (SSR)

If your Angular app uses Angular Universal for server-side rendering, PRISM is typically unnecessary. However, PRISM can still help with:

  • Pages that rely heavily on client-side data fetching after SSR.
  • Hybrid apps where some routes are SSR and others are CSR.
  • Legacy Angular apps that cannot easily adopt Universal.

Route Exclusions

The preset excludes Angular-specific assets:

[routes]
exclude = [
"/api/**",
"**/*.js", "**/*.css", "**/*.json", "**/*.xml",
"**/*.png", "**/*.jpg", "**/*.gif", "**/*.svg", "**/*.ico",
"**/*.woff", "**/*.woff2", "**/*.ttf", "**/*.wasm", "**/*.map",
"/assets/**",
"/manifest.json", "/ngsw.json", "/ngsw-worker.js",
"/robots.txt", "/sitemap.xml",
]

Note the Angular-specific exclusions: /ngsw.json and /ngsw-worker.js are Angular's service worker files.

Full Preset

presets/angular-spa.toml
[render]
wait_for = "networkidle"
timeout_secs = 15

[render.postprocess]
enabled = true
strip_scripts = true
strip_noscript = true
strip_comments = true
strip_event_handlers = true
strip_hydration_attrs = true
resolve_lazy_images = true

[render.content_validation]
enabled = true
min_text_length = 100
require_title = true
min_html_bytes = 1024

[routes]
include = ["/**"]
exclude = [
"/api/**",
"**/*.js", "**/*.css", "**/*.json", "**/*.xml",
"**/*.png", "**/*.jpg", "**/*.gif", "**/*.svg", "**/*.ico",
"**/*.woff", "**/*.woff2", "**/*.ttf", "**/*.wasm", "**/*.map",
"/assets/**",
"/manifest.json", "/ngsw.json", "/ngsw-worker.js",
"/robots.txt", "/sitemap.xml",
]