fix(@angular/build): avoid top-level await for Zone.js injection in Vitest runner - #34150
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a new 'zoneless' option for the Vitest unit-test runner in Angular, allowing developers to explicitly configure whether tests should run in zoneless mode. It refactors the Zone.js testing initialization logic by injecting the necessary polyfills directly into the build options and deprecates the automatic injection of Zone.js based on dependency detection. The review feedback suggests improving robustness by adding a fallback empty array when initializing the polyfills Set and updating the deprecation warning message to provide clearer guidance for library projects that lack a polyfills configuration option.
d64f95d to
3ebcbbf
Compare
920587f to
887c542
Compare
|
@alan-agius4 two cases still broken:
|
|
zone.js/testing should never be added to the application's |
|
my bad, out of scope for this pr. |
887c542 to
1e6e227
Compare
935f6cc to
41f0666
Compare
…itest runner Previously, the Vitest unit-test runner used dynamic import strategies (`'dynamic'` and `'dynamic-zone'`) within the generated TestBed initialization virtual file (`createTestBedInitVirtualFile`) to load `zone.js` and `zone.js/testing`. This logic was fundamentally flawed: 1. When Zone.js was loaded dynamically at runtime via the `'dynamic'` strategy, esbuild did not downlevel `async`/`await` because `isZonelessApp` checked the build target's `polyfills` configuration (which did not explicitly list `zone.js`). Consequently, native async/await microtasks bypassed Zone.js context tracking, breaking Zone.js at runtime. 2. If a project used a local polyfills file (e.g. `polyfills: ["src/polyfills.ts"]`), `isZonelessApp` considered the application zoneful and disabled `async-await` support in esbuild. However, esbuild cannot downlevel top-level await when async/await is downleveled, causing esbuild to reject top-level await unconditionally. Hence, the `'dynamic'` strategy never worked as intended. 3. For zoneless applications (such as `polyfills: []`), the syntactic presence of top-level `await` in the virtual file caused esbuild builds to fail when targeting older browsers or Browserslist targets that lack top-level await support, even though Zone was never present at runtime. This commit resolves these issues by: - Eliminating top-level `await import()` from `createTestBedInitVirtualFile` entirely. - Inverting the polyfill strategy so that `zone.js` and `zone.js/testing` are injected directly into `buildOptions.polyfills` before bundling based on the configured `polyfills` option (from the `test` target or inherited from the `build` target). - For library targets where `polyfills` is undefined, `zone.js` and `zone.js/testing` are injected if `zone.js` is installed, accompanied by a deprecation warning advising users to configure the `polyfills` option in their test configuration (`[]` for zoneless projects or `["zone.js"]` for Zone.js projects). Fixes angular#33324
41f0666 to
9a62fb7
Compare
|
This PR was merged into the repository. The changes were merged into the following branches:
|
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Previously, the Vitest unit-test runner used dynamic import strategies (
'dynamic'and'dynamic-zone') within the generated TestBed initialization virtual file (createTestBedInitVirtualFile) to loadzone.jsandzone.js/testing.This logic was fundamentally flawed:
'dynamic'strategy, esbuild did not downlevelasync/awaitbecauseisZonelessAppchecked the build target'spolyfillsconfiguration (which did not explicitly listzone.js). Consequently, native async/await microtasks bypassed Zone.js context tracking, breaking Zone.js at runtime.polyfills: ["src/polyfills.ts"]),isZonelessAppconsidered the application zoneful and disabledasync-awaitsupport in esbuild. However, esbuild cannot downlevel top-level await when async/await is downleveled, causing esbuild to reject top-level await unconditionally. Hence, the'dynamic'strategy never worked as intended.polyfills: []), the syntactic presence of top-levelawaitin the virtual file caused esbuild builds to fail when targeting older browsers or Browserslist targets that lack top-level await support, even though Zone was never present at runtime.Issue Number: Fixes #33324
What is the new behavior?
await import()fromcreateTestBedInitVirtualFileentirely.zone.jsandzone.js/testingare injected directly intobuildOptions.polyfillsbefore bundling based on the configuredpolyfillsoption (from thetesttarget or inherited from thebuildtarget).polyfillsis undefined,zone.jsandzone.js/testingare injected ifzone.jsis installed, accompanied by a deprecation warning advising users to configure thepolyfillsoption in their test configuration ([]for zoneless projects or["zone.js"]for Zone.js projects).Does this PR introduce a breaking change?