Previously in Ivy, metadata for directives/components/modules/etc was
carried in .d.ts files inside type information encoded on the
DirectiveDef, ComponentDef, NgModuleDef, etc types of Ivy definition
fields. This works well, but has the side effect of complicating Ivy's
runtime code as these extra generic type parameters had to be specified
as <any> throughout the codebase. *DefInternal types were introduced
previously to mitigate this issue, but that's the wrong way to solve
the problem.
This commit returns *Def types to their original form, with no metadata
attached. Instead, new *DefWithMeta types are introduced that alias the
plain definition types and add extra generic parameters. This way the
only code that needs to deal with the extra metadata parameters is the
compiler code that reads and writes them - the existence of this metadata
is transparent to the runtime, as it should be.
PR Close#26203
The bootstrap property of @NgModule was not previously compiled by
the compiler in AOT or JIT modes (in Ivy). This commit adds support
for bootstrap.
PR Close#25775
This commit creates an API for factory functions which allows them
to be inherited from one another. To do so, it differentiates between
the factory function as a wrapper for a constructor and the factory
function in ngInjectableDefs which is determined by a default
provider.
The new form is:
factory: (t?) => new (t || SomeType)(inject(Dep1), inject(Dep2))
The 't' parameter allows for constructor inheritance. A subclass with
no declared constructor inherits its constructor from the superclass.
With the 't' parameter, a subclass can call the superclass' factory
function and use it to create an instance of the subclass.
For @Injectables with configured providers, the factory function is
of the form:
factory: (t?) => t ? constructorInject(t) : provider();
where constructorInject(t) creates an instance of 't' using the
naturally declared constructor of the type, and where provider()
creates an instance of the base type using the special declared
provider on @Injectable.
PR Close#25392
When ngtsc encounters a reference to a type (for example, a Component
type listed in an NgModule declarations array), it traces the import
of that type and attempts to determine the best way to refer to it.
In the event the type is defined in the same file where a reference
is being generated, the identifier of the type is used. If the type
was imported, ngtsc has a choice. It can use the identifier from the
original import, or it can write a new import to the module where the
type came from.
ngtsc has a bug currently when it elects to rely on the user's import.
When writing a .d.ts file, the user's import may have been elided as
the type was not referred to from the type side of the program. Thus,
in .d.ts files ngtsc must always assume the import may not exist, and
generate a new one.
In .js output the import is guaranteed to still exist, so it's
preferable for ngtsc to continue using the existing import if one is
available.
This commit changes how @angular/compiler writes type definitions, and
allows it to use a different expression to write a type definition than
is used to write the value. This allows ngtsc to specify that types in
type definitions should always be imported. A corresponding change to
the staticallyResolve() Reference system allows the choice of which
type of import to use when generating an Expression from a Reference.
PR Close#25080
Previously ngtsc would use a tuple of class types for listing metadata
in .d.ts files. For example, an @NgModule's declarations might be
represented with the type:
[NgIf, NgForOf, NgClass]
If the module had no declarations, an empty tuple [] would be produced.
This has two problems.
1. If the class type has generic type parameters, TypeScript will
complain that they're not provided.
2. The empty tuple type is not actually legal.
This commit addresses both problems.
1. Class types are now represented using the `typeof` operator, so the
above declarations would be represented as:
[typeof NgIf, typeof NgForOf, typeof NgClass].
Since typeof operates on a value, it doesn't require generic type
arguments.
2. Instead of an empty tuple, `never` is used to indicate no metadata.
PR Close#24862
InjectorDef is parameterized on the type of the injector
configuration class (e.g. the @NgModule decorated type). Previously
this parameter was not included when generating .d.ts files that
contained InjectorDefs.
PR Close#24738
This change generates ngInjectorDef as well as ngModuleDef for @NgModule
annotated types, reflecting the dual nature of @NgModules as both compilation
scopes and as DI configuration containers.
This required implementing ngInjectorDef compilation in @angular/compiler as
well as allowing for multiple generated definitions for a single decorator in
the core of ngtsc.
PR Close#24632
This change supports compilation of components, directives, and modules
within ngtsc. Support is not complete, but is enough to compile and test
//packages/core/test/bundling/todo in full AOT mode. Code size benefits
are not yet achieved as //packages/core itself does not get compiled, and
some decorators (e.g. @Input) are not stripped, leading to unwanted code
being retained by the tree-shaker. This will be improved in future commits.
PR Close#24427
This commit adds a mechanism by which the @angular/core annotations
for @Component, @Injectable, and @NgModule become decorators which,
when executed at runtime, trigger just-in-time compilation of their
associated types. The activation of these decorators is configured
by the ivy_switch mechanism, ensuring that the Ivy JIT engine does
not get included in Angular bundles unless specifically requested.
PR Close#23833
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