docs: fix migrations formatting (#33267)

PR Close #33267
This commit is contained in:
Kapunahele Wong 2019-10-19 08:50:50 -04:00 committed by Andrew Kushnir
parent 02134172dd
commit de62d8ebdb
5 changed files with 91 additions and 139 deletions

View File

@ -3,17 +3,12 @@
## What does this migration do?
In Angular version 8, a schematic added `static` flags to all `@ViewChild()`
and `@ContentChild()` queries.
In Angular version 8, a schematic added `static` flags to all `@ViewChild()` and `@ContentChild()` queries.
This was the first step towards changing the default behavior.
With version 9, the default value
changes to `static: false` and the flag becomes optional.
With version 9, the default value changes to `static: false` and the flag becomes optional.
This schematic scans classes in the compilation and for each
class, checks if the members have a `@ViewChild()` or
`@ContentChild()` query with the `static` flag set to
`false`. If so, the schematic removes the flag, as it
now matches the default.
This schematic scans classes in the compilation and for each class, checks if the members have a `@ViewChild()` or `@ContentChild()` query with the `static` flag set to `false`.
If so, the schematic removes the flag, as it now matches the default.
**Before:**
```ts
@ -31,48 +26,31 @@ now matches the default.
@ViewChild('bar', {static: true}) bar: ElementRef;
```
Note that the flag is not supported in `@ViewChildren()`
or `@ContentChildren()` queries, so the schematic
will not check these properties.
Note that the flag is not supported in `@ViewChildren()` or `@ContentChildren()` queries, so the schematic will not check these properties.
## Why is this migration necessary?
This schematic performs a code cleanup to remove `static`
flags that match the default, as they are no longer
necessary. Functionally, the code change should be a noop.
This schematic performs a code cleanup to remove `static` flags that match the default, as they are no longer necessary.
Functionally, the code change should be a noop.
Before version 9, Angular figured out the static or
dynamic nature of a query automatically, based
on how the template was written. Looking at templates
in this way, however, caused buggy and surprising behavior
(see more about that in the [Static Query Migration Guide](guide/static-query-migration#what-does-this-flag-mean)).
As of version 9, Angular uses dynamic queries
(`static: false`) by default, which simplifies
queries. Developers can still explicitly set a
query to `static: true` if necessary.
Before version 9, Angular figured out the static or dynamic nature of a query automatically, based on how the template was written.
Looking at templates in this way, however, caused buggy and surprising behavior (see more about that in the [Static Query Migration Guide](guide/static-query-migration#what-does-this-flag-mean)).
As of version 9, Angular uses dynamic queries (`static: false`) by default, which simplifies queries.
Developers can still explicitly set a query to `static: true` if necessary.
<div class=" alert is-helpful">
### What is the difference between static and dynamic queries?
The `static` option for `@ViewChild()` and `@ContentChild()`
queries determines when
the query results become available.
The `static` option for `@ViewChild()` and `@ContentChild()` queries determines when the query results become available.
With static queries (`static: true`), the query resolves
once the view has been created, but before change detection runs.
The result, though, will never be updated to reflect
changes to your view, such as
changes to `ngIf` and `ngFor` blocks.
With static queries (`static: true`), the query resolves once the view has been created, but before change detection runs.
The result, though, will never be updated to reflect changes to your view, such as changes to `ngIf` and `ngFor` blocks.
With dynamic queries (`static: false`), the query resolves
after either `ngAfterViewInit()` or
`ngAfterContentInit()` for `@ViewChild()` and `@ContentChild()`
respectively. The result will
be updated for changes to your view, such as changes to
`ngIf` and `ngFor` blocks.
With dynamic queries (`static: false`), the query resolves after either `ngAfterViewInit()` or `ngAfterContentInit()` for `@ViewChild()` and `@ContentChild()` respectively.
The result will be updated for changes to your view, such as changes to `ngIf` and `ngFor` blocks.
For more information, see the following entries in the
[Static Query Migration Guide](https://angular.io/guide/static-query-migration):
@ -86,22 +64,19 @@ For more information, see the following entries in the
## What does this mean for libraries?
In order to support applications that are still running
with version 8, the safest option for libraries is to
retain the `static` flag to keep the resolution
timing consistent.
In order to support applications that are still running with version 8, the safest option for libraries is to retain the `static` flag to keep the resolution timing consistent.
- *Libraries on version 9 with applications running version 8: *
The schematic won't run on libraries. As long as libraries retain their `static` flags from version 8, they should work with apps on 8.
The schematic won't run on libraries.
As long as libraries retain their `static` flags from version 8, they should work with apps on 8.
- *Libraries on version 8 with applications running version 9: *
Libraries will have explicit flags defined. The behavior
with explicit flags has not changed.
Libraries will have explicit flags defined.
The behavior with explicit flags has not changed.
### What about applications using non-migrated libraries?
Because this is a code cleanup that is a noop,
non-migrated libraries will work the same either way.
Because this is a code cleanup that is a noop, non-migrated libraries will work the same either way.

View File

@ -6,7 +6,7 @@
application but are not decorated.
2. The schematic updates providers which follow the `{provide: SomeToken}` pattern
to explicitly specify `useValue: undefined`.
**Example for missing `@Injectable()`**
_Before migration:_
@ -29,6 +29,7 @@ export class MyFifthClass {...}
]
})
```
_After migration:_
```ts
@Injectable()
@ -47,8 +48,8 @@ with `@Injectable()` because they are never instantiated, but just used as a [DI
**Example for provider needing `useValue: undefined`**
This example shows a provider following the `{provide: X}` pattern. The provider needs to be
migrated to a more explicit definition where `useValue: undefined` is specified.
This example shows a provider following the `{provide: X}` pattern.
The provider needs to be migrated to a more explicit definition where `useValue: undefined` is specified.
_Before migration_:
```typescript
@ -61,16 +62,12 @@ _After migration_:
### Why is adding `@Injectable()` necessary?
In our docs, we've always recommended adding `@Injectable()`
decorators to any class that is provided or injected in your application.
However, older versions of Angular did allow injection of a class
without the decorator in certain cases, such as AOT mode.
This means if you accidentally omitted the decorator, your application
may have continued to work despite missing `@Injectable()` decorators in some places.
This is problematic for future versions of Angular. Eventually, we plan
to strictly require the decorator because doing so enables further
optimization of both the compiler and the runtime. This schematic
adds any `@Injectable()` decorators that may be missing to future-proof your app.
In our docs, we've always recommended adding `@Injectable()` decorators to any class that is provided or injected in your application.
However, older versions of Angular did allow injection of a class without the decorator in certain cases, such as AOT mode.
This means if you accidentally omitted the decorator, your application may have continued to work despite missing `@Injectable()` decorators in some places.
This is problematic for future versions of Angular.
Eventually, we plan to strictly require the decorator because doing so enables further optimization of both the compiler and the runtime.
This schematic adds any `@Injectable()` decorators that may be missing to future-proof your app.
### Why is adding `useValue: undefined` necessary?
@ -83,28 +80,26 @@ Consider the following pattern:
```
Providers using this pattern will behave as if they provide `MyService` as [DI token][DI_TOKEN]
with the value of `undefined`. This is not the case in Ivy where such providers will be interpreted
as if `useClass: MyService` is specified. This means that these providers will behave differently
when updating to version 9 and above. To ensure that the provider behaves the same as before, the
DI value should be explicitly set to `undefined`.
with the value of `undefined`.
This is not the case in Ivy where such providers will be interpreted as if `useClass: MyService` is specified.
This means that these providers will behave differently when updating to version 9 and above.
To ensure that the provider behaves the same as before, the DI value should be explicitly set to `undefined`.
### When should I be adding `@Injectable()` decorators to classes?
Any class that is provided must have an `@Injectable()` decorator. The decorator is necessary
for the framework to properly create an instance of that class through DI.
Any class that is provided must have an `@Injectable()` decorator.
The decorator is necessary for the framework to properly create an instance of that class through DI.
However, classes which are already decorated with `@Pipe`, `@Component` or `@Directive` do not
need both decorators. The existing class decorator already instructs the compiler to generate the
However, classes which are already decorated with `@Pipe`, `@Component` or `@Directive` do not need both decorators.
The existing class decorator already instructs the compiler to generate the
needed information.
### Should I update my library?
Yes, if your library has any classes that are meant to be injected, they should be updated with
the `@Injectable()` decorator. In a future version of Angular, a missing `@Injectable()` decorator
will always throw an error.
Yes, if your library has any classes that are meant to be injected, they should be updated with the `@Injectable()` decorator.
In a future version of Angular, a missing `@Injectable()` decorator will always throw an error.
Additionally, providers in your library that follow the described `{provide: X}` pattern should be
updated to specify an explicit value. Without explicit value, these providers can behave
differently based on the Angular version in applications consuming your library.
Additionally, providers in your library that follow the described `{provide: X}` pattern should be updated to specify an explicit value.
Without explicit value, these providers can behave differently based on the Angular version in applications consuming your library.
[DI_TOKEN]: guide/glossary#di-token
[DI_TOKEN]: guide/glossary#di-token

View File

@ -29,7 +29,8 @@ The symbol is loaded by importing the `@angular/localize/init` module, which has
## Why is this migration necessary?
Prior to Angular version 9, Angular's internationalization (i18n) system inlined translated messages into the compiled output as part of this template compilation. This approach required running the template compiler once per target locale, often leading to slow production build times.
Prior to Angular version 9, Angular's internationalization (i18n) system inlined translated messages into the compiled output as part of this template compilation.
This approach required running the template compiler once per target locale, often leading to slow production build times.
In the new i18n system, the Angular compiler tags i18n messages in the compiled code with a global `$localize` handler.
The inlining of translations then occurs as a post-compilation step for each locale.
@ -55,7 +56,8 @@ if your app uses Angular's i18n APIs.
## Why is my tslint failing?
The import of `@angular/localize/init` may cause a tslint error for `no-import-side-effect` because it adds to the global context (that is, a side effect). To fix this error, add the following to your `tslint.config`:
The import of `@angular/localize/init` may cause a tslint error for `no-import-side-effect` because it adds to the global context (that is, a side effect).
To fix this error, add the following to your `tslint.config`:
```json

View File

@ -2,19 +2,24 @@
## Migration Overview
The `Renderer` class has been marked as deprecated since Angular version 4. This section provides guidance on migrating from this deprecated API to the newer `Renderer2` API and what it means for your app.
The `Renderer` class has been marked as deprecated since Angular version 4.
This section provides guidance on migrating from this deprecated API to the newer `Renderer2` API and what it means for your app.
## Why should I migrate to Renderer2?
The deprecated `Renderer` class has been removed in version 9 of Angular, so it's necessary to migrate to a supported API. Using `Renderer2` is the recommended strategy because it supports a similar set of functionality to `Renderer`. The API surface is quite large (with 19 methods), but the schematic should simplify this process for your applications.
The deprecated `Renderer` class has been removed in version 9 of Angular, so it's necessary to migrate to a supported API.
Using `Renderer2` is the recommended strategy because it supports a similar set of functionality to `Renderer`.
The API surface is quite large (with 19 methods), but the schematic should simplify this process for your applications.
## Is there action required on my end?
No. The schematic should handle most cases with the exception of `Renderer.animate()` and `Renderer.setDebugInfo()`, which already arent supported.
No.
The schematic should handle most cases with the exception of `Renderer.animate()` and `Renderer.setDebugInfo()`, which already aren't supported.
## What are the `__ngRendererX` methods? Why are they necessary?
Some methods either don't have exact equivalents in `Renderer2`, or they correspond to more than one expression. For example, both renderers have a `createElement()` method, but they're not equal because a call such as `renderer.createElement(parentNode, namespaceAndName)` in the `Renderer` corresponds to the following block of code in `Renderer2`:
Some methods either don't have exact equivalents in `Renderer2`, or they correspond to more than one expression.
For example, both renderers have a `createElement()` method, but they're not equal because a call such as `renderer.createElement(parentNode, namespaceAndName)` in the `Renderer` corresponds to the following block of code in `Renderer2`:
```ts
const [namespace, name] = splitNamespace(namespaceAndName);
@ -25,7 +30,10 @@ if (parentNode) {
return el;
```
Migration has to guarantee that the return values of functions and types of variables stay the same. To handle the majority of cases safely, the schematic declares helper functions at the bottom of the user's file. These helpers encapsulate your own logic and keep the replacements inside your code down to a single function call. Here's an example of how the `createElement()` migration looks:
Migration has to guarantee that the return values of functions and types of variables stay the same.
To handle the majority of cases safely, the schematic declares helper functions at the bottom of the user's file.
These helpers encapsulate your own logic and keep the replacements inside your code down to a single function call.
Here's an example of how the `createElement()` migration looks:
**Before:**

View File

@ -103,52 +103,35 @@ class Dir extends Base {
### Migrating classes that use DI
When a class has a `@Directive()` or `@Component()` decorator,
the Angular compiler generates extra code to inject dependencies into
the constructor. When using inheritance, Ivy needs both the parent class
and the child class to apply a decorator to generate the correct code.
When a class has a `@Directive()` or `@Component()` decorator, the Angular compiler generates extra code to inject dependencies into the constructor.
When using inheritance, Ivy needs both the parent class and the child class to apply a decorator to generate the correct code.
You can think of this change as two cases: a parent class is missing a
decorator or a child class is missing a decorator. In both scenarios,
Angular's runtime needs additional information from the compiler.
decorator or a child class is missing a decorator.
In both scenarios, Angular's runtime needs additional information from the compiler.
This additional information comes from adding decorators.
#### Decorator missing from parent class
When the decorator is missing from the parent class,
the subclass will inherit a constructor from a class for
which the compiler did not generate special constructor
info (because it was not decorated as a directive).
When Angular then tries to create the subclass,
it doesn't have the correct info
to create it.
When the decorator is missing from the parent class, the subclass will inherit a constructor from a class for which the compiler did not generate special constructor info (because it was not decorated as a directive).
When Angular then tries to create the subclass, it doesn't have the correct info to create it.
In View Engine, the compiler has global knowledge, so it
can look up the missing data. However, the Ivy compiler
only processes each directive in isolation. This means that
compilation can be faster, but the compiler can't
automatically infer the same
information as before. Adding the `@Directive()` explicitly
provides this information.
In View Engine, the compiler has global knowledge, so it can look up the missing data.
However, the Ivy compiler only processes each directive in isolation.
This means that compilation can be faster, but the compiler can't automatically infer the same information as before.
Adding the `@Directive()` explicitly provides this information.
In the future, add `@Directive()` to base classes that
do not already have decorators and are extended by directives.
In the future, add `@Directive()` to base classes that do not already have decorators and are extended by directives.
#### Decorator missing from child class
When the child class is missing the decorator, the
child class inherits from the
parent class yet has no decorators of its own.
Without a decorator, the compiler has no way of knowing
that the class is a `@Directive` or `@Component`, so
it doesn't generate the proper instructions for the directive.
When the child class is missing the decorator, the child class inherits from the parent class yet has no decorators of its own.
Without a decorator, the compiler has no way of knowing that the class is a `@Directive` or `@Component`, so it doesn't generate the proper instructions for the directive.
### Migrating classes that use field decorators
In ViewEngine, base classes with field decorators like `@Input()` worked
even when the class did not have a `@Directive()` or `@Component()` decorator.
In ViewEngine, base classes with field decorators like `@Input()` worked even when the class did not have a `@Directive()` or `@Component()` decorator.
For example:
```ts
@ -165,52 +148,41 @@ class Dir extends Base {
}
```
However, this example won't compile with Ivy because the `Base` class
_requires_ either a `@Directive()` or `@Component()` decorator to generate
code for inputs, outputs, queries, and host bindings.
However, this example won't compile with Ivy because the `Base` class _requires_ either a `@Directive()` or `@Component()` decorator to generate code for inputs, outputs, queries, and host bindings.
Always requiring a class decorator leads to two main benefits for Angular:
1. The previous behavior was inconsistent. Some Angular features required a decorator (dependency injection), but others did not. Now, all Angular features consistently require a class decorator.
1. The previous behavior was inconsistent.
Some Angular features required a decorator (dependency injection), but others did not.
Now, all Angular features consistently require a class decorator.
1. Supporting undecorated classes increases the code size and complexity of Angular. Always requiring class decorators allows the framework to become smaller and simpler for all users.
1. Supporting undecorated classes increases the code size and complexity of Angular.
Always requiring class decorators allows the framework to become smaller and simpler for all users.
## What does it mean to have a `@Directive()` decorator with no metadata inside of it?
The presence of the `@Directive` decorator causes Angular to generate
extra code for the affected class. If that decorator includes no
properties (metadata),
the directive won't be matched to elements or instantiated
directly, but other classes that _extend_ the
directive class will inherit this generated code. You can think of
this as an "abstract" directive.
The presence of the `@Directive` decorator causes Angular to generate extra code for the affected class.
If that decorator includes no properties (metadata), the directive won't be matched to elements or instantiated directly, but other classes that _extend_ the directive class will inherit this generated code.
You can think of this as an "abstract" directive.
Adding an abstract directive to an `NgModule` will cause an error.
A directive must have a `selector` property defined in order to match some element in a template.
## When do I need a `@Directive()` decorator without a selector?
If you're using dependency injection, or any Angular-specific
feature, such as `@HostBinding()`, `@ViewChild()`, or `@Input()`, you need a
`@Directive()` or `@Component()` decorator.
The decorator lets the compiler know to generate the correct
instructions to create that class and any classes that extend it.
If you don't want to use that base class as a directive directly, leave
the selector blank. If you do want it to be usable independently,
fill in the metadata as usual.
If you're using dependency injection, or any Angular-specific feature, such as `@HostBinding()`, `@ViewChild()`, or `@Input()`, you need a `@Directive()` or `@Component()` decorator.
The decorator lets the compiler know to generate the correct instructions to create that class and any classes that extend it.
If you don't want to use that base class as a directive directly, leave the selector blank.
If you do want it to be usable independently, fill in the metadata as usual.
Classes that don't use Angular features don't need an Angular decorator.
## I'm a library author. Should I add the `@Directive()` decorator to base classes?
As support for selectorless decorators is introduced in
Angular version 9, if you want to support Angular version 8 and earlier, you
shouldn't add a selectorless `@Directive()` decorator.
You can either add `@Directive()` with a selector or
move the Angular-specific features to affected subclasses.
As support for selectorless decorators is introduced in Angular version 9, if you want to support Angular version 8 and earlier, you shouldn't add a selectorless `@Directive()` decorator.
You can either add `@Directive()` with a selector or move the Angular-specific features to affected subclasses.
## What about applications using non-migrated libraries?
`ngcc` should transform any non-migrated libraries to generate the proper code.