DEV Community

Windson Mateus πŸ‡ΊπŸ‡¦
Windson Mateus πŸ‡ΊπŸ‡¦

Posted on

Upgrading from Angular 8 to 13

In this post I will report what I learned in the migration of Angular applications v8 to v13.

In addition, I will show you the most common errors that you may encounter in the process as well as their respective solutions, indicating the sources when appropriate.

I spent 1 year and a half allocated in a division that worked with many applications and a suite of components built in Angular 8.

angular

In the last 2 months of the last year we had meetings with the frontend working group where the subject of angular application migration has always been talked.
Considered a critical issue, especially when we remembered the risk of recent cases such as the log4j vulnerability in Java and the discontinuity of the faker library that affected the projects in AngularJS, officially unsupported.

Then came an opportunity to work with technical debt. When we did this work the Angular version was 13 and because Google only supports up to 2 previous versions, Angular 2 through 10 were no longer supported.

angular support

Initial guidelines

ng update keep calm

We take the experience we had in migrating the component project in Angular 8 to 13. These are the possible migration approaches:

1) Run a ng update with each version because it is not possible through it to move from version 8 straight to 13, so you need to run this command to migrate from 8 to 9, from 9 to 10, and so on. The advantage is that it converts the code automatically, but the process of going through so many versions ends up being more costly and therefore not recommended in our case where there was a gap of 5 versions. It may be the most appropriate option for future migrations.

2) Create a new project in Angular 13 and copy the fonts from the old project into Angular 8. Then solve the problems as they arise. This approach has been adopted for the migration of our component project and is what we recommend in this situation.

Migration roadmap

1) Install latest version of Angular

npm install -g @angular/cli

2) Create new project

ng new novo-projeto

3) Copy fonts from old project

When copying the fonts it is recommended to keep the new package.json that was generated to include and resolve the various dependencies on demand so that at the end of the process only the ones really needed are included, thus also meeting the best safety standards. Update angular versions of the package.json of the subprojects (if any) as well.

4) Modify tsconfig.lib.json settings

Update the tsconfig.lib.json files of the subprojects (if any) to align with the current tsconfig.json files

"target": "es2017",
"module": "es2020",
"lib": [
"es2020",
"dom"
]

Common configuration errors and solutions

  • An unhandled exception occurred: The target entry-point "@novo-projeto" has missing dependencies: primeng/toast, primeng/button

Add the primeng to the package.json. This will be the most common error because it will occur for all various dependencies that have not yet been included, such as: bootstrap, ng-select, among others. Try to always define the version of the dependency corresponding to the current version of Angular in the project.

Other situations that can be solved in this way are errors of type:Script file ____ does not exist. or An unhandled occurred exception: ENOENT: no such file or directory, lstat ______

  • "ng build" for library fails with "does not support the 'build' target

Copy angular.json file from old project

  • npm WARN @angular-devkit/build-ng-packagr@0.1002.0 requires a peer of ng-packagr@^10.0.0 but none is installed. You must install peer dependencies yourself.

The build-ng-packagr has been discontinued. Remove the build-ng-packagr from package.json and modify the tasks in angular.json, so that where there is @angular-devkit/build-ng-packagr:build replace for @angular-devkit/build-angular:ng-packagr

  • Directory import '...\node_modules\@angular\compiler-cli\ngcc' is not supported resolving ES modules imported from ...\node_modules\ng-packagr\lib\utils\ng-compiler-cli.js. Did you mean to import @angular/compiler-cli/ngcc/index.js?

Resolves by modifying the version of ng-packagr in the package.json file, to one corresponding to the Angular version in the project.

  • Cannot resolve type entity i5.Scrolling Module to symbol* ou *ERROR: The target entry-point "primeng/dropdown" has missing dependencies: @angular/cdk/scrolling

It is solved by adding the @angular/cdk to package.json.

  • ModuleError: Module Error (from ./node_modules/postcss-loader/dist/cjs.js) ... Can't resolve 'OpenSans-Regular.eot' in '...\dist\seus-components\css'

Install the postcss and postcss-cli:

npm install postcss postcss-cli

  • Error: Module not found: Error: Can't resolve 'chart.js/auto'

Install chart and ng2-charts, which is a wrapper of the first, running:

npm install --save ng2-charts and npm install --save chart.js

Common errors involving code change and solutions

  • Module errors of type: '"primeng"' has no exported member 'ConfirmDialogModule'

In earlier versions of primeng imports were like this:

import { Checkbox, MessageService, ConfirmDialogModule } from 'primeng/primeng';

References are now more specific, so they need to be corrected:

import { Checkbox } from 'primeng/checkbox';
import { MessageService } from 'primeng/api';
import { ConfirmDialogModule } from 'primeng/confirmdialog';

  • error TS1323: Dynamic imports are only supported when the '--module' flag is set to 'es2020'

In order to support dynamic imports, add the line to tsconfig.json:

"module": "esnext",

  • When working with observables, error Error TS2554: Expected 1 arguments, but got 0 may arise

Occurs after migration to rxjs 7. It can be solved by passing a fake value:

this.subject.next("");

  • Error: Module not found: Resolving to directories is not possible with the exports field (request was ./)

It usually occurs after migration to Angular 12. It is solved by removing the "/" at the end of imports or replacement of double quotes by single. Example:

Before: import { MsgCenterModule } from '@seu-componente/etc-client/';
After: import { MsgCenterModule } from '@seu-componente/etc-client';
Before: import { ABCEnum, XYZEnum } from "../../tabela.constants";
After: import { ABCEnum, XYZEnum } from '../../tabela.constants';

  • Error of the type: Module not found: Error: Can't solve 'dayjs' / Error: Module not found: Error: Can't solve 'inputmask'

Installing this library because even though it is not directly used in the application, it is necessary in some cases because it is referenced by the component used:

npm install dayjs --save

npm install inputmask --save

  • Type error: Object is possibly 'null'. TS2531 for window.document

The typescript compiler is indicating that window.document.getElementById('content') may return NULL. Because it is a migrated code that already worked previously just add the ! to code: document.getElementById('content')!. innerHTML = '';

  • error NG8002: Can't bind to 'minWidth' since it isn't a known property of 'p-dialog'.

From primeng 9 some properties must be set in style. Therefore, in html, where it has [width]="600" [minWidth]="200" change to [style]="{width: '600px', minWidth: '200px'}". Look at the brackets or a CSS-style setar error occurs

  • error TS7006: Parameter 'perfis' implicitly has an 'any' type

This is because variables now need to have some type defined, so it is necessary at all points in the code to set them to any or for a more specific type. A sometimes pointed solution is to set "noImplicitAny" to false in the tsconfig.json, but it is not recommended.

  • error TS2564: Property 'titulo' has no initializer and is not definitely assigned in the constructor

Starting with version 2.7 the **typescript **compiler requires that the property/variable be initialized. To solve there are several approaches but we chose to add the "!" in the definition of the variable:

public container!: ViewContainerRef;

We did this because we have assurances that this is initialized because it worked in the previous project in Angular 8, since the previous code ran without errors at runtime.

Note: In tsconfig.json, compilerOptions can be defined as "strictPropertyInitialization": false, to ignore these errors and speed up this phase of migration, but it is recommended to go back to true later.

  • error TS2322: Type 'string | null' is not assignable to type 'string | undefined'.

Very common when setting an interface property as optional, solved with "!" just like the previous error.

  • error TS2322: Type 'Boolean' is not assignable to type 'boolean' ... 'boolean' is a primitive, but 'Boolean' is a wrapper object. Prefer using 'boolean' when possible

Newer versions of typescript are more rigid. In this case you will need to modify the code to use the boolean primitive type.

  • error NG3001: Unsupported private class MsgCenterComponent. This class is visible to consumers via SistemaClientModule -> MsgCenterComponent, but is not exported from the top-level library entrypoint.

It usually happens from version 9 of Angular. Add to the public_api.ts the line corresponding to the class in question, in this example:

export * from './lib/msg-center/msg-center.component';

  • error TS2314: Generic type 'ModuleWithProviders<T>' requires 1 type argument(s)

Change the code as follows, in this example:

static forRoot(): ModuleWithProviders<XYZClientModule>

  • error TS7030: Not all code paths return a value.

Ensure that a value is returned in the code in question. It usually occurs in more extensive if clauses.

  • error TS2339: Property 'throw' does not exist on type 'typeof Observable'

Change the call to:

return throwError(() => response);

  • error TS1192: Module '".../node_modules/@types/uuid/index"' has no default export.

Install dependency: npm i --save-dev @types/uuid

And modify the call in the code to:

import * as uuid from 'uuid';

  • error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'. No index signature with a parameter of type 'string' was found on type '{}'

You need to define the type of index that the object has by modifying the code to:

pagesStatus: {[index: string]:any} = {}

  • error TS2322: Type 'string' is not assignable to type 'number'

It can occur in html tag attributes. For example, where there were:

<p-fileUpload mode="advanced" name="demo[]" maxFileSize=1000000 multiple=true chooseLabel="Buscar arquivo" (onUpload)="onUpload($event)"></p-fileUpload>

Place the brackets:

<p-fileUpload mode="advanced" name="demo[]" [maxFileSize]="1000000" [multiple]="true" chooseLabel="Buscar arquivo" (onUpload)="onUpload($event)"></p-fileUpload>

After migration

  • Code entryComponents Removal: From Angular 13 on, the use of entryComponents is no longer required

  • Remove [responsive] attributes from p-dialog. In the new version such components are fully responsive and so the attribute has been discontinued.

Top comments (0)