docs(ivy): update STATUS.md with compiler work breakdown (#22874)

PR Close #22874
This commit is contained in:
Misko Hevery 2018-03-19 22:02:48 -07:00 committed by Matias Niemelä
parent f88fba020b
commit b524e4b142
2 changed files with 254 additions and 89 deletions

View File

@ -0,0 +1,92 @@
# Metadata storage in `.d.ts` files
Currently angular stores metadata in `.metadata.json` files. This is problematic for several reasons:
- Error prone (tools have to know how to work with them.)
- Metadata does not follow import/exports.
- Complicated to explain, maintain.
- Hard for 3rd party contributors to add value.
For Ivy we will be storing the metadata directly in `.d.ts` in the form of type information. This has several advantages:
- TypeScript does most of the work of resolution
- 3rd party developers already understand `.d.ts` as well as TypeScript type system.
The key information which Ivy needs is the selector information. That is what pipe, component or directive has to be inserted at which location. These selector maps are declared in `@NgModule` annotations. Therefore the goal is to store: selectors and `@NgModule` import/exports rules.
Let's assume that we have a file such as:
```javascript
@Pipe({ name: 'myPipe' })
export class MyPipe { }
@Component({ selector: `my-component` })
export class MyComponent { }
@Component({ selector: `[myDirective]` })
export class MyDirective { }
@NgModule({
declarations: [MyDirective, MyPipe],
exports: [MyDirective, MyPipe]
})
export class MyModule { }
@NgModule({
declarations: [MyComponent],
imports: [MyModule],
exports: [MyComponent],
})
export class MyAppModule { }
```
Then we can encode the selector information into the types as shown in this `.d.ts` file:
```javascript
export class MyPipe {
static ngPipeDef: PipeDef<{type: MyPipe, selector: 'myPipe'}>;
}
export class MyComponent {
static ngComponentDef: ComponentDef<{type: MyComponent, selector: 'my-component'}>;
}
export class MyDirective {
static ngDirectiveDef: DirectiveDef<{type: MyDirective, selector: '[myDirective]'}>;
}
export class MyModule {
static ngInjectorDef: InjectorDef<MyAppModule>;
static ngModule = {
type: MyModule,
imports: [],
exports: [MyDirective, MyPipe]
};
}
export class MyAppModule {
static ngModule = {
type: MyAppModule,
imports: [MyModule],
exports: [MyComponent]
};
}
```
This means that `ngtsc` can extract selector information from `Program` by having TypeScript resolving the types and then doing walking the resolved AST. This would be equivalent to something like this in code:
```javascript
const MyComponent_selector /* inferred type: 'my-component' */ = getSelector(MyComponent);
const MyDirective_selector /* inferred type: '[myDirective]' */ = getSelector(MyDirective);
const MyPipe_selector /* inferred type: 'myPipe' */ = getSelector(MyPipe);
const MyModule_exports /* inferred type: typeof MyDirective | typeof MyPipe */ =
getNgModuleExports(MyModule);
const MyAppModule_imports /* inferred type: typeof MyModule */ = getNgModuleImports(MyAppModule);
const MyAppModule_transitive_imports /* inferred type: typeof MyDirective | typeof MyPipe */ =
getNgModuleExports(MyAppModule_imports);
declare function getNgModuleExports<T>(module: {ngModule: {exports: T[]}}): T;
declare function getNgModuleImports<T>(module: {ngModule: {imports: T[]}}): T;
declare function getSelector<T>(componentType: {
ngComponentDef?: ComponentDef<{selector: T}>,
ngDirectiveDef?: DirectiveDef<{selector: T}>,
ngPipeDef?: PipeDef<{selector: T}>,
}): T;
````

View File

@ -8,7 +8,79 @@ We currently expect Ivy to remain behind the flag until it's feature complete an
# Implementation Status
## Annotations
The work can be divided into three categories:
- `@angular/compiler-cli`: TypeScript transformer pipeline which includes two command line tools:
- `ngtsc`: (Angular TypeScript Compiler) Angular compiler which strips out `@Component` (and friends) and replaces it with `defineComponent` (and friends).
- `ngcc`: (Angular Compatibility Compiler) NPM upgrade compiler which reads the `.metadata.json` files and `.js` files and adds `defineComponent` (and friends) into the `node_module`. This in effect converts a pre-ivy module into ivy module.
- `@angular/compiler`: Ivy Compiler which converts decorator into ivy
- `@angular/core`: Decorators which can be patched with `@angular/compiler`.
## `@angular/compiler-cli` changes
### `ngtsc` TSC compiler transformer
TSC transformer which removes and converts `@Pipe`, `@Component`, `@Directive` and `@NgModule`
to the corresponding `definePipe`, `defineComponent`, `defineDirective` and `defineInjector`.
- ❌ Basic setup of the transformer into `tsc`
- ❌ Can read metadata from `.d.ts` (see: [METADATA.md](./METADATA.md))
- ❌ Detect decorators and convert them to the `defineXXX` method using the `__Compiler` in `@angular/compiler`.
- ❌ `@Pipe` => `definePipe`
- ❌ `@Component` => `defineComponent`
- ❌ `@Directive` => `defineDirective`
- ❌ `@NgModule` => `defineInjector`
- ❌ Encode selectors into `.d.ts` file.
- ❌ `@Pipe` => see [METADATA.md](./METADATA.md)
- ❌ `@Component` => see [METADATA.md](./METADATA.md)
- ❌ `@Directive` => see [METADATA.md](./METADATA.md)
- ❌ `@NgModule` => see [METADATA.md](./METADATA.md)
- ❌ support `extends` for `@Pipe`, `@Component`, `@Directive` and `@NgModule`.
- ❌ Documentation
### `ngcc` Angular `node_module` compatibility compiler
A tool which "upgrades" `node_module` compiled with non-ivy `ngc` into ivy compliant format.
- ❌ Basic setup of stand alone executable
- ❌ Integration with WebPack (cli)
- ❌ Rewrite existing code by interpreting the associated metadata
- ❌ `PipeCompiler`: `@Pipe` => `definePipe`
- ❌ `DirectiveCompiler`: `@Directive` => `defineDirective`
- ❌ `NgModuleCompiler`: `@NgModule` => `defineInjector`
- ❌ `ComponentCompiler`: `@Component` => `defineComponent`
- ❌ `TemplateCompiler`
- ❌ `StyleCompiler`
- ❌ Documentation
## `@angular/compiler` changes
- ❌ Component compilation: Translates `@Component` => `defineComponent`
- ❌ `TemplateCompiler` (current known as `ViewCompiler`)
- ❌ `StyleCompiler`
- ❌ `PipeCompiler`: Translates `@Pipe` => `definePipe`
- ❌ `DirectiveCompiler`: Translates `@Directive` => `defineDirective`
- ❌ `InjectableCompiler`: Translates `@Injectable` => `defineInjectable`
- ❌ `NgModuleCompiler`: Translates `@NgModule` => `defineInjector` (and `defineNgModule` only in jit)
- ❌ Documentation
## `@angular/core` changes
The goal is for the `@Component` (and friends) to be the compiler of template. Since decorators are functions which execute during parsing of the `.js` file, the decorator can compile the template into Ivy. The AoT compiler's job is to remove the `@Component` and replace it with call to `defineComponent`.
- ❌ Remove `createDecorator` (and friends) since we no longer support other modes.
- ❌ `@angular/compiler` can patch itself onto:
- ❌ `@Injectable`
- ❌ `@NgModule`
- ❌ `@Pipe`
- ❌ `@Directive`
- ❌ `@Component`
- ❌ `ResourceLoader.resolved: Promise<>` Returns true if all `templateUrl`s and `styleUrl` have been resolved and application is ready to be bootstrapped.
# Crosscutting
## Decorators
| Annotation | `defineXXX()` | Run time | Spec | Compiler | Back Patch |
| -------------------- | ------------------------------ | ------- | -------- | -------- | -------- |
| `@Component` | ✅ `defineComponent()` | ✅ | ✅ | ✅ | ❌ |
@ -31,86 +103,6 @@ We currently expect Ivy to remain behind the flag until it's feature complete an
## Life Cycle Hooks
| Feature | Runtime | Spec | Compiler |
| ------------------------- | ------- | -------- | -------- |
| `onChanges()` | ✅ | ✅ | ✅ |
| `onDestroy()` | ✅ | ✅ | ✅ |
| `onInit()` | ✅ | ✅ | ✅ |
| `onChanges()` | ✅ | ✅ | ✅ |
| `doCheck()` | ✅ | ✅ | ✅ |
| `afterViewChecked()` | ✅ | ✅ | ✅ |
| `afterViewInit()` | ✅ | ✅ | ✅ |
| `afterContentChecked()` | ✅ | ✅ | ✅ |
| `afterContentInit()` | ✅ | ✅ | ✅ |
| listener teardown | ✅ | ✅ | ✅ |
## Template Syntax
| Feature | Runtime | Spec | Compiler |
| -------------------------------- | ------- | -------- | -------- |
| `<div>` | ✅ | ✅ | ✅ |
| `<div>{{exp}}</div>` | ✅ | ✅ | ✅ |
| `<div attr=value>` | ✅ | ✅ | ✅ |
| `<div (click)="stmt">` | ✅ | ✅ | ✅ |
| `<div #foo>` | ✅ | ✅ | ✅ |
| `<div #foo="bar">` | ✅ | ✅ | ✅ |
| `<div [value]="exp">` | ✅ | ✅ | ✅ |
| `<div title="Hello {{name}}!">` | ✅ | ✅ | ✅ |
| `<div [attr.value]="exp">` | ✅ | ✅ | ❌ |
| `<div class="literal">` | ✅ | ✅ | ✅ |
| `<div [class]="exp">` | ❌ | ❌ | ❌ |
| `<div [class.foo]="exp">` | ✅ | ✅ | ❌ |
| `<div style="literal">` | ✅ | ✅ | ✅ |
| `<div [style]="exp">` | ❌ | ❌ | ❌ |
| `<div [style.foo]="exp">` | ✅ | ✅ | ❌ |
| `{{ ['literal', exp ] }}` | ✅ | ✅ | ✅ |
| `{{ { a: 'literal', b: exp } }}` | ✅ | ✅ | ✅ |
| `{{ exp \| pipe: arg }}` | ✅ | ✅ | ✅ |
## `@Query`
| Feature | Runtime | Spec | Compiler |
| ------------------------------- | ------- | -------- | -------- |
| `@Query(descendants)` | ✅ | ✅ | n/a |
| `@Query(one)` | ✅ | ✅ | n/a |
| `@Query(read)` | ✅ | ✅ | n/a |
| `@Query(selector)` | ✅ | ✅ | n/a |
| `@Query(Type)` | ✅ | ✅ | n/a |
| `@ContentChildred` | ✅ | ✅ | ❌ |
| `@ContentChild` | ✅ | ✅ | ✅ |
| `@ViewChildren` | ✅ | ✅ | ❌ |
| `@ViewChild` | ✅ | ✅ | ✅ |
## Content Projection
| Feature | Runtime | Spec | Compiler |
| ------------------------------- | ------- | -------- | -------- |
| `<ng-content>` | ✅ | ✅ | ✅ |
| `<ng-content selector="...">` | ✅ | ✅ | ✅ |
| container `projectAs` | ✅ | ✅ | ❌ |
## Injection Features
| Feature | Runtime | Spec | Compiler |
| ----------------------------------- | ------- | -------- | -------- |
| `inject(Type)` | ✅ | ✅ | ✅ |
| `directiveInject(Type)` | ✅ | ✅ | ❌ |
| `inject(Type, SkipSelf)` | ❌ | ❌ | ❌ |
| `attribute('name')` | ✅ | ✅ | ❌ |
| `injectChangeDetectionRef()` | ✅ | ✅ | ❌ |
| `injectElementRef()` | ✅ | ✅ | ✅ |
| `injectViewContainerRef()` | ✅ | ✅ | ✅ |
| `injectTemplateRef()` | ✅ | ✅ | ✅ |
| default `inject()` with no injector | ❌ | ❌ | ❌ |
| sanitization with no injector | ✅ | ✅ | ❌ |
## Change Detection
| Feature | Runtime |
| ----------------------------------- | ------- |
@ -131,11 +123,90 @@ We currently expect Ivy to remain behind the flag until it's feature complete an
| ----------------------------------- | ------- |
| `renderComponent()` | ✅ |
| `getHostElement()` | ✅ |
| `createInjector()` | ❌ |
| `createInjector()` | ✅ |
## Template Compiler
### Template Syntax
| Feature | Runtime | Spec | Compiler |
| --------------------------------------- | ------- | -------- | -------- |
| `<div>` | ✅ | ✅ | ✅ |
| `<div>{{exp}}</div>` | ✅ | ✅ | ✅ |
| `<div attr=value>` | ✅ | ✅ | ✅ |
| `<div (click)="stmt">` | ✅ | ✅ | ✅ |
| `<div #foo>` | ✅ | ✅ | ✅ |
| `<div #foo="bar">` | ✅ | ✅ | ✅ |
| `<div [value]="exp">` | ✅ | ✅ | ✅ |
| `<div title="Hello {{name}}!">` | ✅ | ✅ | ✅ |
| `<div [attr.value]="exp">` | ✅ | ✅ | ❌ |
| `<div class="literal">` | ✅ | ✅ | ✅ |
| `<div [class]="exp">` | ❌ | ❌ | ❌ |
| `<div [class.foo]="exp">` | ✅ | ✅ | ❌ |
| `<div style="literal">` | ✅ | ✅ | ✅ |
| `<div [style]="exp">` | ❌ | ❌ | ❌ |
| `<div [style.foo]="exp">` | ✅ | ✅ | ❌ |
| `{{ ['literal', exp ] }}` | ✅ | ✅ | ✅ |
| `{{ { a: 'literal', b: exp } }}` | ✅ | ✅ | ✅ |
| `{{ exp \| pipe: arg }}` | ✅ | ✅ | ✅ |
| `<svg:g svg:p>` | ❌ | ❌ | ❌ |
| `<img src=[userData]>` sanitization | ❌ | ❌ | ❌ |
### Life Cycle Hooks
| Feature | Runtime | Spec | Compiler |
| ------------------------- | ------- | -------- | -------- |
| `onChanges()` | ✅ | ✅ | ✅ |
| `onDestroy()` | ✅ | ✅ | ✅ |
| `onInit()` | ✅ | ✅ | ✅ |
| `onChanges()` | ✅ | ✅ | ✅ |
| `doCheck()` | ✅ | ✅ | ✅ |
| `afterViewChecked()` | ✅ | ✅ | ✅ |
| `afterViewInit()` | ✅ | ✅ | ✅ |
| `afterContentChecked()` | ✅ | ✅ | ✅ |
| `afterContentInit()` | ✅ | ✅ | ✅ |
| listener teardown | ✅ | ✅ | ✅ |
## I18N
### `@Query`
| Feature | Runtime | Spec | Compiler |
| ------------------------------- | ------- | -------- | -------- |
| `@Query(descendants)` | ✅ | ✅ | n/a |
| `@Query(one)` | ✅ | ✅ | n/a |
| `@Query(read)` | ✅ | ✅ | n/a |
| `@Query(selector)` | ✅ | ✅ | n/a |
| `@Query(Type)` | ✅ | ✅ | n/a |
| `@ContentChildred` | ✅ | ✅ | ❌ |
| `@ContentChild` | ✅ | ✅ | ✅ |
| `@ViewChildren` | ✅ | ✅ | ❌ |
| `@ViewChild` | ✅ | ✅ | ✅ |
### Content Projection
| Feature | Runtime | Spec | Compiler |
| ------------------------------- | ------- | -------- | -------- |
| `<ng-content>` | ✅ | ✅ | ✅ |
| `<ng-content selector="...">` | ✅ | ✅ | ✅ |
| container `projectAs` | ✅ | ✅ | ❌ |
### Injection Features
| Feature | Runtime | Spec | Compiler |
| ----------------------------------- | ------- | -------- | -------- |
| `inject(Type)` | ✅ | ✅ | ✅ |
| `directiveInject(Type)` | ✅ | ✅ | ❌ |
| `inject(Type, SkipSelf)` | ❌ | ❌ | ❌ |
| `attribute('name')` | ✅ | ✅ | ❌ |
| `injectChangeDetectionRef()` | ✅ | ✅ | ❌ |
| `injectElementRef()` | ✅ | ✅ | ✅ |
| `injectViewContainerRef()` | ✅ | ✅ | ✅ |
| `injectTemplateRef()` | ✅ | ✅ | ✅ |
| default `inject()` with no injector | ❌ | ❌ | ❌ |
| sanitization with no injector | ✅ | ✅ | ❌ |
### I18N
| Feature | Runtime | Spec | Compiler |
| ----------------------------------- | ------- | -------- | -------- |
| translate text literals | ❌ | ❌ | ❌ |
@ -143,10 +214,17 @@ We currently expect Ivy to remain behind the flag until it's feature complete an
| ICU | ❌ | ❌ | ❌ |
### View Encapsulation
| Feature | Runtime | Spec | Compiler |
| ----------------------------------- | ------- | -------- | -------- |
| Render3.None | ✅ | ✅ | ✅ |
| Render2.None | ✅ | ✅ | ✅ |
| Render2.Emulated | ❌ | ❌ | ❌ |
| Render2.Native | ❌ | ❌ | ❌ |
## `______Ref`s
### `______Ref`s
| Method | View Container Ref | Template Ref | Embeded View Ref | View Ref | Element Ref | Change Detection Ref |
| ---------------------- | ------------------ | ------------ | ---------------- | -------- | ----------- | -------------------- |
| `clear()` | ❌ | n/a | n/a | n/a | n/a | n/a |
@ -165,8 +243,3 @@ We currently expect Ivy to remain behind the flag until it's feature complete an
| `checkNoChanges()` | n/a | n/a | ❌ | n/a | n/a | ✅ |
| `reattach()` | n/a | n/a | ❌ | n/a | n/a | ✅ |
| `nativeElement()` | n/a | n/a | n/a | n/a | ✅ | n/a |
## Missing Pieces
- Sanitization ✅
- Back patching in tree shakable way. ❌
- attribute namespace ❌