Incremental compilation allows for the output state of one compilation to be
reused as input to the next compilation. This involves retaining references
to instances from prior compilations, which must be done carefully to avoid
memory leaks.
This commit fixes such a leak with a complicated retention chain:
* `TrackedIncrementalBuildStrategy` unnecessarily hangs on to the previous
`IncrementalDriver` (state of the previous compilation) once the current
compilation completes.
In general this is unnecessary, but should be safe as long as the chain
only goes back one level - if the `IncrementalDriver` doesn't retain any
previous `TrackedIncrementalBuildStrategy` instances. However, this does
happen:
* `NgCompiler` indirectly causes retention of previous `NgCompiler`
instances (and thus previous `TrackedIncrementalBuildStrategy` instances)
through accidental capture of the `this` context in a closure created in
its constructor. This closure is wrapped in a `ts.ModuleResolutionCache`
used to create a `ModuleResolver` class, which is passed to the program's
`TraitCompiler` on construction.
* The `IncrementalDriver` retains a reference to the `TraitCompiler` of the
previous compilation, completing the reference chain.
The final retention chain thus looks like:
* `TrackedIncrementalBuildStrategy` of current program
* `.previous`: `IncrementalDriver` of previous program
* `.lastGood.traitCompiler`: `TraitCompiler`
* `.handlers[..].moduleResolver.moduleResolutionCache`: cache
* (via `getCanonicalFileName` closure): `NgCompiler`
* `.incrementalStrategy`: `TrackedIncrementalBuildStrategy` of previous
program.
The closure link is the "real" leak here. `NgCompiler` is creating a closure
for `getCanonicalFileName`, delegating to its
`this.adapter.getCanonicalFileName`, for the purposes of creating a
`ts.ModuleResolutionCache`. The fact that the closure references
`NgCompiler` thus eventually causes previous `NgCompiler` iterations to be
retained. This is also potentially problematic due to the shared nature of
`ts.ModuleResolutionCache`, which is potentially retained across multiple
compilations intentionally.
This commit fixes the first two links in the retention chain: the build
strategy is patched to not retain a `previous` pointer, and the `NgCompiler`
is patched to not create a closure in the first place, but instead pass a
bound function. This ensures that the `NgCompiler` does not retain previous
instances of itself in the first place, even if the build strategy does
end up retaining the previous incremental state unnecessarily.
The third link (`IncrementalDriver` unnecessarily retaining the whole
`TraitCompiler`) is not addressed in this commit as it's a more
architectural problem that will require some refactoring. However, the leak
potential of this retention is eliminated thanks to fixing the first two
issues.
PR Close#37835
This commit fixes a spelling error in the word error in the
observables.md guide. It is currently
spelled errror and the mistake is not intentional.
PR Close#36437
change in the definition of providedIn:any any instance creates a singleton instance
for each lazy loaded module and one instance for eager loaded module
PR Close#35292
PR https://github.com/angular/angular/pull/37523 failed when trying to use `rxjs delay` operator
inside `fakeAsync`, and the reasons are:
1. we need to import `rxjs-fake-async` patch to make the integration work.
2. since in `angular` repo, the bazel target `/tools/testing:node` not using `zone-testing` bundle,
instead it load `zone-spec` packages seperately, so it causes one issue which is the `zone.js/testing/fake-async`
package is not loaded, we do have a fallback logic under `packages/core/testing` calles `fake_async_fallback`,
but the logic is out of date with `fake-async` under `zone.js` package.
So this PR, I updated the content of `fake_async_fallback` to make it consistent with
`fake-async`. And I will make another PR to try to remove the `fallback` logic.
PR Close#37680
Close#33657
in jasmine 3.5, there is a new feature, user can pass a properties object to `jasmine.createSpyObj`
```
const spy = jasmine.createSpyObj('spy', ['method1'], {prop1: 'foo'});
expect(spy.prop1).toEqual('foo');
```
This case will not work for Angular TestBed, for example,
```
describe('AppComponent', () => {
beforeEach(() => {
//Note the third parameter
// @ts-ignore
const someServiceSpy = jasmine.createSpyObj('SomeService', ['someFunction'], ['aProperty']);
TestBed.configureTestingModule({
declarations: [
AppComponent
],
providers: [
{provide: SomeService, useValue: someServiceSpy},
]
}).compileComponents();
});
it('should create the app', () => {
//spyObj will have someFunction, but will not have aProperty
let spyObj = TestBed.get(SomeService);
});
```
Because `jasmine.createSpyObj` will create the `aProperty` with `enumerable=false`,
and `TestBed.configureTestingModule` will try to copy all the properties from spyObj to
the injected service instance. And because `enumerable` is false, so the property (here is aProperty)
will not be copied.
This PR will monkey patch the `jasmine.createSpyObj` and make sure the new property's
`enumerable=true`.
PR Close#34624
When ngcc creates an entry-point program, the `allowJs` option is enabled
in order to operate on the JavaScript source files of the entry-point.
A side-effect of this approach is that external modules that don't ship
declaration files will also have their JavaScript source files loaded
into the program, as the `allowJs` flag allows for them to be imported.
This may pose an issue in certain edge cases, where ngcc would inadvertently
operate on these external modules. This can introduce all sorts of undesirable
behavior and incompatibilities, e.g. the reflection host that is selected for
the entry-point's format could be incompatible with that of the external
module's JavaScript bundles.
To avoid these kinds of issues, module resolution that would resolve to
a JavaScript file located outside of the package will instead be rejected,
as if the file would not exist. This would have been the behavior when
`allowJs` is set to false, which is the case in typical Angular compilations.
Fixes#37508
PR Close#37596
Changes `isWithinPackage` to take an `AbsoluteFsPath` instead of `ts.SourceFile`,
to allow for an upcoming change to use it when no `ts.SourceFile` is available,
but just a path.
PR Close#37596
The major sections Angular Libraries, Schematics, and CLI Builders appear twice, in their old location under Techniques, and in the new correct location under Extending Angular
PR Close#37827
Previously, event listeners for component output events attached on an
Angular custom element before inserting it into the DOM (i.e. before
instantiating the underlying component) didn't fire for events emitted
during initialization lifecycle hooks, such as `ngAfterContentInit`,
`ngAfterViewInit`, `ngOnChanges` (initial call) and `ngOnInit`.
The reason was that `NgElementImpl` [subscribed to events][1] _after_
calling [ngElementStrategy#connect()][2], which is where the
[initial change detection][3] takes place (running the initialization
lifecycle hooks).
This commit fixes this by:
1. Ensuring `ComponentNgElementStrategy#events` is defined and available
for subscribing to, even before instantiating the component.
2. Changing `NgElementImpl` to subscribe to `NgElementStrategy#events`
(if available) before calling `NgElementStrategy#connect()` (which
initializes the component instance) if available.
3. Falling back to the old behavior (subscribing to `events` after
calling `connect()` for strategies that do not initialize `events`
before their `connect()` is run).
NOTE:
By falling back to the old behavior when `NgElementStrategy#events` is
not initialized before calling `NgElementStrategy#connect()`, we avoid
breaking existing custom `NgElementStrategy` implementations (with
@remackgeek's [ElementZoneStrategy][4] being a commonly used example).
Jira issue: [FW-2010](https://angular-team.atlassian.net/browse/FW-2010)
[1]: c0143cb2ab/packages/elements/src/create-custom-element.ts (L167-L170)
[2]: c0143cb2ab/packages/elements/src/create-custom-element.ts (L164)
[3]: c0143cb2ab/packages/elements/src/component-factory-strategy.ts (L158)
[4]: f1b6699495/projects/elements-zone-strategy/src/lib/element-zone-strategy.tsFixes#36141
PR Close#37570
Previously an error thrown in the `analyzeFn` would cause
the ngcc process to exit immediately without removing the
lockfile, and potentially before the unlocker process had been
successfully spawned resulting in the lockfile being orphaned
and left behind.
Now we catch these errors and remove the lockfile as needed.
PR Close#37739
This commit updates the payload size limit for the `hello_world` test app built using Closure. This is likely an effect of the changes in https://github.com/angular/angular/pull/36578 (that reduces the bundle size for most of the apps) and additional changes in subsequent commits.
PR Close#37784
Invoking a callback registered through `ViewRef.onDestroy` throws an error, because we weren't registering it correctly in the internal data structure. These changes also remove the `storeCleanupFn` function, because it was mostly identical to `storeCleanupWithContext` and was only used in one place.
Fixes#36213.
PR Close#37543
Special DI tokens like `ChangeDetectorRef` and `ElementRef` can provide a factory via `NG_ELEMENT_ID`. The problem is that we were reading it off the token as `token[NG_ELEMENT_ID]` which will go up the prototype chain if it couldn't be found on the current token, resulting in the private `ViewRef` API being exposed, because it extends `ChangeDetectorRef`.
These changes fix the issue by guarding the property access with `hasOwnProperty`.
Fixes#36235.
PR Close#37574
Verify that HTML parsing is supported in addition to DOMParser existence.
This maybe wasn't as important before when DOMParser was used just as a
fallback on Firefox, but now that DOMParser is the default choice, we need
to be more accurate.
PR Close#36578
The `inertDocument` member is only needed when using the InertDocument
strategy. By separating the DOMParser and InertDocument strategies into
separate classes, we can easily avoid creating the inert document
unnecessarily when using DOMParser.
PR Close#36578
If [innerHTML] is used in a component and a Content-Security-Policy is set
that does not allow inline styles then Firefox and Chrome show the following
message:
> Content Security Policy: The page’s settings observed the loading of a
resource at self (“default-src”). A CSP report is being sent.
This message is caused because Angular is creating an inline style tag to
test for a browser bug that we use to decide what sanitization strategy to
use, which causes CSP violation errors if inline CSS is prohibited.
This test is no longer necessary, since the `DOMParser` is now safe to use
and the `style` based check is redundant.
In this fix, we default to using `DOMParser` if it is available and fall back
to `createHTMLDocument()` if needed. This is the approach used by DOMPurify
too.
The related unit tests in `html_sanitizer_spec.ts`, "should not allow
JavaScript execution when creating inert document" and "should not allow
JavaScript hidden in badly formed HTML to get through sanitization (Firefox
bug)", are left untouched to assert that the behavior hasn't changed in
those scenarios.
Fixes#25214.
PR Close#36578
This commit fixes a bug whereby the language service would incorrectly
return HTML elements if autocomplete is requested for an unknown symbol.
This is because we walk through every possible scenario, and fallback to
element autocomplete if none of the scenarios match.
The fix here is to return results from interpolation if we know for sure
we are in a bound text. This means we will now return an empty results if
there is no suggestions.
This commit also refactors the code a little to make it easier to
understand.
PR Close#37518
docs commits are sometimes trivial (e.g. an obvious typo fix) and in such cases its very
akward to to write up 100 chars worth of text about why this typo fix is the best thing in the
world and why it is so important and crucial that we must know why we are fixing the typo
at all. After all most typos are not just typos. Or are they? We'll shall see...
PR Close#37764
This feature will allow us to exclude certain commits from the 100 chars minBodyLength requirement for commit
messages which is hard to satisfy for commits that make trivial changes (e.g. fixing typos in docs or comments).
PR Close#37764
This commit replaces an assert with more descriptive error message that is thrown in case `<ng-template>` or `<ng-container>` is used as host element for a Component.
Resolves#35240.
PR Close#35916
The shims_for_IE.js file contains vendor code that predates the third_party
directory. This file is currently used for internal karma testing setup. This
change corrects this by moving the shims_for_IE file to //third_part/
PR Close#37624
`getExternalFiles()` is an API that could optionally be provided by a tsserver plugin
to notify the server of any additional files that should belong to a particular project.
This API was removed in https://github.com/angular/angular/pull/34260 mainly
due to performance reasons.
However, with the introduction of "solution-style" tsconfig in typescript 3.9,
the Angular extension could no longer reliably detect the owning Project solely
based on the ancestor tsconfig.json. In order to support this use case, we have
to reinstate `getExternalFiles()`.
Fixes https://github.com/angular/vscode-ng-language-service/issues/824
PR Close#37750
We recently added OAuth scope checking to the dev-infra Git client
and started leveraging it for the merge script. We set the `repo` scope
as required for running the merge script. We can loosen this requirement
as in the Angular org where the script is consumed, only pull requests on
public repositories are merged through the script.
This should help with reducing the risk with compromised tokens as no
access had to be granted on `repo:invite`, `repo_deployment` etc.
PR Close#37718
Scripts provided in the `ng-dev` command might use local `git`
commands. For such scripts, we keep track of the branch that
has been checked out before the command has been invoked.
We do this so that we can later (upon command completion)
restore back to the original branch. We do not want to
leave the Git repository in a dirty state.
It looks like this logic currently only deals with branches
but does not work properly when a command is invoked from
a detached head. We can make it work by just checking out
the previous revision (if no branch is checked out).
PR Close#37737
As reported in #37699, the size of the main angular.io bundle sometimes
ends up bigger than expected on CI. This usually goes away after
rerunning the job a couple of times.
It is unclear what is causing this. In order to help debug the issue,
this commit stores the JS files that are checked as part of the aio
payload-size check as CI artifacts, where they can be retrieved from and
inspected.
PR Close#37703
Adds the publishConfig registry value to the package.json of the
@angular/benchpress package to publish it via wombat rather than
through npm directly.
PR Close#37752
I was using schematics with the `--name` parameter instead of the `--project`, I did both ways before sending and my suspicion about outdated documentation was confirmed
PR Close#37681
Addresses small typos such as extra whitespaces.
This change was extracted from #29505.
This change was extracted from #29505.
This change was extracted from #29505.
PR Close#37753
This commit disables all diagnostic tests for DynamicValue diagnostics which
make assertions about the diagnostic filename while running tests on Windows.
Such assertions are currently suffering from a case sensitivity issue.
PR Close#37763
The deployment to aio is currently failing because #37721 introduced
"project" entry into the firebase.json which means that we now need to
select the deployment target before deploying to firebase.
This change fixes the issue and refactors the file to be easier to read.
I also added extra echo statements so that the CI logs are easier to
read in case we need to troubleshoot future issues.
PR Close#37762
Several partial_evaluator tests in the diagnostics_spec check assert
correctness of diagnostic filenames. Previously these assertions compared
a resolved (`absoluteFrom`) filename with the TypeScript `ts.SourceFile`'s
`fileName` string, which caused the tests to fail on Windows because the
drive letter case differed.
This commit changes the assertions to use `absoluteFromSourceFile` instead
of the `fileName` string, resulting in an apples-to-apples comparison of
canonicalized paths.
PR Close#37758
This typo caused the script to fail on Linux (interestingly it works fine on Mac).
This is a painful reminder that we should not write any more Bash scripts EVER. shelljs FTW! :-)
PR Close#37754
Currently when bootstrapped component is being removed using `ComponentRef.destroy` or `NgModuleRef.destroy` methods, DOM nodes may be retained in the DOM tree. This commit fixes that problem by always attaching host element of the internal root view to the component's host view node, so the cleanup can happen correctly.
Resolves#36449.
PR Close#37600
In version 10.0.0-next.8, we introduced absolute URL support for
server-based HTTP requests, so long as the fully-resolved URL was
provided in the initial config. However, doing so represents a
breaking change for users who already have their own interceptors
to model this functionality, since our logic executes before all
interceptors fire on a request. See original PR #37071.
Therefore, we introduce a flag to make this change consistent with
v9 behavior, allowing users to opt in to this new behavior. This
commit also fixes two issues with the previous implementation:
1. if the server was initiated with a relative URL, the absolute
URL construction would fail because needed components were empty
2. if the user's absolute URL was on a port, the port would not
be included
PR Close#37539
As of v10, the `undecorated-classes-with-decorated-fields` migration
generally deals with undecorated classes using Angular features. We
intended to run this migation as part of v10 again as undecorated
classes with Angular features are no longer supported in planned v11.
The migration currently behaves incorrectly in some cases where an
`@Injectable` or `@Pipe` decorated classes uses the `ngOnDestroy`
lifecycle hook. We incorrectly add a TODO for those classes. This
commit fixes that.
Additionally, this change makes the migration more robust to
not migrate a class if it inherits from a component, pipe
injectable or non-abstract directive. We previously did not
need this as the undecorated-classes-with-di migration ran
before, but this is no longer the case.
Last, this commit fixes an issue where multiple TODO's could be
added. This happens when multiple Angular CLI build targets have
an overlap in source files. Multiple programs then capture the
same source file, causing the migration to detect an undecorated
class multiple times (i.e. adding a TODO twice).
Fixes#37726.
PR Close#37732
This commit introduces a dedicated `DynamicValue` kind to indicate that a value
cannot be evaluated statically as the function body is not just a single return
statement. This allows more accurate reporting of why a function call failed
to be evaluated, i.e. we now include a reference to the function declaration
and have a tailor-made diagnostic message.
PR Close#37587
During AOT compilation, the value of some expressions need to be known at
compile time. The compiler has the ability to statically evaluate expressions
the best it can, but there can be occurrences when an expression cannot be
evaluated statically. For instance, the evaluation could depend on a dynamic
value or syntax is used that the compiler does not understand. Alternatively,
it is possible that an expression could be statically evaluated but the
resulting value would be of an incorrect type.
In these situations, it would be helpful if the compiler could explain why it
is unable to evaluate an expression. To this extend, the static interpreter
in Ivy keeps track of a trail of `DynamicValue`s which follow the path of nodes
that were considered all the way to the node that causes an expression to be
considered dynamic. Up until this commit, this rich trail of information was
not surfaced to a developer so the compiler was of little help to explain
why static evaluation failed, resulting in situations that are hard to debug
and resolve.
This commit adds much more insight to the diagnostic that is produced for static
evaluation errors. For dynamic values, the trail of `DynamicValue` instances
is presented to the user in a meaningful way. If a value is available but not
of the correct type, the type of the resolved value is shown.
Resolves FW-2155
PR Close#37587
Previously, an anonymous type was used for creating a diagnostic with related
information. The anonymous type would then be translated into the necessary
`ts.DiagnosticRelatedInformation` shape within `makeDiagnostic`. This commit
switches the `makeDiagnostic` signature over to taking `ts.DiagnosticRelatedInformation`
directly and introduces `makeRelatedInformation` to easily create such objects.
This is done to aid in making upcoming work more readable.
PR Close#37587
Commit 4213e8d5 introduced shim reference tagging into the compiler, and
changed how the `TypeCheckProgramHost` worked under the hood during the
creation of a template type-checking program. This work enabled a more
incremental flow for template type-checking, but unintentionally introduced
several regressions in performance, caused by poor incrementality during
`ts.Program` creation.
1. The `TypeCheckProgramHost` was made to rely on the `ts.CompilerHost` to
retrieve instances of `ts.SourceFile`s from the original program. If the
host does not return the original instance of such files, but instead
creates new instances, this has two negative effects: it incurs
additional parsing time, and it interferes with TypeScript's ability to
reuse information about such files.
2. During the incremental creation of a `ts.Program`, TypeScript compares
the `referencedFiles` of `ts.SourceFile` instances from the old program
with those in the new program. If these arrays differ, TypeScript cannot
fully reuse the old program. The implementation of reference tagging
introduced in 4213e8d5 restores the original `referencedFiles` array
after a `ts.Program` is created, which means that future incremental
operations involving that program will always fail this comparison,
effectively limiting the incrementality TypeScript can achieve.
Problem 1 exacerbates problem 2: if a new `ts.SourceFile` is created by the
host after shim generation has been disabled, it will have an untagged
`referencedFiles` array even if the original file's `referencedFiles` was
not restored, triggering problem 2 when creating the template type-checking
program.
To fix these issues, `referencedFiles` arrays are now restored on the old
`ts.Program` prior to the creation of a new incremental program. This allows
TypeScript to get the most out of reusing the old program's data.
Additionally, the `TypeCheckProgramHost` now uses the original `ts.Program`
to retrieve original instances of `ts.SourceFile`s where possible,
preventing issues when a host would otherwise return fresh instances.
Together, these fixes ensure that program reuse is as incremental as
possible, and tests have been added to verify this for certain scenarios.
An optimization was further added to prevent the creation of a type-checking
`ts.Program` in the first place if no type-checking is necessary.
PR Close#37641