Upgrading from Angular 8 to 13
Tags: angular, typescript, webdev, programming
Published: 2022-04-30 03:27:20

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0v58j67qglhwlqcl5xx6.png)

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](https://medium.com/geekculture/log4j-vulnerability-in-detail-and-the-bigger-picture-db49f749009) in Java and the discontinuity of the _faker_ library that affected the projects in [AngularJS, officially unsupported](https://www.infoworld.com/article/3646609/angularjs-reaches-end-of-life.html).

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](https://angular.io/guide/releases), Angular 2 through 10 were no longer supported.

![angular support](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dnomleuxxqeqp7pzelrm.png)

## Initial guidelines

![ng update keep calm](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k8wcmurginap7mya72u5.png)

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](https://blog.ninja-squad.com/2020/09/03/angular-cli-10.1/#:~:text=The%20%40angular-devkit%2Fbuild,-angular:ng-packagr%20.). 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](https://stackoverflow.com/questions/69949917/why-do-i-get-this-error-postcss-is-not-recognized-as-an-internal-or-external):

`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](https://stackoverflow.com/questions/56375703/angular-8-lazy-loading-modules-error-ts1323-dynamic-import-is-only-supporte), 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](https://stackoverflow.com/questions/68590899/rxjs-7-update-subject-expected-1-arguments-but-got-0). 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](https://stackoverflow.com/questions/69446231/module-not-found-error-resolving-to-directories-is-not-possible-with-the-expor). 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](https://stackoverflow.com/questions/55588968/type-error-object-is-possibly-null-ts2531-for-window-document) 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](https://github.com/primefaces/primeng/issues/8551). 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](https://stackoverflow.com/questions/55867116/failed-to-set-an-indexed-property-on-cssstyledeclaration-index-property-sette) occurs

- `error TS7006: Parameter 'perfis' implicitly has an 'any' type`

[This is because](https://stackoverflow.com/questions/43064221/typescript-ts7006-parameter-xxx-implicitly-has-an-any-type) 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](https://stackoverflow.com/questions/49699067/property-has-no-initializer-and-is-not-definitely-assigned-in-the-construc). To solve there are [several approaches](https://mariusschulz.com/blog/strict-property-initialization-in-typescript) 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](https://www.typescriptlang.org/tsconfig#strictPropertyInitialization), 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](https://stackoverflow.com/questions/54496398/typescript-type-string-undefined-is-not-assignable-to-type-string), 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](https://stackoverflow.com/questions/60121962/this-class-is-visible-to-consumers-via-somemodule-somecomponent-but-is-not-e). 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](https://stackoverflow.com/questions/62755093/angular-error-generic-type-modulewithproviderst-requires-1-type-arguments), 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:](https://stackoverflow.com/questions/68655492/throwerrorerror-is-now-deprecated-but-there-is-no-new-errorhttperrorresponse)

`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](https://stackoverflow.com/questions/61541876/why-entrycomponents-is-not-necessary-anymore-in-angular-9-ivy-compiler): 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.