Theory
Shipping it, and keeping it fast
FestConnect's front end works on your machine; now it must go live for real users, and it must stay fast as the event list grows. Those are the last two front-end skills: deployment (building and hosting the app) and performance optimisation (making Angular do less work).
This lesson covers building a production bundle, using environments for per-stage settings, deploying to Firebase Hosting, and three performance techniques: trackBy, OnPush change detection, and lazy loading. With these, FestConnect is both shipped and snappy.
Theory
Building and environments
During development you run ng serve, but to ship you build: ng build --configuration production produces an optimised bundle, minified and tree-shaken (unused code removed), written to a dist folder ready to host.
Apps also need different settings in different stages, for example the API URL differs between your laptop and the live server. Angular handles this with environment files: environment.ts for development and environment.prod.ts for production, and the build swaps in the right one. So you keep the development API pointing locally and the production one pointing at the real backend, without editing code.
Practical
Build and deploy to Firebase Hosting
# Build an optimised production bundle into dist/
ng build --configuration production
# One-time setup, then deploy the built static files
firebase init hosting # point it at the dist/ output folder
firebase deploy # uploads and serves your app live
# Firebase Hosting serves the built files over HTTPS on a global CDN.Theory
Three ways to stay fast
As FestConnect grows, three techniques keep it responsive.
trackBy in a list (@for or ngFor) tells Angular how to identify each item, so when the list changes it reuses the DOM for unchanged items instead of rebuilding every row. OnPush change detection tells a component to re-check only when its @Input values change (not on every little event elsewhere), cutting needless work. Lazy loading (from the routing lesson) defers loading a page's code until it is visited, so the app starts faster.
Each does the same thing in spirit: do less work, only re-render, re-check, or load what actually needs it.
Practical
trackBy and OnPush
// OnPush: this component re-checks only when its @Input changes
@Component({
selector: 'app-events',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
@for (e of events; track e.id) { <!-- 'track' is trackBy: reuse DOM -->
<app-event-card [event]="e" />
}`,
})
export class EventsComponent {
@Input() events: Event[] = [];
}
// track e.id lets Angular reuse rows whose id is unchanged, instead of all.Quiz
In a long list of events that updates often, what does adding trackBy (track e.id) achieve?
- It sorts the list automatically
- It lets Angular reuse the DOM for unchanged items instead of re-rendering the whole list, improving performance
- It encrypts the list data
- It deletes items with duplicate ids
Show the answer
It lets Angular reuse the DOM for unchanged items instead of re-rendering the whole list, improving performance
trackBy tells Angular how to identify each item (by e.id), so when the list changes Angular can REUSE the existing DOM elements for items that are still the same and only touch what actually changed, instead of destroying and rebuilding every row. Option A is wrong: trackBy does not sort; it tracks identity. Option C is invented; it has nothing to do with encryption. Option D is wrong: it does not delete duplicates; it uses the id to match items across updates. Without trackBy, a list update can re-render every row (slow for long lists); with it, Angular does the minimum work. It is a do-less-work optimisation, the theme of performance tuning.
Think first
Why does OnPush change detection make an app faster?
Angular checks components for changes automatically. Why does OnPush, which checks less often, help rather than break things? Then tap.
Show the answer
Because by default Angular re-checks EVERY component very frequently (after almost any event anywhere in the app) to see if the view needs updating, and OnPush safely reduces that to only when a component's inputs actually change, so the app does far less redundant work. Change detection is how Angular keeps the screen in sync with your data: after events, it walks the component tree checking whether anything a template shows has changed. For a big app this can mean thousands of checks per interaction, most of which find nothing to update, wasted effort that can make the UI sluggish. OnPush tells Angular: 'this component's view depends only on its @Input values (and a few well-defined triggers), so you only need to re-check it when one of those inputs changes reference.' That lets Angular SKIP checking that component (and often its subtree) during the many change-detection passes where its inputs did not change, cutting the work dramatically. It does not break correctness as long as you follow the pattern (pass data down through inputs, treat inputs as immutable, use observables/async pipe for streams), which the smart/dumb structure naturally encourages, dumb components with clear inputs are ideal OnPush candidates. So OnPush is faster because it replaces 'check everything, all the time' with 'check this only when its inputs change', eliminating a huge amount of pointless recomputation while keeping the view correct. Less checking, same result, faster app.
Summary
Key takeaways
- To ship, build a production bundle: ng build --configuration production creates an optimised (minified, tree-shaken) dist folder.
- Environment files (environment.ts vs environment.prod.ts) hold per-stage settings like the API URL, swapped at build time.
- Firebase Hosting serves the built static files (firebase init hosting, firebase deploy) over HTTPS.
- trackBy (track e.id) lets Angular reuse DOM for unchanged list items instead of re-rendering the whole list.
- OnPush change detection makes a component re-check only when its @Input values change, cutting needless work.
- Lazy loading defers a page's code until it is visited; all three optimisations share the idea of doing less work.
- Memory hook: build and deploy to Firebase; trackBy, OnPush, and lazy loading keep it fast.