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
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
Computing the value of loadChildren does not work externally, as the CLI
needs to be able to detect the paths referenced to properly set up
codesplitting. However, internally, different approaches to codesplitting
require hashed module IDs, and the computation of those hashes involves
something like:
{path: '...', loadChildren: hashFn('module')}
ngc should lower loadChildren into an exported constant in that case.
This will never break externally, because loadChildren is always a
string externally, and a string won't get lowered.
PR Close#23088
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
Closure has a transformation which turns:
Service.ngInjectableDef = ...;
into:
Service$ngInjectableDef = ...;
This transformation obviously breaks Ivy in a major way. The solution is
to annotate the fields as @nocollapse. However, Typescript appears to ignore
synthetic comments added to a node during a transformation, so the "right"
way to add these comments doesn't work.
As an interim measure, a post-processing step just before the compiled JS is
written to disk appends the correct comments with a regular expression.
PR Close#22691
When the compiler generates a reference to an exported variable in the
same file, it inserts a synthetic ts.Identifier node. In CommonJS
output, this synthetic node would not be properly rewritten with an
`exports.` prefix.
This change sets the TS original node property on the synthetic node
we generate, which ensures TS knows to rewrite it in CommonJS output.
PR Close#22564
When angularCompilerOptions { enableResourceInlining: true }, we replace all templateUrl and styleUrls properties in @Component with template/styles
PR Close#22615
InjectionToken can be created with an ngInjectableDef, and previously
this allowed the full expressiveness of @Injectable. However, this
requires a runtime reflection system in order to generate factories
from expressed provider declarations.
Instead, this change requires scoped InjectionTokens to provide the
factory directly (likely using inject() for the arguments), bypassing
the need for a reflection system.
Fixes#22205
PR Close#22207
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
Folding errors passed calls prevented the static reflector from
begin able to ignore errors in annotations it doesn't know as
the call to the unknown annotation was elided from the metadata.
Fixes: #21273
PR Close#21708
The "enableIvy" compiler option is the initial implementation
of the Render3 (or Ivy) code generation. This commit enables
generation generating "Hello, World" (example in the test)
but not much else. It is currenly only useful for internal Ivy
testing as Ivy is in development.
PR Close#21427
The compiler host would force any file that is in node_modules
into the list of files that needed to be type checked which
captures .js files if `allowJs` is set to `true`. This should
have only forced .d.ts files into the project to enable
generation of factories.
Fixes: #19757
Previously, this code would unconditionally add a @fileoverview
comment to generated files, and only if the contained any code at all.
However often existing fileoverview comments should be copied from the
file the generated file was originally based off of. This allows users
to e.g. include Closure Compiler directives in their original
`component.ts` file, which will then automaticallly also apply to code
generated from it.
This special cases `@license` comments, as Closure disregards directives
in comments containing `@license`.
PR Close#20870
The errors produced when error were encountered while interpreting the
content of a directive was often incomprehencible. With this change
these kind of error messages should be easier to understand and diagnose.
PR Close#20459
This also changes the compiler so that we throw less often
on structural changes and produce a meaningful state
in the `ng.Program` in case of errors.
Related to #19951
PR Close#19953
The error collector changes behavior of the metadata resolver
in ways that haven't been fully hardened. This changes limits
its use to the lazy route detection and the language service.
Issue: #19906
PR Close#19912
This fixes a problem introduced in 8d45fefc31
which modified how diagnostic error messages are reported for structural
metadata errors causing some of the diagnostics to be lost.
PR Close#19886
References to resources (such as .css files) that are generated into
the `outDir` directory outside of `rootDir` would cause a spurious
compiler error about not being able to find a files that ends in
'.ngstyle.ts'.
Also fixed a minor issue in compiler error reporting
Fixes: #19765, #19767
PR Close#19770
This is important to not confuse users nor downstream tools that
consume our source maps. For generated content for which we don’t
have an original source file, we use the generated file now.
Fixes#19538
Closure no longer needs to have the imports rewritten avoid rewriting
as this can cause issues when the source directory structure differs
from what is deployed.
Fixes: #19026
introduce the option `allowEmptyCodegenFiles` to generate all generated files,
even if they are empty.
- also provides the original source files from which the file was generated
in the write file callback
- needed e.g. for G3 when copying over pinto mod names from the original component
to all generated files
use `importAs` from flat modules when writing summaries
- i.e. prevents incorrect entries like @angular/common/common in the .ngsummary.json files.
change interaction between ng and ts to prevent race conditions
- before Angular would rely on TS to first read the file for which we generate files,
and then the generated files. However, this can break easily when we reuse an old program.
don’t generate files for sources that are outside of `rootDir`
(see #19337)
We now create 2 programs with exactly the same fileNames and
exactly the same `import` / `export` declarations,
allowing TS to reuse the structure of first program
completely. When passing in an oldProgram and the files didn’t change,
TS can also reuse the old program completely.
This is possible buy adding generated files to TS
in `host.geSourceFile` via `ts.SourceFile.referencedFiles`.
This commit also:
- has a minor side effect on how we generate shared stylesheets:
- previously every import in a stylesheet would generate a new
`.ngstyles.ts` file.
- now, we only generate 1 `.ngstyles.ts` file per entry in `@Component.styleUrls`.
This was required as we need to be able to determine the program files
without loading the resources (which can be async).
- makes all angular related methods in `CompilerHost`
optional, allowing to just use a regular `ts.CompilerHost` as `CompilerHost`.
- simplifies the logic around `Compiler.analyzeNgModules` by introducing `NgAnalyzedFile`.
Perf impact: 1.5s improvement in compiling angular io
PR Close#19275
- temporarily keeps the old sources under packages/tsc-wrapped
until the build scripts are changed to use compiler-cli everywhere.
- removes the compiler options `disableTransformerPipeline` that was introduced
in a previous beta of Angular 5, i.e. the transformer based compiler
is now always enabled.
PR Close#18966
With this commit the compiler will "lower" expressions into exported
variables for values the compiler does not need to know statically
in order to be able to generate a factory. For example:
```
providers: [{provider: 'token', useValue: calculated()}]
```
produced an error as the expression `calculated()` is not supported
by the compiler because `calculated` is not a
[known function](https://angular.io/guide/metadata#annotationsdecorators)
With this commit this is rewritten, during emit of the .js file, into
something like:
```
export var ɵ0 = calculated();
...
provdiers: [{provider: 'token', useValue: ɵ0}]
```
The compiler then will now generate a reference to the exported `ɵ0`
instead of failing to evaluate `calculated()`.
PR Close#18905