Skip to content

Commit 1749ee6

Browse files
mgechevthePunderWoman
authored andcommitted
docs: add update instructions for v20 (angular#61338)
PR Close angular#61338
1 parent f182886 commit 1749ee6

File tree

2 files changed

+179
-3
lines changed

2 files changed

+179
-3
lines changed

adev/src/app/features/update/recommendations.ts

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2537,4 +2537,179 @@ export const RECOMMENDATIONS: Step[] = [
25372537
possibleIn: 1900,
25382538
step: '19.0.0-update-fakeasync-to-flush-pending-timers',
25392539
},
2540+
{
2541+
action:
2542+
"In the application's project directory, run `ng update @angular/core@20 @angular/cli@20` to update your application to Angular v20.",
2543+
level: ApplicationComplexity.Basic,
2544+
necessaryAsOf: 2000,
2545+
possibleIn: 2000,
2546+
step: '20.0.0_ng_update',
2547+
},
2548+
{
2549+
possibleIn: 2000,
2550+
necessaryAsOf: 2000,
2551+
level: ApplicationComplexity.Basic,
2552+
material: true,
2553+
step: 'update @angular/material',
2554+
action: 'Run `ng update @angular/material@20`.',
2555+
},
2556+
{
2557+
possibleIn: 2000,
2558+
necessaryAsOf: 2000,
2559+
level: ApplicationComplexity.Basic,
2560+
step: '20.0.0_rename_afterRender_to_afterEveryRender',
2561+
action: 'Rename the `afterRender` lifecycle hook to `afterEveryRender`',
2562+
},
2563+
{
2564+
possibleIn: 2000,
2565+
necessaryAsOf: 2000,
2566+
level: ApplicationComplexity.Medium,
2567+
step: '20.0.0_replace_TestBed_flushEffects_with_tick',
2568+
action:
2569+
'Replace uses of `TestBed.flushEffects()` with `TestBed.tick()`, the closest equivalent to synchronously flush effects.',
2570+
},
2571+
{
2572+
possibleIn: 2000,
2573+
necessaryAsOf: 2000,
2574+
level: ApplicationComplexity.Advanced,
2575+
step: '20.0.0_update_provideCheckNoChangesConfig',
2576+
action:
2577+
'Rename `provideExperimentalCheckNoChangesForDebug` to `provideCheckNoChangesConfig`. Note its behavior now applies to all `checkNoChanges` runs. The `useNgZoneOnStable` option is no longer available.',
2578+
},
2579+
{
2580+
possibleIn: 2000,
2581+
necessaryAsOf: 2000,
2582+
level: ApplicationComplexity.Advanced,
2583+
step: '20.0.0_refactor_ng_reflect_attributes_usage',
2584+
action:
2585+
'Refactor application and test code to avoid relying on `ng-reflect-*` attributes. If needed temporarily for migration, use `provideNgReflectAttributes()` from `@angular/core` in bootstrap providers to re-enable them in dev mode only.',
2586+
},
2587+
{
2588+
possibleIn: 2000,
2589+
necessaryAsOf: 2000,
2590+
level: ApplicationComplexity.Advanced,
2591+
step: '20.0.0_adjust_RedirectFn_return_type_handling',
2592+
action:
2593+
'Adjust code that directly calls functions returning `RedirectFn`. These functions can now also return an `Observable` or `Promise`; ensure your logic correctly handles these asynchronous return types.',
2594+
},
2595+
{
2596+
possibleIn: 2000,
2597+
necessaryAsOf: 2000,
2598+
level: ApplicationComplexity.Advanced,
2599+
step: '20.0.0_rename_provideExperimentalZonelessChangeDetection',
2600+
action:
2601+
'Rename `provideExperimentalZonelessChangeDetection` to `provideZonelessChangeDetection`.',
2602+
},
2603+
{
2604+
possibleIn: 2000,
2605+
necessaryAsOf: 2000,
2606+
level: ApplicationComplexity.Advanced,
2607+
step: '20.0.0_update_template_expressions_using_in_property',
2608+
action:
2609+
"If your templates use `{{ in }}` or `in` in expressions to refer to a component property named 'in', change it to `{{ this.in }}` or `this.in` as 'in' now refers to the JavaScript 'in' operator. If you're using `in` as a template reference, you'd have to rename the reference.",
2610+
},
2611+
{
2612+
possibleIn: 2000,
2613+
necessaryAsOf: 2000,
2614+
level: ApplicationComplexity.Advanced,
2615+
step: '20.0.0_update_router_method_array_parameters_to_readonly',
2616+
action:
2617+
'The type for the commands arrays passed to Router methods (`createUrlTree`, `navigate`, `createUrlTreeFromSnapshot`) have been updated to use `readonly T[]` since the array is not mutated. Code which extracts these types (e.g. with `typeof`) may need to be adjusted if it expects mutable arrays.',
2618+
},
2619+
{
2620+
possibleIn: 2000,
2621+
necessaryAsOf: 2000,
2622+
level: ApplicationComplexity.Advanced,
2623+
step: '20.0.0_update_animation_tests_for_guaranteed_flushing',
2624+
action:
2625+
'Review and update tests asserting on DOM elements involved in animations. Animations are now guaranteed to be flushed with change detection or `ApplicationRef.tick`, potentially altering previous test outcomes.',
2626+
},
2627+
{
2628+
possibleIn: 2000,
2629+
necessaryAsOf: 2000,
2630+
level: ApplicationComplexity.Medium,
2631+
step: '20.0.0_handle_uncaught_listener_errors_in_tests',
2632+
action:
2633+
'In tests, uncaught errors in event listeners are now rethrown by default. Previously, these were only logged to the console by default. Catch them if intentional for the test case, or use `rethrowApplicationErrors: false` in `configureTestingModule` as a last resort.',
2634+
},
2635+
{
2636+
possibleIn: 2000,
2637+
necessaryAsOf: 2000,
2638+
level: ApplicationComplexity.Advanced,
2639+
step: '20.0.0_update_route_guards_array_types',
2640+
action:
2641+
'The `any` type is removed from the Route guard arrays (canActivate, canDeactivate, etc); ensure guards are functions, `ProviderToken<T>`, or (deprecated) strings. Refactor string guards to `ProviderToken<T>` or functions.',
2642+
},
2643+
{
2644+
possibleIn: 2000,
2645+
necessaryAsOf: 2000,
2646+
level: ApplicationComplexity.Basic,
2647+
step: '20.0.0_update_nodejs_version',
2648+
action:
2649+
'Ensure your Node.js version is at least 20.11.1 and not v18 or v22.0-v22.10 before upgrading to Angular v20. Check https://angular.dev/reference/versions for the full list of supported Node.js versions.',
2650+
},
2651+
{
2652+
possibleIn: 2000,
2653+
necessaryAsOf: 2000,
2654+
level: ApplicationComplexity.Basic,
2655+
step: '20.0.0_replace_TestBed_get_with_TestBed_inject',
2656+
action:
2657+
'Replace all occurrences of the deprecated `TestBed.get()` method with `TestBed.inject()` in your Angular tests for dependency injection.',
2658+
},
2659+
{
2660+
possibleIn: 2000,
2661+
necessaryAsOf: 2000,
2662+
level: ApplicationComplexity.Medium,
2663+
step: '20.0.0_remove_InjectFlags_usage',
2664+
action:
2665+
'Remove `InjectFlags` enum and its usage from `inject`, `Injector.get`, `EnvironmentInjector.get`, and `TestBed.inject` calls. Use options like `{optional: true}` for `inject` or handle null for `*.get` methods.',
2666+
},
2667+
{
2668+
possibleIn: 2000,
2669+
necessaryAsOf: 2000,
2670+
level: ApplicationComplexity.Advanced,
2671+
step: '20.0.0_update_injector_get_calls_to_use_ProviderToken',
2672+
action:
2673+
'Update `injector.get()` calls to use a specific `ProviderToken<T>` instead of relying on the removed `any` overload. If using string tokens (deprecated since v4), migrate them to `ProviderToken<T>`.',
2674+
},
2675+
{
2676+
possibleIn: 2000,
2677+
necessaryAsOf: 2000,
2678+
level: ApplicationComplexity.Basic,
2679+
step: '20.0.0_update_typescript_version',
2680+
action:
2681+
"Upgrade your project's TypeScript version to at least 5.8 before upgrading to Angular v20 to ensure compatibility.",
2682+
},
2683+
{
2684+
possibleIn: 2000,
2685+
necessaryAsOf: 2000,
2686+
level: ApplicationComplexity.Advanced,
2687+
step: '20.0.0_review_AsyncPipe_error_handling_in_tests',
2688+
action:
2689+
'`Unhandled errors in subscriptions/promises of AsyncPipe` are now directly reported to `ErrorHandler`. This may alter test outcomes; ensure tests correctly handle these reported errors.',
2690+
},
2691+
{
2692+
possibleIn: 2000,
2693+
necessaryAsOf: 2000,
2694+
level: ApplicationComplexity.Advanced,
2695+
step: '20.0.0_refactor_PendingTasks_run_usage',
2696+
action:
2697+
'If relying on the return value of `PendingTasks.run`, refactor to use `PendingTasks.add`. Handle promise results/rejections manually, especially for SSR to prevent node process shutdown on unhandled rejections.',
2698+
},
2699+
{
2700+
possibleIn: 2000,
2701+
necessaryAsOf: 2000,
2702+
level: ApplicationComplexity.Advanced,
2703+
step: '20.0.0_update_template_expressions_using_void_property',
2704+
action:
2705+
"If your templates use `{{ void }}` or `void` in expressions to refer to a component property named 'void', change it to `{{ this.void }}` or `this.void` as 'void' now refers to the JavaScript `void` operator.",
2706+
},
2707+
{
2708+
possibleIn: 2000,
2709+
necessaryAsOf: 2000,
2710+
level: ApplicationComplexity.Advanced,
2711+
step: '20.0.0_review_date_pipe_formatter_Y_usage',
2712+
action:
2713+
'Review `DatePipe` usages. Using the `Y` (week-numbering year) formatter without also including `w` (week number) is now detected as suspicious. Use `y` (year) if that was the intent, or include `w` alongside `Y`.',
2714+
},
25402715
];

adev/src/app/features/update/update.component.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export default class AppComponent {
6363
protected afterRecommendations: Step[] = [];
6464

6565
protected readonly versions = [
66+
{name: '20.0', number: 2000},
6667
{name: '19.0', number: 1900},
6768
{name: '18.0', number: 1800},
6869
{name: '17.0', number: 1700},
@@ -99,9 +100,9 @@ export default class AppComponent {
99100
{name: '2.1', number: 201},
100101
{name: '2.0', number: 200},
101102
];
102-
protected from = this.versions.find((version) => version.name === '17.0')!;
103-
protected to = this.versions.find((version) => version.name === '18.0')!;
104-
protected futureVersion = 2000;
103+
protected from = this.versions.find((version) => version.name === '19.0')!;
104+
protected to = this.versions.find((version) => version.name === '20.0')!;
105+
protected futureVersion = 2100;
105106

106107
protected readonly steps: Step[] = RECOMMENDATIONS;
107108

0 commit comments

Comments
 (0)