A new flag added to the component's debug info to determine whether to throw runtime error (in dev mode) if component is being rendered without its NgModule. This flag is only set for non-standalone components.
PR Close#52061
A new statement will be generated for components which will attach some useful debug info to them to be used in runtime error handling. Currently this only happens in full and local compilation modes.
PR Close#51919
Enables the new `@` block syntax by default by removing the `enabledBlockTypes` flags. There are still some internal flags that allow special use cases to opt out of the block syntax, like during XML parsing and when compiling older libraries (see #51979).
PR Close#51994
Currently the field encapsulation undergoes some static analysis to check if it is `ViewEncapsulation` enum. Such static check fails in local compilation mode in g3 as the symbol cannot be resolved. On the other hand this field has to be resolved statically as its value determined the generated code. So in local compilation mode we add a lighter resolving logic which relies only on local information.
PR Close#51848
Currently the field changeDetection undergoes some static analysis to check if it is `ChangeDetectionStrategy` enum. Such static check fails in local compilation mode in g3 as the symbol cannot be resolved. So in local compilation mode we bypass such resolving and just write the expression as is into the component definition.
PR Close#51848
Switches the syntax for blocks from `{#block}{/block}` to `@block {}` based on the feedback from the community.
Read more about the decision-making process in our blog: https://blog.angular.io/meet-angulars-new-control-flow-a02c6eee7843
The existing block types changed in the following ways:
**Conditional blocks:**
```html
<!-- Before -->
{#if cond}
Main content
{:else if otherCond}
Else if content
{:else}
Else content
{/if}
<!-- After -->
@if (cond) {
Main content
} @else if (otherCond) {
Else if content
} @else {
Else content
}
```
**Deferred blocks**
```html
<!-- Before -->
{#defer when isLoaded}
Main content
{:loading} Loading...
{:placeholder} <icon>pending</icon>
{:error} Failed to load
{/defer}
<!-- After -->
@defer (when isLoaded) {
Main content
} @loading {
Loading...
} @placeholder {
<icon>pending</icon>
} @error {
Failed to load
}
```
**Switch blocks:**
```html
<!-- Before -->
{#switch value}
{:case 1}
One
{:case 2}
Two
{:default}
Default
{/switch}
<!-- After -->
@switch (value) {
@case (1) {
One
}
@case (2) {
Two
}
@default {
Default
}
}
```
**For loops**
```html
<!-- Before -->
{#for item of items; track item}
{{item.name}}
{:empty} No items
{/for}
<!-- After -->
@for (item of items; track item) {
{{item.name}}
} @empty {
No items
}
```
PR Close#51891
Reworks the compiler to use the API introduced in #51816 to match triggers to the element nodes they point to. This will be used to generate the new instructions for `on interaction` and `prefetch on interaction`.
PR Close#51830
Currently the compiler in local mode assumes that the standalone component imports are array expressions. This is not always true as they can be const variables as well. This change allow non-array expressions for standalone component imports field and passes that expression to the downstream tools such as deps tracker to compute the component's deps in runtime.
PR Close#51819
Adds support for passing in `@Component.styles` as a string. Also introduces a new `styleUrl` property on `@Component` for providing a single stylesheet. This is more convenient for the most common case where a component only has one stylesheet associated with it.
PR Close#51715
Currently internally Angular has some customized tsconfig files, because we don't align with the tsconfig of the rest of g3. These changes enable `noImplicitReturns` and `noPropertyAccessFromIndexSignature` to align better with the internal config.
PR Close#51728
In local compilation mode it is not possible to use an imported string for component's template or styles as it cannot be resolved statically in compile time. There are some such use cases in g3 and potentially devs might incorporate such pattern. At the moment such pattern will cause the local compilation fail with generic error messages (e.g., so and so at position 1 is not a reference, etc). This change makes specific error messages with helpful hints for such cases. These new error messages can help devs to quickly resolve the issue as well as make it possible to identify existing issues in g3.
PR Close#51338
This commit updates TestBed to wait for async component metadata resolution before compiling components.
Async metadata is added by the compiler in case a component uses defer blocks, which contain deferrable
symbols.
PR Close#51182
This commit updates compiler logic to generate the `setClassMetadataAsync` calls for components that used defer blocks. The `setClassMetadataAsync` function loads deferrable dependencies and invokes the `setClassMetadata` synchronously once everything is loaded. This change is needed to avoid eager references to deferrable symbols in component metadata in generated code.
PR Close#51182
A factory generator function called "i0.ɵɵgetComponentDepsFactory" is added to generate a factory function for component dependencies. This function will use the deps tracker to calculate the component's dependencies.
For standalone components the component imports (if exists) will be passed to this function. Alternatively this function can grab the imports directly from the decorate, but such extraaction needs some runtime logic which overlapps with what the trait compiler is doing. So better to pass the imports directly to this function at compile time.
PR Close#51089
This commit updates the logic to drop regular imports when all symbols that it brings can be defer-loaded.
The change ensures that there is no mix of regular and dynamic imports present in a source file.
PR Close#51171
Updates the TemplateDefinitionBuilder class to generate the `defer` instruction for `{#defer}` blocks. Also generates dependency function that would be invoked at runtime (with dynamic imports inside).
PR Close#51162
This commit brings the logic to calculate teh set of dependencies for each defer block. For each dependency we also identify whether it can be defer-loaded or not.
PR Close#51162
This is a minor refactoring of the ComponentHandler class logic to extract helper function and types to the top level for simplicity and reuse across other functions of the class.
PR Close#51162
This commit adds a new class called `DeferredSymbolTracker` to keep track of all usages of a particular symbol within a source file and allow to detect whether a symbol can be defer loaded (i.e. if there are any references to a symbol).
PR Close#51162
A minimal change to full compilation mode to work in local mode. Now compiler can compile components without ctor injections, though the compiled code missing the following items which will be added in subsequent commits:
* it does not produce `dependencies` for component definition.
* it fails if component has ctor injection
PR Close#50545
The compiler will only include analysis and compile phases in local mode. Also a new `compileLocal` method is added to the annotation handler for local compilation.
This commit makes no change to the full/partial compilation code paths.
PR Close#50545
An internal compiler option named `supportTestBed` is now available for use by the
Angular CLI. This option currently controls the extraction and emit of Angular class
metadata. This emitted information is only needed in AOT mode when using certain
TestBed APIs. However, AOT mode is currently not available for unit testing within
the Angular CLI. As a result, the metadata is not used within CLI generation applications
and in particular production applications. Without this option, the CLI needs to
manually perform a code transform to remove the metadata and also replicate TypeScript's
import eliding. This is can be a complicated operation and must be continually kept
up to date with any changes to both the Angular compiler and TypeScript. The introduction
of this new option alleviates these concerns.
PR Close#50604
If the compiler CLI is running through closure compiler, the trait
decorator handlers are converted from classes to functions as ES5
is picked as default output target for the bundled version.
The problem is that currently all trait handlers end up having the
same `name`. i.e. an empty string, and therefore adopting previous
traits from a previous build iteration result in the incorrect handler
being used for e.g. registrering, compiling etc- causing
ambiguous/confusing errors down the line in other parts.
We can look into changing the output target in the future, but even
then we are safer using an actual literal due to property renaming.
```$$closure$$NgModuleDecoratorHandler = function() {}`.
It is is questionable if we should just simply NOT run the compiler
through JSCompiler.
PR Close#50673
Adds the necessary compiler changes to support input transform functions. The compiler output has changed in the following ways:
### Directive handler
The directive handler now extracts a reference to the input transform function and it resolves the type of its first parameter. It also asserts that the type can be referenced in the compiled output and that it doesn't clash with any pre-existing `ngAcceptInputType_` members.
### .d.ts
In the generated declaration files the compiler now inserts an `ngAcceptInputType_` member for each input with a `transform` function. The member's type corresponds to the type of the first parameter of the function, e.g.
```typescript
// foo.directive.ts
@Directive()
export class Foo {
@Input({transform: (incomingValue: string) => parseInt(incomingValue)}) value: number;
}
// foo.directive.d.ts
export class Foo {
value: number;
static ngAcceptInputType_value: string;
}
```
### Type check block
If an input has `transform` function, the TCB will use the type of its first parameter for the setter type. This uses the same infrastructure as the `ngAcceptInputType_` members.
### Directive declaration
The generated runtime directive declaration call now includes the `transform` function in the `inputs` map, if the input is being transformed. The function will be picked up by the runtime in the next commit to do the actual transformation.
```typescript
// foo.directive.ts
@Directive()
export class Foo {
@Input({transform: (incomingValue: string) => parseInt(incomingValue)}) value: number;
}
// foo.directive.js
export class Foo {
ɵdir = ɵɵdefineDirective({
inputs: {
value: ['value', 'value', incomingValue => parseInt(incomingValue)]
}
});
}
```
PR Close#50225
This commit adds the `signals: boolean` property to the internal
directive/component metadata. This does not add it to the public API
yet, as the feature has no internal support other than compiler
detection.
PR Close#49981
NgModules which import standalone components currently list those components
in their injector definitions, because we assume that any standalone
component may export providers from its own imports.
This commit adds an optimization for that emit, which attempts to statically
analyze the NgModule imports and determine which standalone components, if
any are present, do not export providers and thus can be omitted.
This analysis is imperfect, because some imported components may be declared
outside of the current compilation, or transitively import types which are
declared outside the compilation. These types are therefore _assumed_ to
carry providers and so the optimization isn't applied to them.
PR Close#49837
The compiler currently does not check to make sure that directives in
the host bindings are exported. These directives are part of the public
API of the component so they do have to be.
PR Close#49527
This commit simplifies various parts of ngtsc to no longer support synthetic decorators,
downleveled enum members and inline declarations. These concepts were present to support
ngcc, but can be dropped now that ngcc has been removed.
PR Close#49136
This commit updates parts of the FW to be ES2022 complaint.
These changes are needed to fix the following problems problems with using properties before they are initialized.
Example
```ts
class Foo {
bar = this.buz;
constructor(private buz: unknown){}
}
```
PR Close#49559
This commit updates parts of the FW to be ES2022 complaint.
These changes are needed to fix the following problems problems with using properties before they are initialized.
Example
```ts
class Foo {
bar = this.buz;
constructor(private buz: unknown){}
}
```
PR Close#49332
Consider the following scenario:
1. A TS file with a component and templateUrl exists
2. The template file does not exist.
3. First build: ngtsc will properly report the error, via a FatalDiagnosticError
4. The template file is now created
5. Second build: ngtsc still reports the same errror.
ngtsc persists the analysis data of the component and never invalidates
it when the template/style file becomes available later.
This breaks incremental builds and potentially common workflows
where resource files are added later after the TS file is created. This
did surface as an issue in the Angular CLI yet because Webpack requires
users to re-start the process when a new file is added. With ESBuild
this will change and this also breaks incremental builds with
Bazel/Blaze workers.
To fix this, we have a few options:
* Invalidate the analysis when e.g. the template file is missing. Never
caching it means that it will be re-analyzed on every build iteration.
* Add the resource dependency to ngtsc's incremental file graph. ngtsc
will then know via `host.getModifiedResources` when the file becomes
available- and fresh analysis of component would occur.
The first approach is straightforward to implement and was chosen here.
The second approach would allow ngtsc to re-use more of the analysis
when we know that e.g. the template file still not there, but it
increases complexity unnecessarily because there is no **single**
obvious resource path for e.g. a `templateUrl`. The URL is attempted
to be resolved using multiple strategies, such as TS program root dirs,
or there is support for a custom resolution through
`host.resourceNameToFileName`.
It would be possible to determine some candidate paths and add them to
the dependency tracker, but it seems incomplete given possible external
resolvers like `resourceNameToFileName` and also would likely not have
a sufficient-enough impact given that a broken component decorator is
not expected to remain for too long between N incremental build
iterations.
PR Close#49184
In AOT compilations, the `strictInjectionParameters` compiler option can
be enabled to report errors when an `@Injectable` annotated class has a
constructor with parameters that do not provide an injection token, e.g.
only a primitive type or interface.
Since Ivy it's become required that any class with Angular behavior
(e.g. the `ngOnDestroy` lifecycle hook) is decorated using an Angular
decorator, which meant that `@Injectable()` may need to have been added
to abstract base classes. Doing so would then report an error if
`strictInjectionParameters` is enabled, if the abstract class has an
incompatible constructor for DI purposes. This may be fine though, as
a subclass may call the constructor explicitly without relying on
Angular's DI mechanism.
Therefore, this commit excludes abstract classes from the
`strictInjectionParameters` check. This avoids an error from being
reported at compile time. If the constructor ends up being used by
Angular's DI system at runtime, then the factory function of the
abstract class will throw an error by means of the `ɵɵinvalidFactory`
instruction.
In addition to the runtime error, this commit also analyzes the inheritance
chain of an injectable without a constructor to verify that their inherited
constructor is valid.
BREAKING CHANGE: Invalid constructors for DI may now report compilation errors
When a class inherits its constructor from a base class, the compiler may now
report an error when that constructor cannot be used for DI purposes. This may
either be because the base class is missing an Angular decorator such as
`@Injectable()` or `@Directive()`, or because the constructor contains parameters
which do not have an associated token (such as primitive types like `string`).
These situations used to behave unexpectedly at runtime, where the class may be
constructed without any of its constructor parameters, so this is now reported
as an error during compilation.
Any new errors that may be reported because of this change can be resolved either
by decorating the base class from which the constructor is inherited, or by adding
an explicit constructor to the class for which the error is reported.
Closes#37914
PR Close#44615
This is the compile-time implementation of the `hostDirectives` feature plus a little bit of runtime code to illustrate how the newly-generated code will plug into the runtime. It works by creating a call to the new `ɵɵHostDirectivesFeature` feature whenever a directive has a `hostDirectives` field. Afterwards `ɵɵHostDirectivesFeature` will patch a new function onto the directive definition that will be invoked during directive matching.
For example, if we take the following definition:
```ts
@Directive({
hostDirectives: [HostA, {directive: HostB, inputs: ['input: alias']}]
})
class MyDir {}
```
Will compile to:
```js
MyDir.ɵdir = ɵɵdefineComponent({
features: [ɵɵHostDirectivesFeature([HostA, {
directive: HostB,
inputs: {
input: "alias"
}
}])]
});
```
The template type checking is implemented during directive matching by adding the host directives applied on the host to the array of matched directives whenever the host is matched in a template.
Relates to #8785.
PR Close#46868
This helper accepts a class, and returns the primary Angular Decorator associated with that trait (e.g. the Component, Pipe, Directive, or NgModule decorator). This will be useful for the language service import project, which needs to edit import arrays inside the decorator.
PR Close#47180
Angular generally supports cycles between components in the same NgModule.
We have a mechanism of moving the component scope declaration into the
NgModule file in this case. This ensures that Angular never itself
introduces an import which creates a cycle.
What happens if the cycle already exists in the user's program, though, is a
bit different. In these cases, the "correct" emit for Angular is to generate
the component scope (whether direct or remote) inside of a closure, to
prevent evaluating the scope's references until module evaluation is
complete and all cyclic imports have been resolved. We don't want to do this
for *all* scopes because the code size cost of emitting a function wrapper
is non-zero.
In this fix, we take the presence of a `forwardRef` in a component's
`imports` or in an NgModule `declarations` or `imports` as a sign that
component scopes emitted into those files need to be protected against
cyclic references. In a future commit, we may introduce a warning or error
if cyclic imports are not protected behind `forwardRef` in these cases, but
this will take some time to implement.
PR Close#46139
This commit improves the reported error when importing e.g. `RouterModule.forRoot()`
from within `Component.imports`. Such import is not supported, as standalone components
can only refer to other standalone entities or NgModules in their `imports` array;
`ModuleWithProviders` are not supported as `Component.imports` is meant to be used
for the compilation scope of the component, _not_ for configuring DI.
Closes#46003
PR Close#46009
update the error message presented during aot compilation when an unrecognized
tag/element is found in a standalone component so that it does not mention
the ngModule anymore
Note: the jit variant is present in PR #45920resolves#45818
PR Close#45919
The Angular compiler performs cycle detection when generating imports within
component files. This was previously necessary as reifying dependencies
discovered via NgModules into the component output could add imports that
weren't present in the original component and potentially create cycles.
Doing this could cause order-of-execution issues with existing user imports,
so the compiler detects this case and falls back to an alternative way of
specifying component dependencies that doesn't risk creating cycles.
For standalone components, Angular does not need to add new imports to the
component file as the user has already explicitly referenced dependencies
in the `@Component.imports`. As a result, the cycle detection can be
skipped.
Correctly authoring a program with import cycles is always challenging. One
side of a cyclic import will always initially evaluate to `undefined`, and
this can result in errors in the component definition when this happens
within component `imports`.
Our compiler _could_ detect the cycle and choose to wrap the component
dependencies in an automatic closure instead, avoiding any issues with
`undefined` during an eager evaluation. However, this commit makes an active
choice not to do that as it only serves to mask the problems with cyclic
imports. Future refactorings may cause the "other half" of the cycle to
break. Users should instead be aware of the potential problems with cycles
and explicitly defer evaluations with `forwardRef` where needed. This
ensures that future implementations of Angular compilation which may not be
able to automatically detect import cycles and correct accordingly can still
compile such components.
PR Close#46029
This commit improves the error message for using `imports` on a component
that isn't set to `standalone: true`. Two concrete improvements are made:
* A related information message is added to the diagnostic which suggests
the fix of adding `standalone: true`.
* The component is marked as poisoned, preventing other errors which might
be caused by an incorrectly configured template scope from being generated
and thus masking the original problem.
Fixes#45850
PR Close#45851