Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 51 additions & 70 deletions packages/core/src/render3/STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ We currently expect Ivy to remain behind the flag until it's feature complete an
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 `.STORING_METADATA_IN_D.TS.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.
- `ngcc`: (Angular Compatibility Compiler) NPM upgrade compiler which reads the `STORING_METADATA_IN_D.TS.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`.

Expand All @@ -22,86 +22,71 @@ The work can be divided into three categories:
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 STORING_METADATA_IN_D.TS from `.d.ts` (see: [STORING_METADATA_IN_D.TS.md](./STORING_METADATA_IN_D.TS.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 [STORING_METADATA_IN_D.TS.md](./STORING_METADATA_IN_D.TS.md)
- ❌ `@Component` => see [STORING_METADATA_IN_D.TS.md](./STORING_METADATA_IN_D.TS.md)
- ❌ `@Directive` => see [STORING_METADATA_IN_D.TS.md](./STORING_METADATA_IN_D.TS.md)
- ❌ `@NgModule` => see [STORING_METADATA_IN_D.TS.md](./STORING_METADATA_IN_D.TS.md)
- ❌ support `extends` for `@Pipe`, `@Component`, `@Directive` and `@NgModule`.
- ✅ Basic setup of the transformer into `tsc`
- ✅ Can read STORING_METADATA_IN_D.TS from `.d.ts` (see: [STORING_METADATA_IN_D.TS.md](./STORING_METADATA_IN_D.TS.md))
- ✅ Detect decorators and convert them to the `defineXXX` method using the `__Compiler` in `@angular/compiler`.
- ✅ Encode selectors into `.d.ts` file.
- ✅ 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
- ✅ Basic setup of stand alone executable
- ✅ Rewrite existing code by interpreting the associated STORING_METADATA_IN_D.TS
- ❌ Integration with WebPack (cli)
- ❌ Rewrite existing code by interpreting the associated STORING_METADATA_IN_D.TS
- ❌ `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)
- ✅ 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.
- ✅ `@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.

# Testing / Debugging
- ❌ in debug mode publish components into DOM nodes for easier debugging.
- ✅ in debug mode publish components into DOM nodes for easier debugging.

# Crosscutting

## Decorators
| Annotation | `defineXXX()` | Run time | Spec | Compiler | Back Patch |
| -------------------- | ------------------------------ | ------- | -------- | -------- | -------- |
| `@Component` | ✅ `defineComponent()` | ✅ | ✅ | ✅ | ❌ |
| `@Directive` | ✅ `defineDirective()` | ✅ | ✅ | ✅ | ❌ |
| `@Directive` | ❌ `defineAbstractDirective()` | ❌ | ❌ | ❌ | ❌ |
| `@Pipe` | ✅ `definePipe()` | ✅ | ✅ | ✅ | ❌ |
| `@Injectable` | ✅ `defineInjectable()` | ✅ | ❌ | ❌ | ❌ |
| `@NgModule` | ✅ `defineInjector()` | ✅ | ❌ | ❌ | ❌ |
| `@ConfigureInjector` | ❌ `defineInjector()` | ❌ | ❌ | ❌ | ❌ |
| Annotation | `defineXXX()` | Run time | Spec | Compiler |
| -------------------- | ------------------------------ | ------- | -------- | -------- |
| `@Component` | ✅ `defineComponent()` | ✅ | ✅ | ✅ |
| `@Directive` | ✅ `defineDirective()` | ✅ | ✅ | ✅ |
| `@Directive` | ✅ `defineBase()` | ✅ | ✅ | ✅ |
| `@Pipe` | ✅ `definePipe()` | ✅ | ✅ | ✅ |
| `@Injectable` | ✅ `defineInjectable()` | ✅ | ✅ | ✅ |
| `@NgModule` | ✅ `defineInjector()` | ✅ | ✅ | ✅ |
| `@ConfigureInjector` | ✅ `defineInjector()` | ❌ | ❌ | ❌ |



## Component Composition
| Feature | Runtime | Spec | Compiler |
| ---------------------------------------- | ------- | -------- | -------- |
| creation reordering based on injection | ❌ | ❌ | ✅ |
| `class CompA extends CompB {}` | ❌ | ❌ | ❌ |
| `class CompA extends CompB { @Input }` | ❌ | ❌ | ❌ |
| `class CompA extends CompB { @Output }` | ❌ | ❌ | ❌ |
| creation reordering based on injection | ✅ | ✅ | ✅ |
| `class CompA extends CompB {}` | ✅ | ✅ | ✅ |
| `class CompA extends CompB { @Input }` | ✅ | ✅ | ✅ |
| `class CompA extends CompB { @Output }` | ✅ | ✅ | ✅ |



Expand Down Expand Up @@ -147,16 +132,12 @@ The goal is for the `@Component` (and friends) to be the compiler of template. S
| `<div style="literal">` | ✅ | ✅ | ✅ |
| `<div [style]="exp">` | ✅ | ✅ | ✅ |
| `<div [style.foo]="exp">` | ✅ | ✅ | ✅ |
| `<div xmlns:foo="url" foo:bar="baz">` <br/>Compiler still needs to be updated to process templates with namespaced attributes. ([see #24386](https://github.com/angular/angular/pull/24386)) | ✅ | ✅ | ❌ |
| `<div xmlns:foo="url" foo:bar="baz">` | ✅ | ✅ | ✅ |
| `{{ ['literal', exp ] }}` | ✅ | ✅ | ✅ |
| `{{ { a: 'literal', b: exp } }}` | ✅ | ✅ | ✅ |
| `{{ exp \| pipe: arg }}` | ✅ | ✅ | ✅ |
| `<svg:g svg:p>` | ✅ | ✅ | ✅ |
| `<img src=[userData]>` sanitization | ❌ | ❌ | ❌ |
| `<div (nocd.click)>` | ❌ | ❌ | ❌ |
| `<div (bubble.click)>` | ❌ | ❌ | ❌ |
| `<div (keyup.enter)>` | ❌ | ❌ | ❌ |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(keyup.enter) works in the current view engine so we should preserve this functionality, otherwise this is a breaking change.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but it is all existing functionality from Renderer2 and so I don't think we need to track it here.

| `<div (hammer.js)>` | ❌ | ❌ | ❌ |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the gestures with hammer.js work today so we should either preserve this or designed an alternative (hammer.js seems to be getting outdated and not maintained those days, if I'm not mistaken).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above comment.

| `<img src=[userData]>` sanitization | ✅ | ✅ | ✅ |
| [`<div (directiveOut)>`][gh23560] | ✅ | ✅ | ✅ |
| [`<ng-template (directiveOut)>`][gh23561] | ✅ | ✅ | ✅ |
| [`<ng-container>`][gh24381] | ✅ | ✅ | ✅ |
Expand Down Expand Up @@ -189,10 +170,10 @@ The goal is for the `@Component` (and friends) to be the compiler of template. S
| `@Query(read)` | ✅ | ✅ | n/a |
| `@Query(selector)` | ✅ | ✅ | n/a |
| `@Query(Type)` | ✅ | ✅ | n/a |
| `@ContentChildren` | ✅ | ✅ | ❌ |
| `@ContentChildren` | ✅ | ✅ | ✅ |
| `@ContentChild` | ✅ | ✅ | ✅ |
| `@ViewChildren` | ✅ | ✅ | ❌ |
| `@ViewChild` | ✅ | ✅ | ❌ |
| `@ViewChildren` | ✅ | ✅ | ✅ |
| `@ViewChild` | ✅ | ✅ | ✅ |



Expand All @@ -201,41 +182,41 @@ The goal is for the `@Component` (and friends) to be the compiler of template. S
| ------------------------------- | ------- | -------- | -------- |
| `<ng-content>` | ✅ | ✅ | ✅ |
| `<ng-content selector="...">` | ✅ | ✅ | ✅ |
| container `projectAs` | ✅ | ✅ | ❌ |
| container `ngProjectAs` | ✅ | ✅ | ✅ |



### Injection Features
| Feature | Runtime | Spec | Compiler |
| ----------------------------------- | ------- | -------- | -------- |
| `inject(Type)` | ✅ | ✅ | ✅ |
| `directiveInject(Type)` | ✅ | ✅ | ❌ |
| `directiveInject(Type)` | ✅ | ✅ | ✅ |
| `inject(Type, SkipSelf)` | ❌ | ❌ | ❌ |
| `attribute('name')` | ✅ | ✅ | ❌ |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it injectAttribute()?

| `injectChangeDetectionRef()` | ✅ | ✅ | ❌ |
| `injectChangeDetectionRef()` | ✅ | ✅ | ✅ |
| `injectElementRef()` | ✅ | ✅ | ✅ |
| `injectViewContainerRef()` | ✅ | ✅ | ✅ |
| `injectTemplateRef()` | ✅ | ✅ | ✅ |
| `injectRenderer2()` | ✅ | ✅ | ✅ |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't these specific instruction being removed at #26064 and #26369?

| default `inject()` with no injector | ❌ | ❌ | ❌ |
| sanitization with no injector | ✅ | ✅ | ❌ |
| default `inject()` with no injector | ✅ | ✅ | ✅ |
| sanitization with no injector | ✅ | ✅ | ✅ |


### I18N
| Feature | Runtime | Spec | Compiler |
| ----------------------------------- | ------- | -------- | -------- |
| translate text literals | ✅ | ✅ | ✅ |
| translate text literals | ❌ | ❌ | ✅ |

@alfaproject alfaproject Oct 11, 2018 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😢

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We realized that the current implementation was flawed. Should have a fix soon.

| rearrange text nodes | ❌ | ❌ | ❌ |
| ICU | ❌ | ❌ | ❌ |


### View Encapsulation
| Feature | Runtime | Spec | Compiler |
| ----------------------------------- | ------- | -------- | -------- |
| Renderer3.None | ✅ | ✅ | ✅ |
| Renderer2.None | ✅ | ✅ | ✅ |
| Renderer2.Emulated | ❌ | ❌ | ❌ |
| Renderer2.Native | ❌ | ❌ | ❌ |
| Renderer3.None | ✅ | ✅ | ✅ |
| Renderer2.None | ✅ | ✅ | ✅ |
| Renderer2.Emulated | ✅ | ✅ | ✅ |
| Renderer2.Native | ✅ | ✅ | ✅ |



Expand Down
57 changes: 57 additions & 0 deletions packages/core/src/render3/STORING_METADATA_IN_D.TS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Storing Metadata in `.d.ts` files

Previous version of Angular used `metadata.json` files to store information about directives/component/pipes/ng-modules.
`ngc` compiler would than do a global analysis to generate the `.ngfactory.ts` files from the `metadata.json`.
Ivy strives for locality, which means that `ngtsc` should not need any global information in order to compile the system.
The above is mostly true.
Unfortunately, in order for `ngtsc` to generate code which is tree shakable `ngtsc` does need to have global knowledge.

Here is an abbreviated example of breakage of tree-shake-ability.
```typescript
@Directive({
selector: '[tooltip]'
})
export class TooltipDirective {
// ngtsc generates this:
static ngDirectiveDef = defineDirective(...);
}

@Component({
selector: 'my-app',
template: 'Hello World!'
})
class MyAppComponent {
// ngtsc generates this:
static ngDirectiveDef = defineComponent({
...
directives: [
// BREAKS TREE-SHAKING!!!
// TooltipDirective included here because it was declared in the NgModule
// ngtsc does not know it can be omitted.
// Only way for ngtsc to know that it can omit TooltipDirective is if it knows
// its selector and see if the selector matches the current component's template.
TooltipDirective
]
});
}

@NgModule({
declarations: [MyAppComponent, TooltipDirective],
bootstrap: [MyAppComponent],
})
class MyAppModule {
// ngtsc generates this:
static ngDirectiveDef = defineNgModule(...);
}
```

Notice that `ngtsc` can't remove `TooltipDirective` because it would need to know its selector and see if the directive matches in the component's template.
Knowing the selector breaks locality and so we make an exception for some locality information such as selector, inputs and outputs.
Since we are breaking the locality rule, we need to store the information someplace since `ngtsc` can't have access to the `TooltipDirective` source.
We store the information in the `.d.ts` file like so.

```typescript
class TooltipDirective {
static ngDirectiveDef: DirectiveDefWithMeta<TooltipDirective, '[tooltip]', '', {}, {}, []>
}
```