Build and Test: esbuild, Vite, and Vitest over Karma In short: Angular's build changed engine in v16, and the test runner changed in v21. The build change is a straight speed win. The test change is more interesting, because it follows directly from dropping Zone.js. The build handles this. Names you may find in an older project are steps along the way; is where it ended up. It also combined the browser and server builds into one, so with server rendering you no longer keep two separate setups. What got faster Production builds are meaningfully faster, but the development loop is where you feel it. Vite serves modules directly rather than bundling everything first, so the dev server starts quickly and updates as you type instead of rebuilding. v19 added live updating for templates and styles , which means editing a template updates the running page without losing where you were . If you have ever navigated four screens deep to test something and lost it on every save, this changes how you work more than any build timing does. Measure this on your own project rather than trusting a general figure — the gain depends heavily on codebase size and what your build does. What can break Custom build configuration. If you customised the old build engine, there is no direct equivalent. This is the main reason a team stays on the old builder. Older-style packages. The new engine is stricter. Packages that used to be tolerated may now warn or fail, and the fix is usually a newer version. Node built-ins. Not added automatically. A library expecting them needs them set up explicitly. Vitest replaces Karma Karma was marked as going away in v18, and Vitest became the default in v21 . There is a migration helper: Why it is better No browser needed. Karma started a real Chrome for every run. Vitest runs in Node with a simulated page by default, so startup is much lighter. A real browser is still available when you genuinely need one. Watch mode that works. Only affected tests run again when you change something. No zone by default. This is the interesting part. Karma's model was built around waiting for the zone to settle — , , . Vitest runs without a zone, matching how v21+ apps actually run. Translating the vocabulary Mostly mechanical: Timers are where the model genuinely changes: covers what did. still works. Testing signals Signal components are much easier to test , because you can read values directly instead of drawing the component and searching the page: is how you set a signal input from a test. Reading works it out on demand — there is no update cycle to wait for, because a is just a function call. Set your tests up to match production: The MCP server v21 shipped a server that gives AI coding assistants current, accurate Angular guidance. This matters more than it sounds. There is a great deal of pre-v17 Angular content in any AI model's training, so without help they confidently produce and when you ask for modern code. Stable: , , , . Experimental: , , . v22 added Agent Skills, installed with , doing the same job a different way. Two of these are genuinely useful for the next lesson's migration. suggests conversions, and helps with the Chapter 5 check. They suggest rather than guarantee — review everything — but on a large project they are much faster than checking by hand. The architect's view Tooling is a team-throughput decision, not a developer-comfort one. That framing matters when you are justifying the time. A slow feedback loop changes behaviour, and always for the worse. When tests take a long time to start, people stop running them locally and let CI find problems — which moves the discovery of a bug from seconds after writing it to twenty minutes later, in a different context, often for a different person. When the dev server loses your place on every save, people test less thoroughly because getting back to the state under test is tedious. Neither cost appears on any dashboard. They appear as slightly lower quality, spread thin. Why the test-runner change follows from Chapter 5. This is not an unrelated tooling swap. , , and exist to control and wait for Zone.js. Once the zone is gone, a large part of that vocabulary has nothing to do, and a runner with a plain / model becomes the better fit. The tooling change is downstream of the framework change — which is also why doing them in the wrong order is awkward. Sequence it deliberately. Migrate to Vitest around the same time you go zoneless, and configure your test bed with . Running tests with a zone while shipping without one means your tests pass on behaviour your users do not have. That is a genuine risk, not a tidiness concern. On testing signal components. This is the underrated gain. You can set an input and read a directly, with no rendering and no change-detection cycle: Cheaper tests get written. Logic that is awkward to test tends not to be tested, so making it cheap is a quality lever , not just a speed one. When to hold off. If you depend…