Do you know how Angular transforms your code?

Post Editor

In this article we will learn how Angular transforms your code.

4 min read
post

Do you know how Angular transforms your code?

In this article we will learn how Angular transforms your code.

post
post
4 min read

A quick overview of Angular 7 typescript transformers
Link to this section

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
Link to this section

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
Link to this section

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:

<>Copy
angularCompilerOptions { enableResourceInlining: true }
Content imageContent image

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

# Lower expressions
Link to this section

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:

<>Copy
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.

Content imageContent image

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:

<>Copy
angularCompilerOptions { disableExpressionLowering: true }

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

# Node emitter transformer
Link to this section

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.

Content imageContent image

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

# Angular class transformer
Link to this section

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.

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

# DecoratorStripTransformer (ivy only)
Link to this section

Removes decorators like:

<>Copy
[‘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
Link to this section

ng cli command also hides a bunch of transformers:

# Replace resources (Jit only)
Link to this section

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

Content imageContent image
Source: @ngtools/webpack/src/transformers/replace_resources.js

# Remove decorators
Link to this section

Removes all decorators originated from @angular/core module.

Content imageContent image

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

proxy-core-decorators.ts

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

module-jit.ts

<>Copy
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)
Link to this section

Imports locales to the main entry point.

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

<>Copy
--locale=fr
Content imageContent image
Source: @ngtools/webpack/src/transformers/register_locale_data.ts

# Replace bootstrap(aot only)
Link to this section

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

Content imageContent image

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:

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

# Replace server bootstrap (server aot only)
Link to this section

The same as above but for server.

Content imageContent image
Source: @ngtools/webpack/src/transformers/replace_server_bootstrap.ts

# Export lazy module map (server only)
Link to this section

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

<>Copy
// * 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.

Content imageContent image
Source: @ngtools/webpack/src/transformers/export_lazy_module_map.ts

# Export ngfactory(server aot only)
Link to this section

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

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

# PlatformTransformers (public API)
Link to this section

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

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

Summary
Link to this section

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.

Share

About the author

author_image

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 is a GDE for Angular and Web Technologies and also active StackOverflow contributor.

Looking for a JS job?
Job logo
NODE.JS / ANGULAR DEVELOPER(SENIOR)

Interon IT Solutions LLC

Worldwide
Remote
$115k - $125k
Job logo
Sr. Developer-.Net/Angular/Node

PRICE WATERHOUSE COOPERS

Worldwide
Remote
$81k - $103k
Job logo
Angular Developer

Software Technology, Inc.

Worldwide
Remote
$75k - $100k
Job logo
Angular Developer

GenSpark

United States
Remote
$60k - $70k
More jobs

Featured articles

blockchainpost
19 July 202212 min read
An Introduction to Blockchain

Learn the fundamentals of a blockchain starting from first principles. We'll cover hashing, mining, consensus and more. After reading this article, you'll have a solid foundation upon which to explore platforms like Ethereum and Solana.

blockchainpost
19 July 202212 min read
An Introduction to Blockchain

Learn the fundamentals of a blockchain starting from first principles. We'll cover hashing, mining, consensus and more. After reading this article, you'll have a solid foundation upon which to explore platforms like Ethereum and Solana.

Read more
blockchainpostAn Introduction to Blockchain

19 July 2022

12 min read

Learn the fundamentals of a blockchain starting from first principles. We'll cover hashing, mining, consensus and more. After reading this article, you'll have a solid foundation upon which to explore platforms like Ethereum and Solana.

Read more