Lab 11: Migration to v21
π Resourcesβ
π Starter Codeβ
step-11-album-wholesale-v16-post-compodoc
In this lab, you will explore what Angular's migration to standalone components looks like β comparing the v16 NgModule-based architecture with the v21 standalone equivalent provided in the starter. You will understand what ng update and ng generate @angular/core:standalone change, and manually apply the key transformations.
Why not run
ng update @angular/core@21directly?Angular's CLI update tool only supports updating one major version at a time. Going from v16 to v21 requires five separate runs:
ng update @angular/core@17 @angular/cli@17
ng update @angular/core@18 @angular/cli@18
ng update @angular/core@19 @angular/cli@19
ng update @angular/core@20 @angular/cli@20
ng update @angular/core@21 @angular/cli@21In a real project you would run each step, fix deprecation warnings, and test before moving on. For this lab, the migrated result is the next starter (
step-15-album-wholesale-v21-post-signal-computed) β use it to study what changed.
π Instructionsβ
Step 1: Compare the Two Startersβ
Open both projects side by side:
- Before (v16):
step-11-album-wholesale-v16-post-compodoc - After (v21):
step-15-album-wholesale-v21-post-signal-computed
Notice the key structural differences.
Step 2: Understand the Bootstrap Changeβ
v16 (src/main.ts):
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
v21 (src/main.ts):
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent, appConfig);
Step 3: Understand the AppModule β app.config.ts Changeβ
v16 (src/app/app.module.ts):
@NgModule({
declarations: [AppComponent, AlbumListComponent, ...],
imports: [
BrowserModule,
HttpClientModule,
RouterModule.forRoot(routes),
ReactiveFormsModule,
],
bootstrap: [AppComponent]
})
export class AppModule {}
v21 (src/app/app.config.ts):
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient(),
provideAnimations(),
]
};
Step 4: Understand Standalone Componentsβ
The automated migration runs:
ng generate @angular/core:standalone
This converts each component from:
// v16 β declared in a module
@Component({ selector: 'app-album-list', ... })
export class AlbumListComponent { }
To:
// v21 β standalone, imports its own dependencies
@Component({
selector: 'app-album-list',
standalone: true,
imports: [MatCard, NgFor, AsyncPipe, ...],
...
})
export class AlbumListComponent { }
Step 5: Understand Functional Guardsβ
v16 β class-based guard:
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
canActivate(): boolean {
return inject(AuthService).isLoggedIn();
}
}
v21 β functional guard:
export const authGuard: CanActivateFn = () => {
return inject(AuthService).isLoggedIn();
};
Step 6: Verify the Migrated Starter Compilesβ
cd step-15-album-wholesale-v21-post-signal-computed
npm install
ng build
This is the result of the migration β all subsequent labs (12β17) build on top of it.