Previously, when an entry-point was ignored via an ngcc config, ngcc
would scan sub-directories for sub-entry-points, but would not use the
correct `packagePath`. For example, if `@angular/common` was ignored, it
would look at `@angular/common/http` but incorrectly use
`.../@angular/common/http` as the `packagePath` (instead of
`.../@angular/common`). As a result, it would not retrieve the correct
ngcc config for the actual package.
This commit fixes it by ensuring the correct `packagePath` is used, even
if the primary entry-point corresponding to that path is ignored. In
order to do this, a new return value for `getEntryPointInfo()` is added:
`IGNORED_ENTRY_POINT`. This is used to differentiate between directories
that correspond to no or an incompatible entry-point and those that
correspond to an entry-point that could otherwise be valid but is
explicitly ignored. Consumers of `getEntryPointInfo()` can then use this
info to discard ignored entry-points, but still use the correct
`packagePath` when scanning their sub-directories for secondary
entry-points.
PR Close#37040
Adds @nocollapse to static properties added by ngcc
iff annotateForClosureCompiler is true.
The Closure Compiler will collapse static properties
into the global namespace. Adding this annotation keeps
the properties attached to their respective object, which
allows them to be referenced via a class's constructor.
The annotation is already added by ngtsc and ngc under the
same option, this commit extends the functionality to ngcc.
Closes#36618.
PR Close#36652
It is quite common for the TS compiler to have to add synthetic
types to function signatures, where the developer has not
explicitly provided them. This results in `import(...)` expressions
appearing in typings files. For example in `@ngrx/data` there is a
class with a getter that has an implicit type:
```ts
export declare class EntityCollectionServiceBase<...> {
...
get store() {
return this.dispatcher.store;
}
...
}
```
In the d.ts file for this we get:
```ts
get store(): Store<import("@ngrx/data").EntityCache>;
```
Given that this file is within the `@ngrx/data` package already,
this caused ngcc to believe that there was a circular dependency,
causing it to fail to process the package - and in fact crash!
This commit resolves this problem by ignoring `import()` expressions
when scanning typings programs for dependencies. This ability was
only introduced very recently in a 10.0.0 RC release, and so it has
limited benefit given that up till now ngcc has been able to process
libraries effectively without it. Moreover, in the rare case that a
package does have such a dependency, it should get picked up
by the sync ngcc+CLI integration point.
PR Close#37503
Now in TS 3.9, classes in ES2015 can be wrapped in an IIFE.
This commit ensures that we still find the static properties that contain
decorator information, even if they are attached to the adjacent node
of the class, rather than the implementation or declaration.
Fixes#37330
PR Close#37436
This finder is designed to only process entry-points that are reachable
by the program defined by a tsconfig.json file.
It is triggered by calling `mainNgcc()` with the `findEntryPointsFromTsConfigProgram`
option set to true. It is ignored if a `targetEntryPointPath` has been
provided as well.
It is triggered from the command line by adding the `--use-program-dependencies`
option, which is also ignored if the `--target` option has been provided.
Using this option can speed up processing in cases where there is a large
number of dependencies installed but only a small proportion of the
entry-points are actually imported into the application.
PR Close#37075
Previously we only checked for static import declaration statements.
This commit also finds import paths from dynamic import expressions.
Also this commit should speed up processing: Previously we were parsing
the source code contents into a `ts.SourceFile` and then walking the parsed
AST to find import paths.
Generating an AST is unnecessary work and it is faster and creates less
memory pressure to just scan the source code contents with the TypeScript
scanner, identifying import paths from the tokens.
PR Close#37075
Previously this host was skipping files if they had imports that spanned
multiple lines, or if the import was a dynamic import expression.
PR Close#37075
This commit will store a cached copy of the parsed tsconfig
that can be reused if the tsconfig path is the same.
This will improve the ngcc "noop" case, where there is no processing
to do, when the entry-points have already been processed.
Previously we were parsing this config every time we checked for
entry-points to process, which can take up to seconds in some
cases.
Resolves#36882
PR Close#37417
Currently, if an ngcc process is killed in a manner that it doesn't clean
up its lock file (or is killed too quickly) the compiler reports that it
is waiting on the PID of a process that doesn't exist, and that it will
wait up to a maximum of N seconds. This PR updates the locking code to
additionally check if the process exists, and if it does not it will
immediately bail out, and print the location of the lock file so a user
may clean it up.
PR Close#37250
Inline source-maps in typings files can impact IDE performance
so ngcc should only add such maps if the original typings file
contains inline source-maps.
Fixes#37324
PR Close#37363
In #37221 we disabled tsickle passes from transforming the tsc output that is used to publish all
Angular framework and components packages (@angular/*).
This change however revealed a bug in the ngc that caused __decorate and __metadata calls to still
be emitted in the JS code even though we don't depend on them.
Additionally it was these calls that caused code in @angular/material packages to fail at runtime
due to circular dependency in the emitted decorator code documeted as
https://github.com/microsoft/TypeScript/issues/27519.
This change partially rolls back #37221 by reenabling the decorator to static fields (static
properties) downleveling.
This is just a temporary workaround while we are also fixing root cause in `ngc` - tracked as
FW-2199.
Resolves FW-2198.
Related to FW-2196
PR Close#37317
As of TypeScript 3.9, the tsc emit is not compatible with Closure
Compiler due to
https://github.com/microsoft/TypeScript/pull/32011.
There is some hope that this will be fixed by a solution like the one
proposed in
https://github.com/microsoft/TypeScript/issues/38374 but currently it's
unclear if / when that will
happen.
Since the Closure support has been somewhat already broken, and the
tsickle pass has been a source
of headaches for some time for Angular packages, we are removing it for
now while we rethink our
strategy to make Angular Closure compatible outside of Google.
This change has no effect on our Closure compatibility within Google
which work well because all the
code is compiled from sources and passed through tsickle.
This change only disables the tsickle pass but doesn't remove it.
A follow up PR should either remove all the traces of tscikle or
re-enable the fixed version.
BREAKING CHANGE: Angular npm packages no longer contain jsdoc comments
to support Closure Compiler's advanced optimizations
The support for Closure compiler in Angular packages has been
experimental and broken for quite some
time.
As of TS3.9 Closure is unusable with the JavaScript emit. Please follow
https://github.com/microsoft/TypeScript/issues/38374 for more
information and updates.
If you used Closure compiler with Angular in the past, you will likely
be better off consuming
Angular packages built from sources directly rather than consuming the
version we publish on npm
which is primarily optimized for Webpack/Rollup + Terser build pipeline.
As a temporary workaround you might consider using your current build
pipeline with Closure flag
`--compilation_level=SIMPLE`. This flag will ensure that your build
pipeline produces buildable and
runnable artifacts, at the cost of increased payload size due to
advanced optimizations being disabled.
If you were affected by this change, please help us understand your
needs by leaving a comment on https://github.com/angular/angular/issues/37234.
PR Close#37221
In ES2015 IIFE wrapped classes, the identifier that would reference the class
of the NgModule may be an alias variable. Previously the `Esm2015ReflectionHost`
was not able to match this alias to the original class declaration. This resulted
in failing to identify some `ModuleWithProviders` functions in such case.
These IIFE wrapped classes were introduced in TypeScript 3.9, which is why
this issue is only recently appearing. Since 9.1.x does not support TS 3.9
there is no reason to backport this commit to that branch.
Fixes#37189
PR Close#37206
To better check that the code is working, this commit gives a
distinct name (`DecoratedWrappedClass_1`) to the "adjacent"
class declaration in the tests.
PR Close#37206
In TypeScript 3.9 some re-export syntaxes have changed to be getter
functions (created by calls to `Object.defineProperty()`) rather than
simple property accessors.
This commit adds support into the CommonJS and UMD reflection hosts
for this style of re-export syntax.
PR Close#36989
In the CommonJS and UMD reflection hosts, the logic for computing the
`viaModule` property of `Declaration` objects was not correct for some
cases when getting the exports of modules.
In these cases it was setting `viaModule` to the path of the local module
rather than `null`.
PR Close#36989
The term `ReexportStatement` is too general for this particular concept.
Here the re-export actually refers to a wildcard where all the module
exports are being re-exported.
When we introduce other re-export statement types later this will be
confusing.
PR Close#36989
Using backtick multiline strings leads to confusing layout
that does not fit with the surrounding indentation. Also it
can lead to test fragility due to automated code formatting.
This commit changes just one set of subject code to use
a more resilient string concatenation approach.
PR Close#36989
After the refactoring of the reflection hosts to accommodate
ES2015 classes wrapped in IIFEs. The same treatment needs to
be applied to the rendering formatters.
PR Close#36989
In TS 3.9, ES2015 output can contain ES classes that are wrapped in an
IIFE. So now ES2015 class declarations can look like one of:
```
class OuterClass1 {}
```
```
let OuterClass = class InnerClass {};
```
```
var AliasClass;
let OuterClass = AliasClass = class InnerClass {};
```
```
let OuterClass = (() => class InnerClass {}};
```
```
var AliasClass;
let OuterClass = AliasClass = (() => class InnerClass {})();
```
```
let OuterClass = (() => {
let AdjacentClass = class InnerClass {};
// ... static properties or decorators attached to `AdjacentClass`
return AdjacentClass;
})();
```
```
var AliasClass;
let OuterClass = AliasClass = (() => {
let AdjacentClass = class InnerClass {};
// ... static properties or decorators attached to `AdjacentClass`
return AdjacentClass;
})();
```
The `Esm5ReflectionHost` already handles slightly different IIFE wrappers
around function-based classes. This can be substantially reused when
fixing `Esm2015ReflectionHost`, since there is a lot of commonality
between the two.
This commit moves code from the `Esm5ReflectionHost` into the `Esm2015ReflectionHost`
and looks to share as much as possible between the two hosts.
PR Close#36989
Previously the path to the unlocker process was being resolved by the
current file-system. In the case that this was a `MockFileSystemWindows`
on a non-Windows operating system, this resulted in an incorrect path
to the entry-point.
Now the path to the entry-point is hand-crafted to avoid being broken by
whatever FileSystem is in use.
PR Close#36989
The previous implementations of `hasBaseClass()` are almost
identical to the implementation of `getBaseClassExpression()`.
There is little benefit in duplicating this code so this refactoring
changes `hasBaseClass()` to just call `getBaseClassExpression()`.
This allows the various hosts that implement this to be simplified.
PR Close#36989
A number of overloads were added to `detectKnownDeclaration()` to
allow it to support `null` being passed through. In practice this could
easily be avoided, which allows the overloads to be removed and the
method signature and implementations to be simplified.
PR Close#36989
Previously in v9, we deprecated the pattern of undecorated base classes
that rely on Angular features. We ran a migration for this in version 9
and will run the same on in version 10 again.
To ensure that projects do not regress and start using the unsupported
pattern again, we report an error in ngtsc if such undecorated classes
are discovered.
We keep the compatibility code enabled in ngcc so that libraries
can be still be consumed, even if they have not been migrated yet.
Resolves FW-2130.
PR Close#36921
As of version 10, libraries following the APF will no longer contain
ESM5 output. Hence, tests in ngcc need to be updated as they currently
rely on the release output of `@angular/core`.
Additionally, we'd need to support in ngcc that the `module`
property of entry-points no longer necessarily refers to
`esm5` output, but instead can also target `esm2015`.
We currently achieve this by checking the path the `module`
property points to. We can do this because as per APF, the
folder name is known for the esm2015 output. Long-term for
more coverage, we want to sniff the format by looking for
known ES2015 constructs in the file `module` refers to.
PR Close#36944
In #36892 the `ModuleWithProviders` type parameter becomes required.
This exposes a bug in ngcc, where it can only handle functions that have a
specific form:
```
function forRoot() {
return { ... };
}
```
In other words, it only accepts functions that return an object literal.
In some libraries, the function instead returns a call to another function.
For example in `angular-in-memory-web-api`:
```
InMemoryWebApiModule.forFeature = function (dbCreator, options) {
return InMemoryWebApiModule_1.forRoot(dbCreator, options);
};
```
This commit changes the parsing of such functions to use the
`PartialEvaluator`, which can evaluate these more complex function
bodies.
PR Close#36948
Previously this method was implemented on the `NgccReflectionHost`,
but really it is asking too much of the host, since it actually needs to do
some static evaluation of the code to be able to support a wider range
of function shapes. Also there was only one implementation of the method
in the `Esm2015ReflectionHost` since it has no format specific code in
in.
This commit moves the whole function (and supporting helpers) into the
`ModuleWithProvidersAnalyzer`, which is the only place it was being used.
This class will be able to do further static evaluation of the function bodies
in order to support more function shapes than the host can do on its own.
The commit removes a whole set of reflection host tests but these are
already covered by the tests of the analyzer.
PR Close#36948
This optimization builds on a lot of prior work to finally make type-
checking of templates incremental.
Incrementality requires two main components:
- the ability to reuse work from a prior compilation.
- the ability to know when changes in the current program invalidate that
prior work.
Prior to this commit, on every type-checking pass the compiler would
generate new .ngtypecheck files for each original input file in the program.
1. (Build #1 main program): empty .ngtypecheck files generated for each
original input file.
2. (Build #1 type-check program): .ngtypecheck contents overridden for those
which have corresponding components that need type-checked.
3. (Build #2 main program): throw away old .ngtypecheck files and generate
new empty ones.
4. (Build #2 type-check program): same as step 2.
With this commit, the `IncrementalDriver` now tracks template type-checking
_metadata_ for each input file. The metadata contains information about
source mappings for generated type-checking code, as well as some
diagnostics which were discovered at type-check analysis time. The actual
type-checking code is stored in the TypeScript AST for type-checking files,
which is now re-used between programs as follows:
1. (Build #1 main program): empty .ngtypecheck files generated for each
original input file.
2. (Build #1 type-check program): .ngtypecheck contents overridden for those
which have corresponding components that need type-checked, and the
metadata registered in the `IncrementalDriver`.
3. (Build #2 main program): The `TypeCheckShimGenerator` now reuses _all_
.ngtypecheck `ts.SourceFile` shims from build #1's type-check program in
the construction of build #2's main program. Some of the contents of
these files might be stale (if a component's template changed, for
example), but wholesale reuse here prevents unnecessary changes in the
contents of the program at this point and makes TypeScript's job a lot
easier.
4. (Build #2 type-check program): For those input files which have not
"logically changed" (meaning components within are semantically the same
as they were before), the compiler will re-use the type-check file
metadata from build #1, and _not_ generate a new .ngtypecheck shim.
For components which have logically changed or where the previous
.ngtypecheck contents cannot otherwise be reused, code generation happens
as before.
PR Close#36211
This function needs to deduplicate the paths that are found from the
paths mappings. Previously this deduplication was not linear and also
called the expensive `relative()` function many times.
This commit, suggested by @JoostK, reduces the complexity of the deduplication
by using a tree structure built from the segments of each path.
PR Close#36881
Previously the `basePaths` were computed when the finder was instantiated.
This was a waste of effort in the case that the targeted entry-point is already
processed.
This change makes the computation of `basePaths` lazy, so that the work is
only done if they are actually needed.
Fixes#36874
PR Close#36881
In TS 3.9 the compiler will start to wrap ES2015 classes in an IIFE to help with
tree-shaking when the class has "associated" statements.
E.g.
```ts
let PlatformLocation = /** @class */ (() => {
...
class PlatformLocation {
}
...
return PlatformLocation;
})();
```
This commit updates `Esm2015ReflectionHost` to support this format.
PR Close#36884
Previously the `AsyncLocker` was configured to only wait
50x500ms before timing out. This is 25secs, which is often
less than a normal run of ngcc, so the chance of a timeout
flake was quite high.
The default is now 500x500ms, which is 250secs. If this is
too high for some projects then it can be changed via the
`ngcc.config.js` project file.
PR Close#36838
The commit adds support to the ngcc.config.js file for setting the
`retryAttempts` and `retryDelay` options for the `AsyncLocker`.
An integration test adds a new check for a timeout and actually uses the
ngcc.config.js to reduce the timeout time to prevent the test from taking
too long to complete.
PR Close#36838
Strictly this method only returns config for packages. So this commit
renames it to `getPackageConfig()`, which frees us up to add other
"getXxxxConfig()` methods later.
PR Close#36838
This test is basically duplicated (and slightly enhanced) in the
following test. So it is superfluous. (I suspect it was the result
of a broken rebase.)
PR Close#36838
When ngcc fails due to a timeout waiting for another process
to complete, it was not failing with a unique exit code, so that it
was not possible to know if the process can be restarted; compared to
ngcc failing for some more fatal reason.
Now if ngcc exits because of a timeout, the exit code will be 177.
PR Close#36838
When ngcc is having to pause and wait for another process
it provides a message to the user. This commit adds the extra
information about how to remove the lockfile if desired, since
this message is not shown if you Ctrl-C out of the process before
the timeout period ends.
PR Close#36838
Now that `ngcc/src/ngcc_options` imports `FileWriter` type, there is a
circular dependency detected by the `ts-circular-deps:check` lint check:
```
ngcc/src/ngcc_options.ts
→ ngcc/src/writing/file_writer.ts
→ ngcc/src/packages/entry_point_bundle.ts
→ ngcc/src/ngcc_options.ts
```
This commit moves the `PathMappings` type (and related helpers) to a
separate file to avoid the circular dependency.
NOTE:
The circular dependency was only with taking types into account. There
was no circular dependency for the actual (JS) code.
PR Close#36626
When running in parallel mode, worker processes forward errors thrown
during task processing to the master process, which in turn exits with
an error.
However, there are cases where the error is not directly related to
processing the entry-point. One such case is when there is not enough
memory (for example, due to all the other tasks being processed
simultaneously).
Previously, an `ENOMEM` error thrown on a worker process would propagate
to the master process, eventually causing ngcc to exit with an error.
Example failure: https://circleci.com/gh/angular/angular/682198
This commit improves handling of these low-memory situations by
detecting `ENOMEM` errors and killing the worker process, thus allowing
the master process to decide how to handle that. The master process will
put the task back into the tasks queue and continue processing tasks
with the rest of the worker processes (and thus with lower memory
pressure).
PR Close#36626
Previously, when the last worker process crashed, the master process
would try to re-spawn it indefinitely. This could lead to an infinite
loop (if for some reason the worker process kept crashing).
This commit avoids this by limiting the number of re-spawn attempts to
3, after which ngcc will exit with an error.
PR Close#36626