Our content is free thanks to ag-Grid

ag-Grid is the industry leading JavaScript datagrid

ag-grid.com

Do you know how Angular transforms your code?

Post Editor

A quick overview of Angular 7 typescript transformers Typescript added support for custom transformers in 2.3 version. This type of extensibility allowed developers to go beyond the scope of the base compiler. After that, almost everyone, who had a project with typescript compilation, wanted to turn his ideas into reality. Angular also could not stand aside. The first pull request on switching to transformer based compilation was born on 10 Jun 2017 [https://github.com/angular/angular/pull/173

4 min read
post

Do you know how Angular transforms your code?

A quick overview of Angular 7 typescript transformers Typescript added support for custom transformers in 2.3 version. This type of extensibility allowed developers to go beyond the scope of the base compiler. After that, almost everyone, who had a project with typescript compilation, wanted to turn his ideas into reality. Angular also could not stand aside. The first pull request on switching to transformer based compilation was born on 10 Jun 2017 [https://github.com/angular/angular/pull/173

post
post
4 min read
4 min read

A quick overview of Angular 7 typescript transformers

Typescript added support for custom transformers in 2.3 version. This type of extensibility allowed developers to go beyond the scope of the base compiler. After that, almost everyone, who had a project with typescript compilation, wanted to turn his ideas into reality. Angular also could not stand aside.

The first pull request on switching to transformer based compilation was born on 10 Jun 2017. A lot of time has passed since that day and now Angular can’t live without these custom transformers.

In this article, I will briefly explore many of the Angular transformers that are mostly required for AOT. I divide them into two types: transformers from the @angular/compiler-cli package and @angular/cli specific transformers.

I use Angular 7.2.1 version here

Angular compiler-cli transformers

Once we run the ngc command we will send our code to Angular wrapper over typescript Program that can make the following transformations:

# Inline resource

You must know this transformer if you’re a library author.

It replaces templateUrl/styleUrls properties in @Component with template/styles respectively.

You can enable this transformer via tsconfig.json:

angularCompilerOptions { 
  enableResourceInlining: true
}

Source: @angular/compiler-cli/src/transformers/inline_resources.js

# Lower expressions

I believe we all met such kind of errors:

Error: Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function.

when were writing metadata like:

providers: [{provide: Token, useFactory: () => new SomeClass()}]

Lower expressions transformer will rewrite () => new SomeClass() expression to a variable exported from the module allowing the compiler to import the variable without needing to understand the expression.

The transformation only works for a strictly defined set of fields: useValue, useFactory, data, id and loadChildren.

For a detailed explanation on this, please refer to the documentation.

Lower expression transformer is enabled by default. To disable it use the disableExpressionLowering option:

angularCompilerOptions { 
  disableExpressionLowering: true
}

Source: @angular/compiler-cli/src/transformers/lower_expressions.js

# Node emitter transformer

This is the main ngc transformer which takes generated by AOT compiler SourceFiles and adds a file overview JSDoc comment containing Closure Compiler specific “suppress”ions in JSDoc.

Source: @angular/compiler-cli/src/transformers/node_emitter_transform.js

# Angular class transformer

It adds the requested static methods specified by partial modules.

This transformer uses PartialModules system introduced in Ivy renderer. Render2 uses this transformer to convert Injectable ‘s to static ngInjectableDef fields.

Source: @angular/compiler-cli/src/transformers/r3_transform.js

# DecoratorStripTransformer (ivy only)

Removes decorators like:

[‘Component’, ‘Directive’, ‘Injectable’, ‘NgModule’, ‘Pipe’, ];

since they were “reified” to ngComponentDef, ngDirectiveDef, ngInjectableDef etc.

Used in legacy ngtsc mode(enableIvy=true)

Source: @angular/compiler-cli/src/transformers/r3_strip_decorators.js

Cli ngtools/webpack transformers

ng cli command also hides a bunch of transformers:

# Replace resources (Jit only)

Replaces resources with webpack’s require version so that all resources will be included at runtime.

Source: @ngtools/webpack/src/transformers/replace_resources.js

# Remove decorators

Removes all decorators originated from @angular/core module.

There is an interesting fact. If we import decorator from a different module then it will be survived.

proxy-core-decorators.ts

import { Component } from '@angular/core';
export { Component };

module-jit.ts

import { Component } from './proxy-core-decorators'
@Component({ // won't be removed
  ...
})
export class SomeComponent {}

So you can use that fact to make some trick to save angular decorators for Jit compilation.

Source: @ngtools/webpack/src/transformers/remove_decorators.js

# Register Locale Data (browser only)

Imports locales to the main entry point.

Basically, it works when we provide locale to cli parameters like

--locale=fr
Source: @ngtools/webpack/src/transformers/register_locale_data.ts

# Replace bootstrap(aot only)

Replaces platformBrowserDynamic().bootstrapModule(AppModule) with platformBrowser().bootstrapModuleFactory(AppModuleNgFactory)

Gotchas:

We have to only writeplatformBrowserDynamic().bootstrapModule(AppModule); once otherwise it won’t be replaced. Also, we can’t split this call in two statements like:

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
Source: @ngtools/webpack/src/transformers/replace_bootstrap.ts

# Replace server bootstrap (server aot only)

The same as above but for server.

Source: @ngtools/webpack/src/transformers/replace_server_bootstrap.ts

# Export lazy module map (server only)

If you’re familiar with Angular SSR then you may come across the following code in the server.ts file:

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const {LAZY_MODULE_MAP} = require('./dist/server/main');


So, this transformer is responsible for making this working. It is used to support that import.

Source: @ngtools/webpack/src/transformers/export_lazy_module_map.ts

# Export ngfactory(server aot only)

Also is used to support import in server.ts file.

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const {AppServerModuleNgFactory, LAZY_MODULE_MAP} = require('./dist/server/main');
Source: @ngtools/webpack/src/transformers/export_ngfactory.ts

# PlatformTransformers (public API)

Gives us the ability to provide our own custom transformer.

For example, here is how native-script applies its own version of bootstrap replacement:

webpack.config.js

new AngularCompilerPlugin({ 
    platformTransformers: aot ? [nsReplaceBootstrap(() => ngCompilerPlugin)] : null,

Summary

Angular widely uses typescript custom transformers. It might be useless to know what they do if you are not interested in Angular internals. But, on the other hand, that knowledge can save your time when you’re stuck with the build.

Discuss with community

Share

About the author

author_image
Alexey Zuev

Alexey is a GDE for Angular and Web Technologies and also active StackOverflow contributor.

author_image

About the author

Alexey Zuev

Alexey is a GDE for Angular and Web Technologies and also active StackOverflow contributor.

About the author

author_image
Alexey Zuev

Alexey is a GDE for Angular and Web Technologies and also active StackOverflow contributor.

NxAngularCli
NxAngularCli
NxAngularCli

Featured articles

RxJSpost
21 January 20214 min read
RxJS in Angular: Part III

In my previous two articles we have discussed how to change our components which solve problems in imperative ways to do that in functional, reactive, RxJS way, and we of course had a lot of fun doing that.

RxJSpost
21 January 20214 min read
RxJS in Angular: Part III

In my previous two articles we have discussed how to change our components which solve problems in imperative ways to do that in functional, reactive, RxJS way, and we of course had a lot of fun doing that.

Read more
RxJSpostRxJS in Angular: Part III

21 January 2021

4 min read

In my previous two articles we have discussed how to change our components which solve problems in imperative ways to do that in functional, reactive, RxJS way, and we of course had a lot of fun doing that.

Read more
Angularpost
20 January 20216 min read
Angular and SOLID principles

In software engineering, making things work the first time is always easy. But, what if you want to add new functionalities to an existing code? Making iterations on an existing basis can be difficult to do without introducing bugs. This is where SOLID principles come into play.

Angularpost
20 January 20216 min read
Angular and SOLID principles

In software engineering, making things work the first time is always easy. But, what if you want to add new functionalities to an existing code? Making iterations on an existing basis can be difficult to do without introducing bugs. This is where SOLID principles come into play.

Read more
AngularpostAngular and SOLID principles

20 January 2021

6 min read

In software engineering, making things work the first time is always easy. But, what if you want to add new functionalities to an existing code? Making iterations on an existing basis can be difficult to do without introducing bugs. This is where SOLID principles come into play.

Read more
Angularpost
14 January 20216 min read
Demystifying Taiga UI root component: portals pattern in Angular

Just before new year we announced our new Angular UI kit library Taiga UI. If you go through Getting started steps, you will see that you need to wrap your app with the tui-root component. Let's see what it does and explore what portals are and how and why we use them.