Skip to main content

What is New in Angular 10?

The new version, v10, of Angular has been published only hours ago and announced by this blog post. Although it may not appear as impactful as v9 (with Ivy and all), this release displays Angular team's commitment to keep Angular up-to-date and relevant. We found this very exciting and the timing was just right, because we are about to release ABP v3.0!

So, we jumped into the details of what changed and how to migrate. Here is what we found.

Major Changes

TypeScript v3.9 Support [breaking change]

Angular 9 was released with TypeScript 3.7 support. Soon TypeScript 3.8 was released and Angular v9.1 supported it. Not long after, another TypeScript version, 3.9, is released and Angular responds with v10, keeping up, not only with TypeScript, but also with TSLib and TSLint.

That is great news. Angular stays up-to-date. First of all, TypeScript 3.9 has performance improvements, which means faster Angular builds, especially in larger projects. Second, all latest TypeScript fixes and features are available to Angular developers. Last, but not the least, Angular developers will be using a more elaborate TypeScript configuration.

Earlier versions of TypeScript are no longer supported, so you have to install v3.9 in your project. I believe a major reason behind this is the next feature I will describe.

"Solution Style” tsconfig.json Files

"Solution Style” tsconfig.json file support was introduced by TypeScript v3.9 to overcome issues with cases where a tsconfig.json existed just to reference other tsconfig.json files, known as a "solution". Angular 10 makes use of that concept and improves IDE supportand, consequently, developer experience.

A new file called tsconfig.base.json is introduced and what was inside the root tsconfig.json before is carried to this new file. You can find further details about the "solution" configuration here, but basically the new tsconfig.json at root level, before and after adding a library to the project, looks like this:

BEFORE:
{
  "files": [],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.spec.json"
    },
    {
      "path": "./e2e/tsconfig.json"
    }
  ]
}
JSON
AFTER:
{
  "files": [],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.spec.json"
    },
    {
      "path": "./e2e/tsconfig.json"
    },
    {
      "path": "./projects/core/tsconfig.lib.json"
    },
    {
      "path": "./projects/core/tsconfig.spec.json"
    }
  ]
}
JSON

If you upgrade to Angular 10 using ng update , the CLI will migrate your workspace to this structure. Earlier versions of TypeScript does not support "solution style", so this may be the reason behind the breaking change described above.

Angular Package Format Changes & esm5/fesm5

Angular package format has changed, and the new format does not include esm5 and fesm5distributions anymore. Angular packages (@angular/*) will not include them. Since Angular generates ES5 from ES2015 and ES2015 is the default language level consumed by Angular tooling, those code distributions had become obsolete. The format change is as follows:

BEFORE:
{
  ...
  "main": "bundles/abp-ng.core.umd.js",
  "module": "fesm5/abp-ng.core.js",
  "es2015": "fesm2015/abp-ng.core.js",
  "esm5": "esm5/abp-ng.core.js",
  "esm2015": "esm2015/abp-ng.core.js",
  "fesm5": "fesm5/abp-ng.core.js",
  "fesm2015": "fesm2015/abp-ng.core.js",
  ...
}
JSON
AFTER:
{
  ...
  "main": "bundles/abp-ng.core.umd.js",
  "module": "fesm2015/abp-ng.core.js",
  "es2015": "fesm2015/abp-ng.core.js",
  "esm2015": "esm2015/abp-ng.core.js",
  "fesm2015": "fesm2015/abp-ng.core.js",
  ...
}
JSON

If your application depends on esm5/fesm5 files, you can relax, because they are still consumable by the build system. Likewise, you do not have to worry if your Angular library does not ship esm2015 or fesm2015, because the CLI will fallback to others. However, in favor of bundle optimization and build speed, it is recommended to deliver ES2015 outputs.

Browserlist

Angular generates bundles based on the Browserlist configuration provided in the root app folder. Angular 10 will look up for a .browserlistrc in your app, but fall back tobrowserlist if not found. The ng update command will rename the file for you.

Breaking Changes

  • Resolvers that return EMPTY will cancel navigation. In order to allow the router to continue navigating to the route, emit some value such as of(null).
  • Logging of unknown property bindings or element names in templates is increased to "error" level. It was "warning" before. The change may have an effect on tools not expecting an error log.
  • Returning null from a UrlMatcher would throw Type 'null' is not assignable to type 'UrlMatchResult'. before. This is fixed, but the return type can now be nulltoo.
  • Reactive forms had a bug which caused valueChanges for controls bound to input fields with number type to fire twice. The listened evet is changed from "change" to "input" to fix this.
  • minLength and maxLength validators validate only if the value has a numeric lengthproperty.
  • There was a bug in detection of day span while using formatDate() or DatePipe and b or B format code. It is fixed and the output, for instance, will now be "at night" instead of "AM".
  • Transplanted views (declared in one component and inserted into another) had change detection issues, but that is fixed now. Detection after detaching and double detection are avoided.

Deprecations and Removals

ModuleWithProviders Without a Generic Type [removed]

Earlier versions of Angular was able to compile static method returns with ModuleWithProviders type without the generic type, i.e. ModuleWithProviders<SomeModule>, because the generated metadata.json files would have the information required for compilation. After Ivy, since metadata.json is not required, Angular checks the generic type for type validation.

BEFORE:
@NgModule({...})
export class SomeModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: SomeModule,
      providers: [...]
    };
  }
}
JavaScript
AFTER:
@NgModule({...})
export class SomeModule {
  static forRoot(): ModuleWithProviders<SomeModule> {
    return {
      ngModule: SomeModule,
      providers: [...]
    };
  }
}
JavaScript

ModuleWithProviders without a generic type was deprecated before. As of Angular 10, it is completely removed.

Undecorated Base Classes [removed]

If you are taking advantage of inheritance from classes that use Angular features such as dependency injection or Angular decorators , you now need to decorate those base classes as well. Otherwise, Angular will throw an error about the missing decorator on the parent.

DEPENDENCY INJECTION:
@Directive()
export abstract class AbstractSome {
  constructor(@Inject(LOCALE_ID) public locale: string) {}
}

@Component({
  selector: 'app-some',
  template: 'Locale: {{ locale }}',
})
export class SomeComponent extends AbstractSome {}
JavaScript

Here is the error Angular 10 compiler throws when the Directive decorator is missing:

The component SomeComponent inherits its constructor from AbstractSome, but the latter does not have an Angular decorator of its own. Dependency injection will not be able to resolve the parameters of AbstractSome's constructor. Either add a @Directive decorator to AbstractSome, or add an explicit constructor to SomeComponent.
Txt
DECORATOR:
@Directive()
export abstract class AbstractSome {
  @Input() x: number;
}

@Component({
  selector: 'app-some',
  template: 'Value of X: {{ x }}',
})
export class SomeComponent extends AbstractSome {}
JavaScript

Angular 10 compiler throws a less detailed error this time:

Class is using Angular features but is not decorated. Please add an explicit Angular decorator.
Txt

I am sure you would not do that, but if you put a Component decorator on the parent and remove the decorator on the child, as you would expect, Angular 10 compiler will throw the error below:

The class 'SomeComponent' is listed in the declarations of the NgModule 'AppModule', but is not a directive, a component, or a pipe. Either remove it from the NgModule's declarations, or add an appropriate Angular decorator.
Txt

WrappedValue [deprecated]

WrappedValue is deprecated and will probably be removed with v12. Check here and here if you have never heard of it before.

It was useful to trigger change detection even when same object instance was produced/emitted. There is a performance cost when WrappedValue is used and the cases where it helps are relatively rare, so Angular team has decided to drop it.

As a side effect of this deprecation, you may see more ExpressionChangedAfterItHasBeenChecked errors than before, because Angular would not throw an error when WrappedValues were evaluated as equal.

Incase you face change detection issues, try cloning the object or trigger change detection manually via markForCheck or detectChanges methods of the ChangeDetectorRef.

Other Deprecations & Removals

  • Support for IE9, IE10, and IE Mobile has been deprecated and will be dropped later. The increased bundle size and complexity was the main reason. Considering even Microsoft dropped support for these browsers, it makes a lot of sense.
  • Angular stopped sanitizing the style property bindings. This is due to drop of support for legacy browsers (like IE6 and IE7) and the performance cost of having a sanitizer.
  • Bazel build schematics will not be continued. Angular team explained the reasonsand referred to this monorepo as a source to keep an eye on, if you are interested in building Angular with Bazel.

Conclusion

I would like to emphasize how thankful I am that Angular team is trying to keep Angular up-to-date. This is a great demonstration and, in my humble opinion, just as meaningful as a state-of-art renderer. It is also very nice to see how easy it is to migrate an existing project. Angular not only keeps up with its ecosystem, but also helps you to keep up together with it.

Congratulations, and thank you!

Comments

Popular posts from this blog

Understand Angular’s forRoot and forChild

  forRoot   /   forChild   is a pattern for singleton services that most of us know from routing. Routing is actually the main use case for it and as it is not commonly used outside of it, I wouldn’t be surprised if most Angular developers haven’t given it a second thought. However, as the official Angular documentation puts it: “Understanding how  forRoot()  works to make sure a service is a singleton will inform your development at a deeper level.” So let’s go. Providers & Injectors Angular comes with a dependency injection (DI) mechanism. When a component depends on a service, you don’t manually create an instance of the service. You  inject  the service and the dependency injection system takes care of providing an instance. import { Component, OnInit } from '@angular/core'; import { TestService } from 'src/app/services/test.service'; @Component({ selector: 'app-test', templateUrl: './test.component.html', styleUrls: ['./test.compon...

How to use Ngx-Charts in Angular ?

Charts helps us to visualize large amount of data in an easy to understand and interactive way. This helps businesses to grow more by taking important decisions from the data. For example, e-commerce can have charts or reports for product sales, with various categories like product type, year, etc. In angular, we have various charting libraries to create charts.  Ngx-charts  is one of them. Check out the list of  best angular chart libraries .  In this article, we will see data visualization with ngx-charts and how to use ngx-charts in angular application ? We will see, How to install ngx-charts in angular ? Create a vertical bar chart Create a pie chart, advanced pie chart and pie chart grid Introduction ngx-charts  is an open-source and declarative charting framework for angular2+. It is maintained by  Swimlane . It is using Angular to render and animate the SVG elements with all of its binding and speed goodness and uses d3 for the excellent math functio...

How to solve Puppeteer TimeoutError: Navigation timeout of 30000 ms exceeded

During the automation of multiple tasks on my job and personal projects, i decided to move on  Puppeteer  instead of the old school PhantomJS. One of the most usual problems with pages that contain a lot of content, because of the ads, images etc. is the load time, an exception is thrown (specifically the TimeoutError) after a page takes more than 30000ms (30 seconds) to load totally. To solve this problem, you will have 2 options, either to increase this timeout in the configuration or remove it at all. Personally, i prefer to remove the limit as i know that the pages that i work with will end up loading someday. In this article, i'll explain you briefly 2 ways to bypass this limitation. A. Globally on the tab The option that i prefer, as i browse multiple pages in the same tab, is to remove the timeout limit on the tab that i use to browse. For example, to remove the limit you should add: await page . setDefaultNavigationTimeout ( 0 ) ;  COPY SNIPPET The setDefaultNav...