Now that we've replaced `ngBaseDef` with an abstract directive definition, there are a lot more cases where we generate a directive definition without a selector. These changes make it so that we don't generate the `selectors` array if it's going to be empty.
PR Close#33431
Prior to this commit, i18n logic which ensures that elements removed in a translation are also removed in DOM, didn't take into account the fact that elements may have local refs. As a result, remove operation failed, since there is no corresponding tNode found. This commit updates the logic to skip all local refs while going though the list of nodes to ensure that DOM matches elements present in translation.
PR Close#33415
`bindingIndex` stores the current location of the bindings in the
template function. Because it used to be stored in `LView` that `LView`
was not reentrant. This could happen if a binding was a getter and had
a side-effect of calling `detectChanges()`.
By moving the `bindingIndex` to `LFrame` where all of the global state
is kept in reentrant way we correct the issue.
PR Close#33235
Removes `ngBaseDef` from the compiler and any runtime code that was still referring to it. In the cases where we'd previously generate a base def we now generate a definition for an abstract directive.
PR Close#33264
For abstract directives, i.e. directives without a selector, it may
happen that their constructor is called explicitly from a subclass,
hence its parameters are not required to be valid for Angular's DI
purposes. Prior to this commit however, having an abstract directive
with a constructor that has parameters that are not eligible for
Angular's DI would produce a compilation error.
A similar scenario may occur for `@Injectable`s, where an explicit
`use*` definition allows for the constructor to be irrelevant. For
example, the situation where `useFactory` is specified allows for the
constructor to be called explicitly with any value, so its constructor
parameters are not required to be valid. For `@Injectable`s this is
handled by generating a DI factory function that throws.
This commit implements the same solution for abstract directives, such
that a compilation error is avoided while still producing an error at
runtime if the type is instantiated implicitly by Angular's DI
mechanism.
Fixes#32981
PR Close#32987
This commit adds CopyDefinitionFeature, which supports the case where an
entire decorator (@Component or @Directive) is inherited from parent to
child.
The existing inheritance feature, InheritDefinitionFeature, supports merging
of parent and child definitions when both were originally present. This
merges things like inputs, outputs, host bindings, etc.
CopyDefinitionFeature, on the other hand, compensates for a definition that
was missing entirely on the child class, by copying fields that aren't
ordinarily inherited (like the template function itself).
This feature is intended to only be used as part of ngcc code generation.
PR Close#33362
This patch ensures that the `[style]` and `[class]` based bindings
are directly applied to an element's style and className attributes.
This patch optimizes the algorithm so that it...
- Doesn't construct an update an instance of `StylingMapArray` for
`[style]` and `[class]` bindings
- Doesn't apply `[style]` and `[class]` based entries using
`classList` and `style` (direct attributes are used instead)
- Doesn't split or iterate over all string-based tokens in a
string value obtained from a `[class]` binding.
This patch speeds up the following cases:
- `<div [class]>` and `<div class="..." [class]>`
- `<div [style]>` and `<div style="..." [style]>`
The overall speec increase is by over 5x.
PR Close#33336
`LFrame` stores information specifice to the current `LView` As the code
enters and leaves `LView`s we use `enterView()` and `leaveView()`
respectively to build a a stack of `LFrame`s. This allows us to easily
restore the previous `LView` instruction state.
PR Close#33178
Recently it was made possible to have a directive without selector,
which are referred to as abstract directives. Such directives should not
be registered in an NgModule, but can still contain decorators for
inputs, outputs, queries, etc. The information from these decorators and
the `@Directive()` decorator itself needs to be registered with the
central `MetadataRegistry` so that other areas of the compiler can
request information about a given directive, an example of which is the
template type checker that needs to know about the inputs and outputs of
directives.
Prior to this change, however, abstract directives would only register
themselves with the `MetadataRegistry` as being an abstract directive,
without all of its other metadata like inputs and outputs. This meant
that the template type checker was unable to resolve the inputs and
outputs of these abstract directives, therefore failing to check them
correctly. The typical error would be that some property does not exist
on a DOM element, whereas said property should have been bound to the
abstract directive's input.
This commit fixes the problem by always registering the metadata of a
directive or component with the `MetadataRegistry`. Tests have been
added to ensure abstract directives are handled correctly in the
template type checker, together with tests to verify the form of
abstract directives in declaration files.
Fixes#30080
PR Close#33131
In the post-$localize world the current locale value is defined by setting
`$localize.locale` which is then read at runtime by Angular in the provider
for the `LOCALE_ID` token and also passed to the ivy machinery via`setLocaleId()`.
The $localize compile-time inlining tooling can replace occurrences of
`$localize.locale` with a string literal, similar to how translations
are inlined.
// FW-1639
See https://github.com/angular/angular-cli/issues/15896
PR Close#33314
change the existing implementation from using
```
string.split(/\s+/);
```
to a char scan which performers the same thing.
The reason why `split(/\s+/)` is slow is that:
- `/\s+/` allocates new `RegExp` every time this code executes.
- `RegExp` scans are a lot more expensive because they are more powerful.
PR Close#33326
With Ivy the `entryComponents` array isn't necessary anymore. These changes mark it as deprecated so that it can be removed in a future version.
PR Close#33205
Prior to this fix if a map-based class or style binding wrote
its values onto an elemenent, the internal styling context would
not register the binding if the initial value as a `NO_CHANGE`
value. This situation occurs if a directive takes control of the
`class` or `style` input values and then returns a `NO_CHANGE` value
if the initial value is empty.
This patch ensures that all bindings are always registered with the
`TStylingContext` data-structure even if their initial value is
an instance of `NO_CHANGE`.
PR Close#33236
Prior to this fix, all style/class bindings (e.g. `[style]` and
`[class.foo]`) would quietly update a binding value if and when the
current binding value changes during checkNoChanges.
With this patch, all styling instructions will properly check to see
if the value has changed during the second pass of detectChanges()
if checkNoChanges is active.
PR Close#33103
LocaleID defs are not considered public API, so the property
that contains them should be prefixed with Angular's marker
for "private" ('ɵ') to discourage apps from relying on def
APIs directly.
This commit adds the prefix and shortens the name from
ngLocaleIdDef to loc. This is because property names
cannot be minified by Uglify without turning on property
mangling (which most apps have turned off) and are thus
size-sensitive.
PR Close#33212
Turns out that writing to global state is more expensive than writing to
a property on an object.
Slower:
````
let count = 0;
function increment() {
count++;
}
```
Faster:
````
const state = {
count: 0
};
function increment() {
state.count++;
}
```
This change moves all of the instruction state into a single state object.
`noop_change_detection` benchmark
Pre refactoring: 16.7 us
Post refactoring: 14.523 us (-13.3%)
PR Close#33093
Prior to this commit, all `className` inputs were not set because the runtime code assumed that the `classMap` instruction is only generated for `[class]` bindings. However the `[className]` binding also produces the same `classMap`, thus the code needs to distinguish between `class` and `className`. This commit adds extra logic to select the right input name and also throws an error in case `[class]` and `[className]` bindings are used on the same element simultaneously.
PR Close#33188
This patch introduces the `printTable()` and `printSources()`
methods to `DebugStylingContext` which can be used via the
`window.ng.getDebugNode` helpers when debugging an application.
PR Close#33179
Injectable defs are not considered public API, so the property
that contains them should be prefixed with Angular's marker
for "private" ('ɵ') to discourage apps from relying on def
APIs directly.
This commit adds the prefix and shortens the name from
ngInjectableDef to "prov" (for "provider", since injector defs
are known as "inj"). This is because property names cannot
be minified by Uglify without turning on property mangling
(which most apps have turned off) and are thus size-sensitive.
PR Close#33151
Injector defs are not considered public API, so the property
that contains them should be prefixed with Angular's marker
for "private" ('ɵ') to discourage apps from relying on def
APIs directly.
This commit adds the prefix and shortens the name from
ngInjectorDef to inj. This is because property names
cannot be minified by Uglify without turning on property
mangling (which most apps have turned off) and are thus
size-sensitive.
PR Close#33151
This change assures that data structures related to initial inputs
(ones set from static attributes) are created only once (during the
first template pass) and no additional runtime checks are done for
subsequent passes.
Additionally this commit changes the data structure used by initial inputs
on TNode - previously initial inputs for a directive were stored at the
directive index in LView. This meant that an array holding initial inputs
was relativelly big and had many null elements (as placeholders for elements,
directives, injector etc.). After the change we only create an array of a size
equal to a number of directives matched on a given TNode.
For the `directive_instantiate` benchmark it boils to allocating a 1-element
array vs. 100-element array previously.
PR Close#33195
Prior to this commit, Ivy runtime asserted that a given element is an instance of a DOM node. These asserts may not be correct in case custom renderer is used, which operates objects with a shape different than DOM nodes. This commit updates the code to avoid the mentioned checks in case procedural renderer is used.
PR Close#33156
Prior to this patch, if a map-class binding is applied directly then
that value will be incorrectly provided a sanitizer even if there is no
sanitization present for an element.
PR Close#33154
Module defs are not considered public API, so the property
that contains them should be prefixed with Angular's marker
for "private" ('ɵ') to discourage apps from relying on def
APIs directly.
This commit adds the prefix and shortens the name from
ngModuleDef to mod. This is because property names
cannot be minified by Uglify without turning on property
mangling (which most apps have turned off) and are thus
size-sensitive.
PR Close#33142
Pipe defs are not considered public API, so the property
that contains them should be prefixed with Angular's marker
for "private" ('ɵ') to discourage apps from relying on def
APIs directly.
This commit adds the prefix and shortens the name from
ngPipeDef to pipe. This is because property names
cannot be minified by Uglify without turning on property
mangling (which most apps have turned off) and are thus
size-sensitive.
PR Close#33142
Factory defs are not considered public API, so the property
that contains them should be prefixed with Angular's marker
for "private" ('ɵ') to discourage apps from relying on def
APIs directly.
This commit adds the prefix and shortens the name from
ngFactoryDef to fac. This is because property names
cannot be minified by Uglify without turning on property
mangling (which most apps have turned off) and are thus
size-sensitive.
Note that the other "defs" (ngPipeDef, etc) will be
prefixed and shortened in follow-up PRs, in an attempt to
limit how large and conflict-y this change is.
PR Close#33116
Directive defs are not considered public API, so the property
that contains them should be prefixed with Angular's marker
for "private" ('ɵ') to discourage apps from relying on def
APIs directly.
This commit adds the prefix and shortens the name from
ngDirectiveDef to dir. This is because property names
cannot be minified by Uglify without turning on property
mangling (which most apps have turned off) and are thus
size-sensitive.
Note that the other "defs" (ngFactoryDef, etc) will be
prefixed and shortened in follow-up PRs, in an attempt to
limit how large and conflict-y this change is.
PR Close#33110
Component defs are not considered public API, so the property
that contains them should be prefixed with Angular's marker
for "private" ('ɵ') to discourage apps from relying on def
APIs directly.
This commit adds the prefix and shortens the name from
`ngComponentDef` to `cmp`. This is because property names
cannot be minified by Uglify without turning on property
mangling (which most apps have turned off) and are thus
size-sensitive.
Note that the other "defs" (ngDirectiveDef, etc) will be
prefixed and shortened in follow-up PRs, in an attempt to
limit how large and conflict-y this change is.
PR Close#33088
Based on the results of the `directive_instantiate` executing host
bindings logic (in creation mode) account for ~23% of time spent in
the directive instantiation, even if a directive doesn't have host
bindings! This is clearly wastful hence a new flag.
PR Close#33102