Previously, ngOnDestroy was only called on services which were statically
determined to have ngOnDestroy methods. In some cases, such as with services
instantiated via factory functions, it's not statically known that the service
has an ngOnDestroy method.
This commit changes the runtime to look for ngOnDestroy when instantiating
all DI tokens, and to call the method if it's present.
Fixes#22466Fixes#22240Fixes#14818
PR Close#23755
Ivy definition looks something like this:
```
class MyService {
static ngInjectableDef = defineInjectable({
…
});
}
```
Here the argument to `defineInjectable` is well known public contract which needs
to be honored in backward compatible way between versions. The type of the
return value of `defineInjectable` on the other hand is private and can change
shape drastically between versions without effecting backwards compatibility of
libraries publish to NPM. To our users it is effectively an `OpaqueToken`.
By prefixing the type with `ɵ` we are communicating the the outside world that
the value is not public API and is subject to change without backward compatibility.
PR Close#23371
- Remove default injection value from `inject` / `directiveInject` since
it is not possible to set using annotations.
- Module `Injector` is stored on `LView` instead of `LInjector` data
structure because it can change only at `LView` level. (More efficient)
- Add `ngInjectableDef` to `IterableDiffers` so that existing tests can
pass as well as enable `IterableDiffers` to be injectable without
`Injector`
PR Close#23345
Currently the context for inject() is only set when the token is seen
for the first time. This has two issues:
* It should always be set when injecting from that injector, because
a constructor may wish to call inject() directly.
* If an NgModuleFactory is .create()'d twice, and an ngInjectableDef
token is requested from each of them, the second time will fail.
This is because the first injection adds the provider definition
and calls the factory, and the provider definitions are shared.
The second injector will see the provider definition and call the
factory to create an instance, but without setting the correct
context for inject().
Fixes angular/material2#10586.
PR Close#23148
This adds compilation of @NgModule providers and imports into
ngInjectorDef statements in generated code. All @NgModule annotations
will be compiled and the @NgModule decorators removed from the
resultant js output.
All @Injectables will also be compiled in Ivy mode, and the decorator
removed.
PR Close#22458
Rename @Injectable({scope -> providedIn}).
Instead of {providedIn: APP_ROOT_SCOPE}, accept {providedIn: 'root'}.
Also, {providedIn: null} implies the injectable should not be added
to any scope.
PR Close#22655
@Injectable() supports a scope parameter which specifies the target module.
However, it's still difficult to specify that a particular service belongs
in the root injector. A developer attempting to ensure that must either
also provide a module intended for placement in the root injector or target
a module known to already be in the root injector (e.g. BrowserModule).
Both of these strategies are cumbersome and brittle.
Instead, this commit adds a token APP_ROOT_SCOPE which provides a
straightforward way of targeting the root injector directly, without
requiring special knowledge of modules within it.
PR Close#22185
This commit bundles 3 important changes, with the goal of enabling tree-shaking
of services which are never injected. Ordinarily, this tree-shaking is prevented
by the existence of a hard dependency on the service by the module in which it
is declared.
Firstly, @Injectable() is modified to accept a 'scope' parameter, which points
to an @NgModule(). This reverses the dependency edge, permitting the module to
not depend on the service which it "provides".
Secondly, the runtime is modified to understand the new relationship created
above. When a module receives a request to inject a token, and cannot find that
token in its list of providers, it will then look at the token for a special
ngInjectableDef field which indicates which module the token is scoped to. If
that module happens to be in the injector, it will behave as if the token
itself was in the injector to begin with.
Thirdly, the compiler is modified to read the @Injectable() metadata and to
generate the special ngInjectableDef field as part of TS compilation, using the
PartialModules system.
Additionally, this commit adds several unit and integration tests of various
flavors to test this change.
PR Close#22005
Adding the binding name to the error message recieved by the user gives
extra context on what exactly changed. The tests are also updated to
reflect the new error message.
PR Close#20352
`main()` function used to be needed to support dart, since dart
Does not allow top level statements. Since we no longer use dart
The need for `main()` has been removed.
In preparation for `Basel` and standardized way of running tests
we are removing `main()`
PR Close#21053
Each node now has two index: nodeIndex and checkIndex.
nodeIndex is the index in both the view definition and the view data.
checkIndex is the index in in the update function (update directives and update
renderer).
While nodeIndex and checkIndex have the same value for now, having both of them
will allow changing the structure of view definition after compilation (ie for
runtime translations).
This change allows ReflectiveInjector to be tree shaken resulting
in not needed Reflect polyfil and smaller bundles.
Code savings for HelloWorld using Closure:
Reflective: bundle.js: 105,864(34,190 gzip)
Static: bundle.js: 154,889(33,555 gzip)
645( 2%)
BREAKING CHANGE:
`platformXXXX()` no longer accepts providers which depend on reflection.
Specifically the method signature when from `Provider[]` to
`StaticProvider[]`.
Example:
Before:
```
[
MyClass,
{provide: ClassA, useClass: SubClassA}
]
```
After:
```
[
{provide: MyClass, deps: [Dep1,...]},
{provide: ClassA, useClass: SubClassA, deps: [Dep1,...]}
]
```
NOTE: This only applies to platform creation and providers for the JIT
compiler. It does not apply to `@Compotent` or `@NgModule` provides
declarations.
Benchpress note: Previously Benchpress also supported reflective
provides, which now require static providers.
DEPRECATION:
- `ReflectiveInjector` is now deprecated as it will be remove. Use
`Injector.create` as a replacement.
closes#18496
Angular can make many assumptions about its event handlers. As a result
the bookkeeping for native addEventListener is significantly cheaper
than Zone's addEventLister which can't make such assumptions.
This change bypasses the Zone's addEventListener if present and always
uses the native addEventHandler. As a result registering event listeners
is about 3 times faster.
PR Close#18107
- prevents unsubscribing from the zone on error
- prevents unsubscribing from directive `EventEmitter`s on error
- prevents detaching views in dev mode if there on error
- ensures that `ngOnInit` is only called 1x (also in prod mode)
Fixes#9531Fixes#2413Fixes#15925
This change reduces the amount of generated code by only adding `log`
calls for elements and text nodes.
We need the `log` calls to allow users to jump to the right place
in the template via source maps. However, we only need it for element
and text nodes, but not for directives, queries, … as for them we
first locate the corresponding element or text node.
Related to #15239
PR Close#15350
Throwing on query changes would be a breaking change compared to v2.
Also discovers a bug with querying manually projected content, see #15117.
Related to #14748Closes#14925
fixes#12869fixes#12889fixes#13885fixes#13870
Before this change there was a single injector tree.
Now we have 2 injector trees, one for the modules and one for the components.
This fixes lazy loading modules.
See the design docs for details:
https://docs.google.com/document/d/1OEUIwc-s69l1o97K0wBd_-Lth5BBxir1KuCRWklTlI4
BREAKING CHANGES
`ComponentFactory.create()` takes an extra optional `NgModuleRef` parameter.
No change should be required in user code as the correct module will be used
when none is provided
DEPRECATIONS
The following methods were used internally and are no more required:
- `RouterOutlet.locationFactoryResolver`
- `RouterOutlet.locationInjector`
The main use case for the generated source maps is to give
errors a meaningful context in terms of the original source
that the user wrote.
Related changes that are included in this commit:
* renamed virtual folders used for jit:
* ng://<module type>/module.ngfactory.js
* ng://<module type>/<comp type>.ngfactory.js
* ng://<module type>/<comp type>.html (for inline templates)
* error logging:
* all errors that happen in templates are logged
from the place of the nearest element.
* instead of logging error messages and stacks separately,
we log the actual error. This is needed so that browsers apply
source maps to the stack correctly.
* error type and error is logged as one log entry.
Note that long-stack-trace zone has a bug that
disables source maps for stack traces,
see https://github.com/angular/zone.js/issues/661.
BREAKING CHANGE:
- DebugNode.source no more returns the source location of a node.
Closes 14013