Demystifying

Ahead-Of-Time Compilation

In Angular

Let me tell ya a

Story...

let's talk about

Compilers

DUDE...

SERIOUSLY

What is a Compiler?

A compiler is a computer program that transforms source code written in a programming language into another computer language [...] The most common reason for converting source code is to create an executable program.

I mean...

Angular

Template

Compiler

Template Strings

{Parser, Lexer, Tokenizer...}

VM CODE

running application

Compiler

2 Traditional Compilations

〈JIT, AOT〉

What is JIT?

Just-in-time (JIT) compilation, also known as dynamic translation, is compilation done during execution of a program – at run time...

Components

B

U

I

L

D

B

R

O

W

S

E

R

Code Gen

JIT Compilation

VM Code

JIT

 

Dynamic Compilation

OR

JIT drawbacks...

Bundle Size
Performance
Bootstrapping Security

May Be

Can Help

Ahead Of Time

What is AOT?

Ahead-of-time (AOT) compilation is the act of compiling a high-level programming language, into a native machine code with the intention of executing the resulting binary file natively. AOT produces machine optimized code...

Components

B

U

I

L

D

B

R

O

W

S

E

R

Code Gen

AOT Compilation

VM Code

AOT

 

Static Compilation

OR

AOT Needs

Application

Context

However...

In Angular...

@NgModule()

Is The Context

Angular modules

@NgModule({
  imports: [
    BrowserModule, MdModule,
    HttpModule, RoutesModule...
  ],
  declarations: [
    HomeComponent, PersonComponent...
  ],
  providers: [ AwesomeService ],
  bootstrap: [ AppComponent ]
})

Angular in JIT mode

// The browser platform with a compiler
import { 
   platformBrowserDynamic 
} from '@angular/platform-browser-dynamic';


// The app module
import { AppModule } from './app.module';


// Compile (JIT) and launch the module
platformBrowserDynamic().bootstrapModule(
   AppModule
);

Angular in AOT mode

// The browser platform with a compiler
import { 
   platformBrowser 
} from '@angular/platform-browser';

// The generated app factory (AOT)
import { 
   AppModuleNgFactory
} from './app.module.ngfactory';

// Launch with the app module factory.
platformBrowser().bootstrapModuleFactory(
   AppModuleNgFactory
);

Angular in AOT mode

$ npm install \
        @angular/compiler-cli \
        @angular/platform-server \
        @angular/compiler \
        typescript@next --save

$ ./node_modules/.bin/ngc -p tsconfig.aot.json

$ # generates app.module.ngfactory.ts
$ # generates app.component.ngfactory.ts
$ # generates app.component.css.shim.ts
$ # generates ...

Angular Code Gen

(example of app.component.ngfactory.ts)

Oh! Also

Tree—Shaking*

*which is not Dead Code Elimination, BTW

Good News...

~30-60%

Less Code*...

*may not be relevant to huge apps due to the codegen process

No More Dynamic Template Compilation

Less

Security

Risks

No more evals

Faster

Time

To Interaction

Using @angular/cli...

const { AotPlugin } = require('@ngtools/webpack');
const tsconfig = root('./src/tsconfig.browser.json');

module.exports = {
    //...
    plugins: [
        new AotPlugin({
            tsConfigPath: tsconfig
        })
    ]
}

Using webpack...

Bonus...

Make your code

Statically Analyzable...

Lambda expression

// bad
providers: [{
  provide: UrlSerializer,
  useFactory: (xDebugService) => {
    return new XUrlSerializer(xDebugService)
  },
  deps: [XDebugService]
}, ...]

Error encountered resolving symbol values statically.
Calling function 'XXXXX', function calls are not supported.
Consider replacing the function or lambda with a reference
to an exported function...

Lambda expression

// good
export function setupUrlSerializer(xDebugService) {
  return new XUrlSerializer(xDebugService);
}

providers: [{
  provide: UrlSerializer,
  useFactory: setupUrlSerializer,
  deps: [XDebugService]
}, ...]

Error encountered resolving symbol values statically.
Calling function 'XXXXX', function calls are not supported.
Consider replacing the function or lambda with a reference
to an exported function...

Access modifiers

// bad
@Component({template: `{{ foo }}`})
export class AppComponent {
  private foo: any;
}

// good
@Component({template: `{{ foo }}`})
export class AppComponent {
  public foo: any;
}

Error at /app.component.ngfactory.ts Property 'foobar' is private and only accessible within class 'AppComponent'.

Named exports

// bad
@Component({})
class AppComponent {}
export default AppComponent;

// good
@Component({})
export class AppComponent {}

can't find symbol undefined exported from module app.component.ts

Know/found others?

tweet them to me

@manekinekko

Thanks for listening...

manekinekko

Resources

Demystifying AOT compilation in Angular

By Wassim Chegham

Demystifying AOT compilation in Angular

The introduction of NgModule was a huge news for the Angular community. This new API is supposed to help the AOT compilation by providing the compilation context and generate a much lighter application bundle. Let's see how does AOT work...

  • 34,671