parent
7fbeb04b7c
commit
9ebb4c02a2
|
@ -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:
|
The work can be divided into three categories:
|
||||||
- `@angular/compiler-cli`: TypeScript transformer pipeline which includes two command line tools:
|
- `@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).
|
- `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/compiler`: Ivy Compiler which converts decorator into ivy
|
||||||
- `@angular/core`: Decorators which can be patched with `@angular/compiler`.
|
- `@angular/core`: Decorators which can be patched with `@angular/compiler`.
|
||||||
|
|
||||||
|
@ -22,45 +22,31 @@ The work can be divided into three categories:
|
||||||
TSC transformer which removes and converts `@Pipe`, `@Component`, `@Directive` and `@NgModule`
|
TSC transformer which removes and converts `@Pipe`, `@Component`, `@Directive` and `@NgModule`
|
||||||
to the corresponding `definePipe`, `defineComponent`, `defineDirective` and `defineInjector`.
|
to the corresponding `definePipe`, `defineComponent`, `defineDirective` and `defineInjector`.
|
||||||
|
|
||||||
- ❌ Basic setup of the transformer into `tsc`
|
- ✅ 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))
|
- ✅ 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`.
|
- ✅ Detect decorators and convert them to the `defineXXX` method using the `__Compiler` in `@angular/compiler`.
|
||||||
- ❌ `@Pipe` => `definePipe`
|
- ✅ Encode selectors into `.d.ts` file.
|
||||||
- ❌ `@Component` => `defineComponent`
|
- ✅ support `extends` for `@Pipe`, `@Component`, `@Directive` and `@NgModule`.
|
||||||
- ❌ `@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`.
|
|
||||||
- ❌ Documentation
|
- ❌ Documentation
|
||||||
|
|
||||||
### `ngcc` Angular `node_module` compatibility compiler
|
### `ngcc` Angular `node_module` compatibility compiler
|
||||||
|
|
||||||
A tool which "upgrades" `node_module` compiled with non-ivy `ngc` into ivy compliant format.
|
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)
|
- ❌ 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
|
- ❌ Documentation
|
||||||
|
|
||||||
## `@angular/compiler` changes
|
## `@angular/compiler` changes
|
||||||
|
|
||||||
- ❌ Component compilation: Translates `@Component` => `defineComponent`
|
- ✅ Component compilation: Translates `@Component` => `defineComponent`
|
||||||
- ❌ `TemplateCompiler` (current known as `ViewCompiler`)
|
- ✅ `TemplateCompiler` (current known as `ViewCompiler`)
|
||||||
- ❌ `StyleCompiler`
|
- ✅ `StyleCompiler`
|
||||||
- ❌ `PipeCompiler`: Translates `@Pipe` => `definePipe`
|
- ✅ `PipeCompiler`: Translates `@Pipe` => `definePipe`
|
||||||
- ❌ `DirectiveCompiler`: Translates `@Directive` => `defineDirective`
|
- ✅ `DirectiveCompiler`: Translates `@Directive` => `defineDirective`
|
||||||
- ❌ `InjectableCompiler`: Translates `@Injectable` => `defineInjectable`
|
- ✅ `InjectableCompiler`: Translates `@Injectable` => `defineInjectable`
|
||||||
- ❌ `NgModuleCompiler`: Translates `@NgModule` => `defineInjector` (and `defineNgModule` only in jit)
|
- ✅ `NgModuleCompiler`: Translates `@NgModule` => `defineInjector` (and `defineNgModule` only in jit)
|
||||||
- ❌ Documentation
|
- ❌ Documentation
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,40 +54,39 @@ A tool which "upgrades" `node_module` compiled with non-ivy `ngc` into ivy compl
|
||||||
|
|
||||||
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`.
|
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:
|
||||||
- ❌ `@angular/compiler` can patch itself onto:
|
- ✅ `@Injectable`
|
||||||
- ❌ `@Injectable`
|
- ✅ `@NgModule`
|
||||||
- ❌ `@NgModule`
|
- ✅ `@Pipe`
|
||||||
- ❌ `@Pipe`
|
- ✅ `@Directive`
|
||||||
- ❌ `@Directive`
|
- ✅ `@Component`
|
||||||
- ❌ `@Component`
|
- ✅ `ResourceLoader.resolved: Promise<>` Returns true if all `templateUrl`s and `styleUrl` have been resolved and application is ready to be bootstrapped.
|
||||||
- ❌ `ResourceLoader.resolved: Promise<>` Returns true if all `templateUrl`s and `styleUrl` have been resolved and application is ready to be bootstrapped.
|
|
||||||
|
|
||||||
# Testing / Debugging
|
# 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
|
# Crosscutting
|
||||||
|
|
||||||
## Decorators
|
## Decorators
|
||||||
| Annotation | `defineXXX()` | Run time | Spec | Compiler | Back Patch |
|
| Annotation | `defineXXX()` | Run time | Spec | Compiler |
|
||||||
| -------------------- | ------------------------------ | ------- | -------- | -------- | -------- |
|
| -------------------- | ------------------------------ | ------- | -------- | -------- |
|
||||||
| `@Component` | ✅ `defineComponent()` | ✅ | ✅ | ✅ | ❌ |
|
| `@Component` | ✅ `defineComponent()` | ✅ | ✅ | ✅ |
|
||||||
| `@Directive` | ✅ `defineDirective()` | ✅ | ✅ | ✅ | ❌ |
|
| `@Directive` | ✅ `defineDirective()` | ✅ | ✅ | ✅ |
|
||||||
| `@Directive` | ❌ `defineAbstractDirective()` | ❌ | ❌ | ❌ | ❌ |
|
| `@Directive` | ✅ `defineBase()` | ✅ | ✅ | ✅ |
|
||||||
| `@Pipe` | ✅ `definePipe()` | ✅ | ✅ | ✅ | ❌ |
|
| `@Pipe` | ✅ `definePipe()` | ✅ | ✅ | ✅ |
|
||||||
| `@Injectable` | ✅ `defineInjectable()` | ✅ | ❌ | ❌ | ❌ |
|
| `@Injectable` | ✅ `defineInjectable()` | ✅ | ✅ | ✅ |
|
||||||
| `@NgModule` | ✅ `defineInjector()` | ✅ | ❌ | ❌ | ❌ |
|
| `@NgModule` | ✅ `defineInjector()` | ✅ | ✅ | ✅ |
|
||||||
| `@ConfigureInjector` | ❌ `defineInjector()` | ❌ | ❌ | ❌ | ❌ |
|
| `@ConfigureInjector` | ✅ `defineInjector()` | ❌ | ❌ | ❌ |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Component Composition
|
## Component Composition
|
||||||
| Feature | Runtime | Spec | Compiler |
|
| Feature | Runtime | Spec | Compiler |
|
||||||
| ---------------------------------------- | ------- | -------- | -------- |
|
| ---------------------------------------- | ------- | -------- | -------- |
|
||||||
| creation reordering based on injection | ❌ | ❌ | ✅ |
|
| creation reordering based on injection | ✅ | ✅ | ✅ |
|
||||||
| `class CompA extends CompB {}` | ❌ | ❌ | ❌ |
|
| `class CompA extends CompB {}` | ✅ | ✅ | ✅ |
|
||||||
| `class CompA extends CompB { @Input }` | ❌ | ❌ | ❌ |
|
| `class CompA extends CompB { @Input }` | ✅ | ✅ | ✅ |
|
||||||
| `class CompA extends CompB { @Output }` | ❌ | ❌ | ❌ |
|
| `class CompA extends CompB { @Output }` | ✅ | ✅ | ✅ |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -147,16 +132,12 @@ The goal is for the `@Component` (and friends) to be the compiler of template. S
|
||||||
| `<div style="literal">` | ✅ | ✅ | ✅ |
|
| `<div style="literal">` | ✅ | ✅ | ✅ |
|
||||||
| `<div [style]="exp">` | ✅ | ✅ | ✅ |
|
| `<div [style]="exp">` | ✅ | ✅ | ✅ |
|
||||||
| `<div [style.foo]="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 ] }}` | ✅ | ✅ | ✅ |
|
| `{{ ['literal', exp ] }}` | ✅ | ✅ | ✅ |
|
||||||
| `{{ { a: 'literal', b: exp } }}` | ✅ | ✅ | ✅ |
|
| `{{ { a: 'literal', b: exp } }}` | ✅ | ✅ | ✅ |
|
||||||
| `{{ exp \| pipe: arg }}` | ✅ | ✅ | ✅ |
|
| `{{ exp \| pipe: arg }}` | ✅ | ✅ | ✅ |
|
||||||
| `<svg:g svg:p>` | ✅ | ✅ | ✅ |
|
| `<svg:g svg:p>` | ✅ | ✅ | ✅ |
|
||||||
| `<img src=[userData]>` sanitization | ❌ | ❌ | ❌ |
|
| `<img src=[userData]>` sanitization | ✅ | ✅ | ✅ |
|
||||||
| `<div (nocd.click)>` | ❌ | ❌ | ❌ |
|
|
||||||
| `<div (bubble.click)>` | ❌ | ❌ | ❌ |
|
|
||||||
| `<div (keyup.enter)>` | ❌ | ❌ | ❌ |
|
|
||||||
| `<div (hammer.js)>` | ❌ | ❌ | ❌ |
|
|
||||||
| [`<div (directiveOut)>`][gh23560] | ✅ | ✅ | ✅ |
|
| [`<div (directiveOut)>`][gh23560] | ✅ | ✅ | ✅ |
|
||||||
| [`<ng-template (directiveOut)>`][gh23561] | ✅ | ✅ | ✅ |
|
| [`<ng-template (directiveOut)>`][gh23561] | ✅ | ✅ | ✅ |
|
||||||
| [`<ng-container>`][gh24381] | ✅ | ✅ | ✅ |
|
| [`<ng-container>`][gh24381] | ✅ | ✅ | ✅ |
|
||||||
|
@ -189,10 +170,10 @@ The goal is for the `@Component` (and friends) to be the compiler of template. S
|
||||||
| `@Query(read)` | ✅ | ✅ | n/a |
|
| `@Query(read)` | ✅ | ✅ | n/a |
|
||||||
| `@Query(selector)` | ✅ | ✅ | n/a |
|
| `@Query(selector)` | ✅ | ✅ | n/a |
|
||||||
| `@Query(Type)` | ✅ | ✅ | n/a |
|
| `@Query(Type)` | ✅ | ✅ | n/a |
|
||||||
| `@ContentChildren` | ✅ | ✅ | ❌ |
|
| `@ContentChildren` | ✅ | ✅ | ✅ |
|
||||||
| `@ContentChild` | ✅ | ✅ | ✅ |
|
| `@ContentChild` | ✅ | ✅ | ✅ |
|
||||||
| `@ViewChildren` | ✅ | ✅ | ❌ |
|
| `@ViewChildren` | ✅ | ✅ | ✅ |
|
||||||
| `@ViewChild` | ✅ | ✅ | ❌ |
|
| `@ViewChild` | ✅ | ✅ | ✅ |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -201,7 +182,7 @@ The goal is for the `@Component` (and friends) to be the compiler of template. S
|
||||||
| ------------------------------- | ------- | -------- | -------- |
|
| ------------------------------- | ------- | -------- | -------- |
|
||||||
| `<ng-content>` | ✅ | ✅ | ✅ |
|
| `<ng-content>` | ✅ | ✅ | ✅ |
|
||||||
| `<ng-content selector="...">` | ✅ | ✅ | ✅ |
|
| `<ng-content selector="...">` | ✅ | ✅ | ✅ |
|
||||||
| container `projectAs` | ✅ | ✅ | ❌ |
|
| container `ngProjectAs` | ✅ | ✅ | ✅ |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -209,22 +190,22 @@ The goal is for the `@Component` (and friends) to be the compiler of template. S
|
||||||
| Feature | Runtime | Spec | Compiler |
|
| Feature | Runtime | Spec | Compiler |
|
||||||
| ----------------------------------- | ------- | -------- | -------- |
|
| ----------------------------------- | ------- | -------- | -------- |
|
||||||
| `inject(Type)` | ✅ | ✅ | ✅ |
|
| `inject(Type)` | ✅ | ✅ | ✅ |
|
||||||
| `directiveInject(Type)` | ✅ | ✅ | ❌ |
|
| `directiveInject(Type)` | ✅ | ✅ | ✅ |
|
||||||
| `inject(Type, SkipSelf)` | ❌ | ❌ | ❌ |
|
| `inject(Type, SkipSelf)` | ❌ | ❌ | ❌ |
|
||||||
| `attribute('name')` | ✅ | ✅ | ❌ |
|
| `attribute('name')` | ✅ | ✅ | ❌ |
|
||||||
| `injectChangeDetectionRef()` | ✅ | ✅ | ❌ |
|
| `injectChangeDetectionRef()` | ✅ | ✅ | ✅ |
|
||||||
| `injectElementRef()` | ✅ | ✅ | ✅ |
|
| `injectElementRef()` | ✅ | ✅ | ✅ |
|
||||||
| `injectViewContainerRef()` | ✅ | ✅ | ✅ |
|
| `injectViewContainerRef()` | ✅ | ✅ | ✅ |
|
||||||
| `injectTemplateRef()` | ✅ | ✅ | ✅ |
|
| `injectTemplateRef()` | ✅ | ✅ | ✅ |
|
||||||
| `injectRenderer2()` | ✅ | ✅ | ✅ |
|
| `injectRenderer2()` | ✅ | ✅ | ✅ |
|
||||||
| default `inject()` with no injector | ❌ | ❌ | ❌ |
|
| default `inject()` with no injector | ✅ | ✅ | ✅ |
|
||||||
| sanitization with no injector | ✅ | ✅ | ❌ |
|
| sanitization with no injector | ✅ | ✅ | ✅ |
|
||||||
|
|
||||||
|
|
||||||
### I18N
|
### I18N
|
||||||
| Feature | Runtime | Spec | Compiler |
|
| Feature | Runtime | Spec | Compiler |
|
||||||
| ----------------------------------- | ------- | -------- | -------- |
|
| ----------------------------------- | ------- | -------- | -------- |
|
||||||
| translate text literals | ✅ | ✅ | ✅ |
|
| translate text literals | ❌ | ❌ | ✅ |
|
||||||
| rearrange text nodes | ❌ | ❌ | ❌ |
|
| rearrange text nodes | ❌ | ❌ | ❌ |
|
||||||
| ICU | ❌ | ❌ | ❌ |
|
| ICU | ❌ | ❌ | ❌ |
|
||||||
|
|
||||||
|
@ -232,10 +213,10 @@ The goal is for the `@Component` (and friends) to be the compiler of template. S
|
||||||
### View Encapsulation
|
### View Encapsulation
|
||||||
| Feature | Runtime | Spec | Compiler |
|
| Feature | Runtime | Spec | Compiler |
|
||||||
| ----------------------------------- | ------- | -------- | -------- |
|
| ----------------------------------- | ------- | -------- | -------- |
|
||||||
| Renderer3.None | ✅ | ✅ | ✅ |
|
| Renderer3.None | ✅ | ✅ | ✅ |
|
||||||
| Renderer2.None | ✅ | ✅ | ✅ |
|
| Renderer2.None | ✅ | ✅ | ✅ |
|
||||||
| Renderer2.Emulated | ❌ | ❌ | ❌ |
|
| Renderer2.Emulated | ✅ | ✅ | ✅ |
|
||||||
| Renderer2.Native | ❌ | ❌ | ❌ |
|
| Renderer2.Native | ✅ | ✅ | ✅ |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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]', '', {}, {}, []>
|
||||||
|
}
|
||||||
|
```
|
Loading…
Reference in New Issue