Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

The Angular Transformer

rkirov edited this page Dec 12, 2014 · 6 revisions

Angular Transformer

Dart's package manager pub supports a system of pluggable processing scripts called transformers. You can find more info about them at https://www.dartlang.org/tools/pub/assets-and-transformers.html

The angular.dart library comes with a transformer of its own. Its purpose is to generate static structures that remove the need for reflection (dart:mirrors) at runtime. This guarantees your application JS size is minimal after dart2js compilation.

To use the Angular transformer include the following line in your pubspec.yaml:

transformers:
- angular

What does it do?

The transformer goes through the following steps:

  • Call into observe transformer.
  • Find all dart files referenced with <script type="application/dart">.
  • Create injection information for all classes used by dependency injection.
  • Transform relative urls.
  • Create setters and getters for all expressions.
  • Extract all metadata annotations.
  • Transform your application entry-point to use staticApplicationFactory.

The code entry point is lib/transformer.dart. Let's go through each step in detail.

Observable transformer

Angular.dart's change detection supports package:observe @Observable objects, so we need to call into their transformer first.

Find all .dart references in html

Dart's transformer library will go through all /lib files, but it misses .dart files directly referenced from files in /web, thus necessitating this step.

Create Injection Information

Dependency injection needs to be able to reflect on the constructor of an injectable class. For example if I have a class Car that needs an Engine and Brakes, dependency injection needs:

  • a mapping Car as type, to the list of required types [Engine, Brakes].
  • a closure to actually call when the requirements are found - (anEngine, someBreaks) => new Car(anEngine, someBreaks).

This transformer creates these objects for all classes annotated with @Injectable() and stores them in <your_file>_generated_type_factories_map.dart. Use that file to manually check and see if the transformer has found all your injectables.

Note technically this transformer is part of the di package and angular calls into it.

Transform relative urls

A relative url in the templateUrl field of a @Component annotation, poses a question - relative to what? Without any transformation it would be relative to the current page when we send the XHR to fetch it. The transformation makes it relative to the current .dart file. The transformations are recorded in <your_file>_static_type_to_uri_mapper.dart.

Create setters/getters for all expressions

Angular ships with an interpreter that evaluates your template expressions. There is not eval in dart, so the interpreter needs to have closures to call into field getters/setters. For example, if you have <div>{{c = a.b}}</div> in your template the transformer will generate maps of getters like "a": (o) => o.a and setters like "c": (o, v) => o.c = v. This allows the interpreter to perform what amounts to eval("c = a.b").

The output of this transformer is in <your_file>_static_expressions.dart. Inspect that file if you see Missing getter: (o) => o.foo error.

Extract metadata

Class metadata annotations like @Component are not accessible during runtime without reflection. This transformer creates a map between types and their corresponding angular annotations. It is mostly used for @Component and @Decorator, and @Injectable annotations.

For example if you write:

class MyComponent

it would generate the following key-value pairing

MyComponent: [const Component(selector('cmp')]

The output of this transformer is in <your_file>_static_metadata.dart.

Transform your application

All the previous transformers output static structures into *_static_*.dart files. This final steps hooks the static structures into the angular application. Because transformers cannot operate on libraries (like angular), it transforms the point in your code where you call into the applicationFactory and replaces it with the staticApplicationFactory.

Clone this wiki locally