Within an @NgModule it's common to include in the imports a call to
a ModuleWithProviders function, for example RouterModule.forRoot().
The old ngc compiler was able to handle this pattern because it had
global knowledge of metadata of not only the input compilation unit
but also all dependencies.
The ngtsc compiler for Ivy doesn't have this knowledge, so the
pattern of ModuleWithProviders functions is more difficult. ngtsc
must be able to determine which module is imported via the function
in order to expand the selector scope and properly tree-shake
directives and pipes.
This commit implements a solution to this problem, by adding a type
parameter to ModuleWithProviders through which the actual module
type can be passed between compilation units.
The provider side isn't a problem because the imports are always
copied directly to the ngInjectorDef.
PR Close#24862
Metadata in Ivy must be literal. For example,
@NgModule({...})
is legal, whereas
const meta = {...};
@NgModule(meta)
is not.
However, some code contains additional superfluous parentheses:
@NgModule(({...}))
It is desirable that ngtsc accept this form of literal object.
PR Close#24862
for non-inline templates
- Non-inline templates used to ouput the path to the component TS file
instead of the path to the original HTML file.
- Inline templates keep the same behavior.
Fixes#24884
PR Close#24885
It's possible to declare an argument-less NgModule:
@NgModule() export class Foo {}
Update the @NgModule compiler to support this usage.
PR Close#24738
On accident a few of the definition types were emitted as public API
symbols. Much of the Ivy API surface is still prefixed with ɵ,
indicating it's a private API. The definition types should be private
for now.
PR Close#24738
This commit changes the @NgModule provider to understand that sometimes
an import will resolve to an object instead of a type, and that object
could be of the ModuleWithProviders type. In that case, the 'ngModule'
property is read, and its value used instead.
This still will not handle ModuleWithProviders references across
compilation units; that work is coming in a future PR.
PR Close#24738
The current module resolution simply attaches .ts to the import/export path, which does
not work if the path is using Node / CommonJS behavior to resolve to an index.ts file.
This patch uses typescript's module resolution logic, and will attempt to load the original
typescript file if this resolution returns a .js or .d.ts file
PR Close#22856
With these changes, the types are a little stricter now and also not
compatible with Protractor's jasmine-like syntax. So, we have to also
use `@types/jasminewd2` for e2e tests (but not for non-e2e tests).
I also had to "augment" `@types/jasminewd2`, because the latest
typings from [DefinitelyTyped][1] do not reflect the fact that the
`jasminewd2` version (v2.1.0) currently used by Protractor supports
passing a `done` callback to a spec.
[1]: 566e039485/types/jasminewd2/index.d.ts (L9-L15)Fixes#23952Closes#24733
PR Close#19904
This commit adds support for templateUrl in component templates within
ngtsc. The compilation pipeline is split into sync and async versions,
where asynchronous compilation invokes a special preanalyze() phase of
analysis. The preanalyze() phase can optionally return a Promise which
will delay compilation until it resolves.
A ResourceLoader interface is used to resolve templateUrls to template
strings and can return results either synchronously or asynchronously.
During sync compilation it is an error if the ResourceLoader returns a
Promise.
Two ResourceLoader implementations are provided. One uses 'fs' to read
resources directly from disk and is chosen if the CompilerHost doesn't
provide a readResource method. The other wraps the readResource method
from CompilerHost if it's provided.
PR Close#24704
- Adds InheritanceDefinitionFeature to ivy
- Ensures that lifecycle hooks are inherited from super classes whether they are defined as directives or not
- Directives cannot inherit from Components
- Components can inherit from Directives or Components
- Ensures that Inputs, Outputs, and Host Bindings are inherited
- Ensures that super class Features are run
PR Close#24570
Currently ngtsc does not compile @Pipe. This has a side effect
of not removing the @Pipe decorator.
This adds a dummy DecoratorHandler that compiles @Pipe into an
empty ngPipeDef. Eventually this will be replaced with a full
implementation, but for now this solution allows compield code
to be tree-shaken properly.
PR Close#24677
Previously ngtsc removed the class-level decorators (@Component,
etc) but left all the ancillary decorators (@Input, @Optional,
etc).
This changes the transform to descend into the members of decorated
classes and remove any Angular decorators, not just the class-level
ones.
PR Close#24677
@angular/core is unique in that it defines the Angular decorators
(@Component, @Directive, etc). Ordinarily ngtsc looks for imports
from @angular/core in order to identify these decorators. Clearly
within core itself, this strategy doesn't work.
Instead, a special constant ITS_JUST_ANGULAR is declared within a
known file in @angular/core. If ngtsc sees this constant it knows
core is being compiled and can ignore the imports when evaluating
decorators.
Additionally, when compiling decorators ngtsc will often write an
import to @angular/core for needed symbols. However @angular/core
cannot import itself. This change creates a module within core to
export all the symbols needed to compile it and adds intelligence
within ngtsc to write relative imports to that module, instead of
absolute imports to @angular/core.
PR Close#24677
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
All errors for existing fields have been detected and suppressed with a
`!` assertion.
Issue/24571 is tracking proper clean up of those instances.
One-line change required in ivy/compilation.ts, because it appears that
the new syntax causes tsickle emitted node to no longer track their
original sourceFiles.
PR Close#24572
ngtsc needs to reflect over code to property compile it. It performs operations
such as enumerating decorators on a type, reading metadata from constructor
parameters, etc.
Depending on the format (ES5, ES6, etc) of the underlying code, the AST
structures over which this reflection takes place can be very different. For
example, in TS/ES6 code `class` declarations are `ts.ClassDeclaration` nodes,
but in ES5 code they've been downleveled to `ts.VariableDeclaration` nodes that
are initialized to IIFEs that build up the classes being defined.
The ReflectionHost abstraction allows ngtsc to perform these operations without
directly querying the AST. Different implementations of ReflectionHost allow
support for different code formats.
PR Close#24541
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
Two new CircleCI environments are created: test_ivy_jit and test_ivy_aot.
Both run a subset of the tests that have been marked with Bazel tags as
being appropriate for that environment.
Once all the tests pass, builds are published to the *-builds repo both
for the legacy View Engine compiled code as well as for ivy-jit and ivy-aot.
PR Close#24309
This adds ngtsc/util/src/visitor, a utility for visiting TS ASTs that
can add synthetic nodes immediately prior to certain types of nodes (e.g.
class declarations). It's useful to lift definitions that need to be
referenced repeatedly in generated code outside of the class that defines
them.
PR Close#24230
Bazel has a restriction that a single output (eg. a compiled version of
//packages/common) can only be produced by a single rule. This precludes
the Angular repo from having multiple rules that build the same code. And
the complexity of having a single rule produce multiple outputs (eg. an
ngc-compiled version of //packages/common and an Ivy-enabled version) is
too high.
Additionally, the Angular repo has lots of existing tests which could be
executed as-is under Ivy. Such testing is very valuable, and it would be
nice to share not only the code, but the dependency graph / build config
as well.
Thus, this change introduces a --define flag 'compile' with three potential
values. When --define=compile=X is set, the entire build system runs in a
particular mode - the behavior of all existing targets is controlled by
the flag. This allows us to reuse our entire build structure for testing
in a variety of different manners. The flag has three possible settings:
* legacy (the default): the traditional View Engine (ngc) build
* local: runs the prototype ngtsc compiler, which does not rely on global
analysis
* jit: runs ngtsc in a mode which executes tsickle, but excludes the
Angular related transforms, which approximates the behavior of plain
tsc. This allows the main packages such as common to be tested with
the JIT compiler.
Additionally, the ivy_ng_module() rule still exists and runs ngc in a mode
where Ivy-compiled output is produced from global analysis information, as
a stopgap while ngtsc is being developed.
PR Close#24056
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
Previously, the compileComponent() and compileDirective() APIs still required
the output of global analysis, even though they only read local information
from that output.
With this refactor, compileComponent() and compileDirective() now define
their inputs explicitly, with the new interfaces R3ComponentMetadata and
R3DirectiveMetadata. compileComponentGlobal() and compileDirectiveGlobal()
are introduced and convert from global analysis output into the new metadata
format.
This refactor also splits out the view compiler into separate files as
r3_view_compiler_local.ts was getting unwieldy.
Finally, this refactor also splits out generation of DI factory functions
into a separate r3_factory utility as the logic is utilized between different
compilers.
PR Close#23545
g3 and the Angular repo have different versions of TypeScript, and
ts.updateIdentifier() has a different signature in the different versions.
There is no way to write a call to the function that will compile in both
versions simultaneously.
Instead, use ts.getMutableClone() as that has the same effect of cloning
the identifier.
PR Close#23550
This commit adds a new compiler pipeline that isn't dependent on global
analysis, referred to as 'ngtsc'. This new compiler is accessed by
running ngc with "enableIvy" set to "ngtsc". It reuses the same initialization
logic but creates a new implementation of Program which does not perform the
global-level analysis that AngularCompilerProgram does. It will be the
foundation for the production Ivy compiler.
PR Close#23455
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
This change changes:
- compiler uses `directiveInject` instead of `inject` for `Directive`s
- unifies the flags in `di` as well as `render3`
- changes the signature of `directiveInject` to match `inject` In prep for #23330
- compiler now generates flags for injection.
Compiler portion of #23342
Prep for #23330
PR Close#23345
rxjs 6.0.0 breaks strictMetadataEmit as they now publish a .d.ts file with a
structure like:
declare export class Subscription {
static EMPTY: Subscription;
}
This generates metadata which contains an error, and fails the strictMetadataEmit
validation. There is nothing a library author can do in this situation except to
set strictMetadataEmit to false.
The spirit of strictMetadataEmit is to validate that the author's library doesn't
do anything that will break downstream users. This failure is a corner case which
causes more harm than good, so this commit disables validation for metadata
collected from .d.ts files.
Fixes#22210
PR Close#23275
Lowering expressions in flat module metadata is desirable, but it won't
work without some rearchitecting. Currently the flat module index source
is added to the Program and therefore must be determined before the rest
of the transforms run. Since the lowering transform changes the set of
exports needed in the index, this creates a catch-22 in the index
generation.
This commit causes the flat module index metadata to be generated using
only those transforms which are "safe" (don't modify the index).
PR Close#23226
Currently, the flat module index metadata is produced directly from
the source metadata. The compiler, however, applies transformations
on the Typescript sources during transpilation, and also equivalent
transformations on the metadata itself. This transformed metadata
doesn't end up in the flat module index.
This changes the compiler to generate the flat module index metadata
from its transformed version instead of directly from source.
PR Close#23129