Ensure that keyframes rules, defined within components with emulated
view encapsulation, are scoped to avoid collisions with keyframes in
other components.
This is achieved by renaming these keyframes to add a prefix that makes
them unique across the application.
In order to enable the handling of keyframes names defined as strings
the previous strategy of replacing quoted css content with `%QUOTED%`
(introduced in commit 7f689a2) has been removed and in its place now
only specific characters inside quotes are being replaced with
placeholder text (those are `;`, `:` and `,`, more can be added in
the future if the need arises).
Closes#33885
BREAKING CHANGE:
Keyframes names are now prefixed with the component's "scope name".
For example, the following keyframes rule in a component definition,
whose "scope name" is host-my-cmp:
@keyframes foo { ... }
will become:
@keyframes host-my-cmp_foo { ... }
Any TypeScript/JavaScript code which relied on the names of keyframes rules
will no longer match.
The recommended solutions in this case are to either:
- change the component's view encapsulation to the `None` or `ShadowDom`
- define keyframes rules in global stylesheets (e.g styles.css)
- define keyframes rules programmatically in code.
PR Close#42608
There were two problems with the `importProvidersFrom` function related to
`ModuleWithProviders` values:
* The public type did not accept `ModuleWithProviders` values directly.
* The implementation of `walkProviderTree` delegates collection of MWP providers
to its caller, in order for the ordering of such providers to be correct.
However, `importProvidersFrom` was not performing that collection, causing MWP
providers passed in at the top level to be dropped.
PR Close#45722
This commit moves the ModuleWithProviders type from `metadata` to `di`, avoiding
the need for `di` to reference `metadata` (in this particular case).
PR Close#45722
Add more tests verifying the following conditions:
- discovery of DI providers from exported NgModules
- forwardRef in standalone component imports
PR Close#45709
This commit changes the injectors hiearchy created during applicationBootstrap.
From now on a standalone injector (holding all the ambient providers of a
standalone component) is create as a child of the application injector.
This change alligns injectors hierarchy for bootstrapped and dynamically
created standalone components.
PR Close#45766
Using `setTimeout` in the Router navigation pipeline creates fragile and
unpredictable behavior. Additionally, it creates a new macrotask, which
would trigger an unnecessary change detection in the application.
This `setTimeout` was added in
https://github.com/angular/angular/commit/15e397816f98ec16839c30fd5c1ea01c7444fb84.
Both tests added in that commit still pass. Additionally, the comment
for _why_ the `setTimeout` was added doesn't really explain how the
described bug would occur. There has been a lot of work in the Router
since then to stabalize edge case scenarios so it's possible it existed
before but doesn't anymore.
Removing this `setTimeout` revealed tests that
relied on the navigation not completing. For example, the test suite did
not have a route which matched the redirect, but the test passed because
it ended before the redirect was flushed, so the `Router` never threw an
error. Similar situations exist for the other use of `setTimeout` in the Route
(the one in the location change listener).
There were no other failures in TGP other than incorrectly written
tests.
BREAKING CHANGE:
When a guard returns a `UrlTree`, the router would previously schedule
the redirect navigation within a `setTimeout`. This timeout is now removed,
which can result in test failures due to incorrectly written tests.
Tests which perform navigations should ensure that all timeouts are
flushed before making assertions. Tests should ensure they are capable
of handling all redirects from the original navigation.
PR Close#45735
This commit moves standalone component scoping into the closures for
`directiveDefs` and `pipeDefs` in JIT mode. This is necessary to support
recursive standalone components, which necessarily use a `forwardRef` within
their import cycle. Previously, the JIT compiler for standalone components
attempted immediate `forwardRef` resolution, resulting in infinite recursion.
PR Close#45720
Before standalone, everything that could appear in an NgModule's `imports`
was relevant to DI, and needed to be emitted in the `imports` of the
generated `InjectorDef` definition. With the introduction of standalone
types, NgModule `imports` can now contain components, directives, and pipes
which are standalone. Only standalone components need to be included in
the `imports` of the generated injector definition - directives and pipes
have no effect on DI. Having them present doesn't cause any errors in the
runtime (they're filtered out by the injector itself) but it does prevent
tree-shaking.
With this commit, the generation of `InjectorDef` now filters the `imports`
to exclude directives and pipes as much as possible. It's not _always_
possible because an expression in `imports` may pull in both a directive and
a `ModuleWithProviders` reference, and we have no way of referencing just
the MWP part of that expression. Therefore this is an optimization, not a
rule of `InjectorDef` compilation.
PR Close#45701
Previously, the NgModule handler would resolve the `imports` field as one
unit, producing an array of `Reference`s. With this refactoring, if
`imports` is a literal array, each individual element will be resolved
independently. This will allow filtering in the future at the element level,
since there will be a separate `ts.Expression` for each individual element.
PR Close#45701
This commit updates the `ForeignFunctionResolver` used by the NgModule
handler to resolve `ModuleWithProvider` types. Previously, this resolver
returned the NgModule `Reference` directly, but there are two problems with
this:
* It's not completely accurate, as the expression returned by the MWP call
will not return the NgModule at runtime.
* We need the ability to distinguish the MWP call itself from an ordinary
NgModule reference in future optimizations.
PR Close#45701
This commit reworks the partial evaluation system's concept of a
ForeignFunctionResolver. Previously, resolvers were expected to return a
`ts.Expression` which the partial evaluator would continue evaluating,
eventually returning a value.
This works well for "transparent" foreign functions like `forwardRef`,
but for things like `ModuleWithProviders` it breaks down, because the
desired resolution value (the NgModule `Reference`) is _not_ the "correct"
evaluation of the function call.
To support better FFR implementations, this commit refactors the FFR system
so that resolvers operate on the `ts.CallExpression` instead, and are
given a callback to resolve further expressions if needed. If they cannot
resolve a given call expression, they have an `unresolvable` value that they
can return to indicate that.
PR Close#45701
Adds getState to LocationStrategy interface as it suppose to be the place to control all window.location interactions.
BREAKING CHANGE:
Adds new required class member that any implementors of the LocationStrategy will need to satisfy.
Location does not depend on PlatformLocation anymore.
PR Close#45648
Similarly to the symmetry being strengthened between children and loadChildren,
a new loadComponent property will be introduced as the asynchronous version of component.
This will allow for direct single-component lazy loading:
```
{path: 'lazy/a', loadComponent:
() => import('./lazy/a.component').then(m => m.ACmp)},
{path: 'lazy/b', loadComponent:
() => import('./lazy/b.component').then(m => m.BCmp)},
```
This option requires that the component being loaded is standalone and
is implemented as a runtime check.
Other notes:
* Components are not loaded until all guards and resolvers complete.
* Loading the component is included in the function passed to the router
preloading strategy
* `RouteConfigLoadStart` and `RouteConfigLoadEnd` events emit at the
start and end of the component loading
* `CanLoad` guards _do not_ apply to `loadComponent`. `canActivate`
should be used instead, just like you would do if it were simply
`component` instead.
PR Close#45705
This commit expands the `LoadChildrenCallback` to accept returning `Routes`
in addition to the existing `NgModule` type. In addition, it adds a
check to ensure these loaded routes all use standalone components.
The components must be standalone because if they were not,
we would not have the required `NgModule` which the component is declared in.
Existing API:
```
{path: 'lazy/route', loadChildren: import('./lazy').then(m => m.LazyModule)}
@NgModule({
imports: [
ExtraCmpModule,
RouterModule.forChild([
{path: 'extra/route', component: ExtraCmp},
]),
],
})
export class LazyModule {}
```
The new API for lazy loading route configs with standalone components
(no NgModule) is to expand `loadChildren` to allow returning simply a `Routes` array.
```
// parent.ts
{
path: 'parent',
loadChildren: () => import('./children').then(m => m.ROUTES),
}
// children.ts
export const ROUTES: Route[] = [
{path: 'child', component: ChildCmp},
];
```
Note that this includes minimal documentation updates. We need to
include a holistic update to the documentation for standalone components
in the future that includes this feature.
PR Close#45700
This commit adds 2 integration apps to verify the `bootstrapApplication` API behavior as well as keep track of the bundle size and retained symbols (tree-shaking).
PR Close#45674
This commit implements the `bootstrapApplication` function that allows bootstrapping an application and pass a standalone component as a root component.
PR Close#45674
The localize primary entry-point (used at runtime in application code)
indirectly loads from the compiler package for computing message ids.
The compiler package has a couple of constants which cannot be DCE-ded/
tree-shaken due to side-effect reliance that is detected by Terser.
We fix these constants to be three-shakable. Note that another issue
technically would be that the compiler package has a side-effect call
for `publishFacade` (for JIT), but that invocation is marked as pure by
the Angular CLI babel optimization pipeline. So this results is no
unused code currently but is risky and should be addressed in the future.
PR Close#45405
This commit addresses two issues:
* The init entry-point currenly access code from another entry-point
using relative imports, resulting in code to be duplicated.
* The init types are now bundled as part of the ng_package APF rule.
There is an API extractor bundling issue with global module
augmentations.
API extractor does not properly handle module augmentation. We need to disable
dts bundling for this entry-point to ensure `$localize` remains globally accessible
for users. This is an option in the `ng_package` rule.
Note that this worked before because `localize/init` was a `ts_library` that did not
have its types bundled.
As part of this change, the `MessageId` and `TargetMessage` exports are
also made public. The localize exported functions rely on these types but
they were not exported.
Related to types, an exception is added for three private exports from the primary
entry-point so that they will show up in the API golden. These private
exports are re-exposed publicly in the init entry-point but no golden
would capture them due to the private symbol prefix. One might wonder
why the symbols are not guarded in the init golden. The reason is that
goldens never inline signatures from cross-entry-points/packages to avoid
duplication.
Lastly, the i18n integration test golden had to be updated because the
polyfills bundle increased slightly. After thorough and time-consuming
investigation, this mostly happens due to different mangle identifies
being used (the input code changed --> so the mangling determinism)
Size before this change:
```
SUCCESS: Commit undefined uncompressed runtime did NOT cross size threshold of 500 bytes or >1% (expected: 929, actual: 926).
SUCCESS: Commit undefined uncompressed main did NOT cross size threshold of 500 bytes or >1% (expected: 124544, actual: 124660).
SUCCESS: Commit undefined uncompressed polyfills did NOT cross size threshold of 500 bytes or >1% (expected: 34530, actual: 34641).
```
After:
```
SUCCESS: Commit undefined uncompressed runtime did NOT cross size threshold of 500 bytes or >1% (expected: 929, actual: 926).
SUCCESS: Commit undefined uncompressed main did NOT cross size threshold of 500 bytes or >1% (expected: 124544, actual: 124650).
FAIL: Commit undefined uncompressed polyfills exceeded expected size by 500 bytes or >1% (expected: 34530, actual: 35252).
```
Inspecting/comparing without mangling shows that the new changes would
actually result in a bundle reduction (potentially visible with
gzip/brotli):
```
➜ Desktop stat -f%z master-nomangle.js
101357
➜ Desktop stat -f%z with-changes-nomangle.js
101226
```
PR Close#45405
The platform-server init entry-point imported code from another
entry-point using a relative import. This resulted in the code to be
bundled into the `init` entry-point as well. This has no breaking
impact but resulted in a little code duplication that we should
clean up.
PR Close#45405
Adds a little golden test for the new `types_bundle` rule that ensures
the rule works at a general level. This rule will be useful for non-APF
ESM packages like the Angular compiler-cli (for which we also want to
bundle types to make them compatible with TypeScripts ESM type
resolution)
PR Close#45405
Speeds up the dev-turnaround by only bundling types when packaging. Currently
bundling occurs for all the `ng_module` targets in devmode.
This has various positive benefits:
* Avoidance of this rather slower operation in development
* Makes APF-built packages also handle types for `ts_library` targets consistently.
* Allows us to ensure APF entry-points have `d.ts` _always_ bundled (working with ESM
module resolution in TypeScript -- currently experimental)
* Allows us to remove the secondary `package.json` files from APF (maybe APF v14? - seems
low-impact). This would clean-up the APF even more and fix resolution issues (like in Vite)
PR Close#45405
This commit reorganizes the tests around the EnvironmentInjector and its use
for standalone injectors, and adds a number of new test cases.
PR Close#45687
This commit implements the `StandaloneFeature` which provides for the
creation of standalone injectors, for those components which need them. The
feature-based implementation ensures the machinery for standalone injectors
is properly tree-shakable.
PR Close#45687
This commit refactors `importProvidersFrom` to support pulling providers
from the dependencies of a standalone component, in addition to NgModules.
Tests will be added in a future commit when standalone components can be
created without calling private APIs.
PR Close#45687
This commit exposes the `standalone` flag on `@Directive`, `@Component`, and
`@Pipe`, effectively making standalone components a part of Angular's public
API. As part of this operation, it also implements JIT compilation for
standalone types.
Standalone types are Angular-decorated types which act as their own
"declarations", where they would otherwise be declared in an NgModule.
Marking an Angular type as standalone means that it can be used directly in
other standalone components and in NgModules, without needing an associated
NgModule to depend on it. In the case of a standalone component, template
dependencies which would otherwise be specified by an NgModule are instead
specified directly on the component itself, via the `imports` field. Other
standalone types can be imported, as well as NgModules.
PR Close#45687
This commit extracts the `importProvidersFrom` function and associated
machinery into a separate file, as opposed to being colocated with
`R3Injector`. Separating these functions will mitigate potential future
circular dependencies as `importProvidersFrom` starts being used in
different parts of the codebase.
PR Close#45687
add the ariaCurrentWhenActive input to the RouterLinkActive directive so that
users can easily set the aria-current property to their active router
links
resolves#35051
PR Close#45167
DEPRECATED:
The `resolver` argument of the `RouterOutletContract.activateWith` function and the `resolver` field of the `OutletContext` class are deprecated. Passing component factory resolvers are no longer needed. The `ComponentFactoryResolver`-related symbols were deprecated in `@angular/core` package since v13.
PR Close#45597
The current API for `activateWith` uses the deprecated
`ComponentFactoryResolver`. The replacement for this is to use
`EnvironmentInjector`. That is, instead of
```
const factory = componentFactoryResolver.resolveComponentFactory(component);
location.createComponent(factory, location.length, injector);
```
the replacement would be
```
location.createComponent(
component, {index: location.length, injector, environmentInjector});
```
PR Close#45597
Currently, the only way to specify new providers for a `Route` and the
children is to create a new `NgModule` with those providers and use the
`loadChildren` feature. This is pretty confusing and a wholly indirect
way of accomplishing this task. With this commit, developers will be
able to specify a list of providers directly on the `Route` itself.
These providers will apply the that route and its children.
This feature was inspired by the upcoming standalone components feature.
This ties in there because, as mentioned before, the prior art for lazy
loading configs was to load an `NgModule`. This loaded module contained
new route configs _and_ could specify new providers. Separating those
two concepts, there should be a way to load _just_ some new routes, but
there should also be a way to specify new providers as well (something
you could do in the `NgModule` world and now will be able to do in the
world without any `NgModule` through this feature).
PR Close#45673
Previously, the following code would fail to compile:
```
let form: FormGroup<{email: FormControl<string | null>}>;
form = fb.group({
email: ['', Validators.required]
});
```
This is because the compiler was unable to properly infer the inner type of `ControlConfig` arrays in some cases. The same issue applies to `FormArray` as well under certain circumstances.
This change cleans up the `FormBuilder` type signatures to always use the explicit Element type, and to catch `ControlConfig` types that might fall through.
PR Close#45684
Servers always decode + as a space, which is undesirable when one
actually wants to query for a plus.
BREAKING CHANGE:
Queries including + will now actually query for + instead of space.
Most workarounds involving custom codecs will be unaffected.
Possible server-side workarounds will need to be undone.
Fixes angular#11058
PR Close#45111
This commit bundles tests for standalone components that are possible after
previous implementation commits. Most new tests are compliance tests, but
a test is also included to validate that the template type-checking system
can work with standalone components as well.
PR Close#45672
This commit adds a type field to .d.ts metadata for directives, components,
and pipes which carries a boolean literal indicating whether the given type
is standalone or not. For backwards compatibility, this flag defaults to
`false`.
Tests are added to validate that standalone types coming from .d.ts files
can be correctly imported into new standalone components.
PR Close#45672
This commit propagates the `isStandalone` flag for a component, directive,
or pipe during partial compilation of a standalone declaration. This flag
allows the linker to properly process a standalone declaration that it
encounters.
PR Close#45672
Standalone component scopes were first implemented in the
`ComponentDecoratorHandler` itself, due to an assumption that "standalone"
allowed for a localized analysis of the component's dependencies. However,
this is not strictly true. Other compiler machinery also needs to understand
component scopes, including standalone component scopes. A good example is
the template type-checking engine, which uses a `ComponentScopeReader` to
build full metadata objects (that is, metadata that considers the entire
inheritance chain) for type-checking purposes. Therefore, the
`ComponentScopeReader` should be able to give the scope for a standalone
component.
To achieve this, a new `StandaloneComponentScopeReader` is implemented, and
the return type of `ComponentScopeReader.getScopeForComponent` is expanded
to express standalone scopes. This cleanly integrates the "standalone"
concept into the existing machinery.
PR Close#45672
This commit adds an emit for standalone components of the
`StandaloneFeature`, which will support creation of standalone injectors and
any other mechanisms necessary for standalone component functionality at
runtime.
Using a feature allows for standalone functionality to be tree-shaken in
applications that aren't using them.
PR Close#45672
This commit expands on the unified dependency tracking in the previous
commit and adds tracking of NgModule dependencies. These are not used for
standard components, but are emitted for standalone components to allow the
runtime to roll up providers from those NgModules into standalone injectors.
PR Close#45672
Previously, the compiler tracked directives and pipes in template scopes
separately. This commit refactors the scope system to unify them into a
single data structure, disambiguated by a `kind` field.
PR Close#45672
Previously, the compiler would represent template dependencies of a
component in its component definition through separate fields (`directives`,
`pipes`).
This commit refactors the compiler/runtime interface to use a single field
(`dependencies`). The runtime component definition object still has separate
`directiveDefs` and `pipeDefs`, which are calculated from the `dependencies`
when the definition is evaluated.
This change is also reflected in partially compiled declarations. To ensure
compatibility with partially compiled code already on NPM, the linker
will still honor the old form of declaration (with separate fields).
PR Close#45672
`PipeSymbol` contains logic to detect changes in the public API surface of
pipes, which includes the pipe name. However, the pipe handler inadvertently
uses the pipe class name instead of the actual pipe name to initialize the
`PipeSymbol`, which breaks incremental compilation when pipe names change.
There is a test which attempts to verify that this logic is working, but the
test actually passes for a different reason. The test swaps the names of 2
pipes that are both used in a component, and asserts that the component is
re-emitted, theoretically because the public APIs of the pipes is changed.
However, the emit order of the references to the pipes depends on the order
in which they match in the template, which changes when the names are
swapped. This ordering dependency is picked up by the semantic dependency
tracking system, and is what actually causes the component to be re-emitted
and therefore the pipe test to pass in spite of the bug with name tracking.
This commit fixes the `PipeSymbol` initialization to use the correct pipe
name. The test is still flawed in that it's sensitive to the ordering of
pipe emits, but this ordering is due to change soon as a result of the
standalone components work, so this issue will be resolved in a future
commit.
PR Close#45672
BREAKING CHANGE:
The type of `component` on `ActivatedRoute` and `ActivatedRouteSnapshot`
includes `string`. In reality, this is not the case. The component
cannot be anything other than a component class.
PR Close#45625
This commit updates one of the styling tests to reset perf counters, making it order-independent and non-flaky (previously the test got random failures depending on whether there are other tests invoked before).
PR Close#45670
This wasn't exactly possible before because the `RouterConfigLoader` was
not an Injectable so there wasn't a straightforward way to share
information between `ApplyRedirects` and the preloader. They each had
their own implementation so they needed to store the values on the
`Route` so they both had access to them. I imagine this was the case
because trying to inject `Router` (to get access to the events) into the
preloader would have caused a circular dependency.
This refactor co-locates the loading details with the loader itself
rather than leaking implementation into the public route config and
mutating the object in an awkward way. This also promotes
`RouterConfigLoader` to a proper `Injectable` so data can be shared
throughout the system.
PR Close#45656