Create a branch from your current production release which will become the Angular 18 version of your application. This will allow you to modify the branch while simultaneously supporting application of hotfixes to your production application during the migration.
Follow the guide below to migrate your branch to Angular 18.
Address any issues in your Angular 18 branch that you discover.
Merge the changes from your Angular 18 branch into the source project.
Navigate to Dependencies in your application.
Drill into each dependency to check for ones that rely on libraries that are specific to an Angular version.
For each such dependency, change the version range to ~18.0.0 and then click the Apply Version Range button.
Old New
mat.define-palette() mat.m2-define-palette()
mat.define-typography-config() mat.m2-define-typography-config()
mat.define-light-theme() mat.m2-define-light-theme()
Predefined palettes referenced by mat.define-palette will need to include m2 as well: mat.$red-palette becomes mat.$m2-red-palette
If you miss converting any palettes, you'll get a build error similar to this:
./src/styles.scss - Error: Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
'Hue "500" does not exist in palette. Available hues are: 0, 10, 20, 25, 30, 35, 40, 50, 60, 70, 80, 90, 95, 98, 99,
100, secondary, neutral, neutral-variant, error'
╷
38 │ default: _get-color-from-palette($base-palette, $default),
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
╵
node_modules/@angular/material/core/m2/_theming.scss 38:14 define-palette()
src/styles.scss 402:12 root stylesheet
Generate your project.
Look for any interceptors (likely in angular/src/app/shared/services) that export the interceptor as a class instead of as a const.
Remove the module file for the interceptor.
import { HttpEvent, HttpInterceptorFn, HttpHandlerFn, HttpRequest } from '@angular/common/http';
import { inject } from '@angular/core';
import { AuthService } from './auth.service';
import { Observable, from, lastValueFrom } from 'rxjs';
import * as Debug from 'debug';
const debug = Debug('AuthInterceptor');
export const authInterceptor: HttpInterceptorFn = (
req: HttpRequest<unknown>,
next: HttpHandlerFn
): Observable<HttpEvent<unknown>> => {
const auth = inject(AuthService);
return from(handleRequest(req, next, auth));
};
async function handleRequest(
req: HttpRequest<unknown>,
next: HttpHandlerFn,
auth: AuthService
): Promise<HttpEvent<unknown>> {
debug('req.url', req.url);
if (req.url.startsWith('http')) {
return await lastValueFrom(next(req));
} else {
debug('auth', auth);
debug('getting token');
const authToken = await auth.getAuthToken();
debug('handleRequest authToken', authToken);
if (authToken) {
const authReq = req.clone({
setHeaders: {
Authorization: authToken
}
});
return await lastValueFrom(next(authReq));
} else {
return await lastValueFrom(next(req));
}
}
}