This commit updates the `node` engines range for all Angular
framework packages to:
* No longer support NodeJS v12 `< 12.20`. This is done because APF v13
uses package export patterns which are only supported as of v12.20.
https://nodejs.org/api/packages.html#packages_subpath_patterns.
* Allows for the latest v16 NodeJS versions. This matches with the CLI
which added NodeJS v16 support with https://github.com/angular/angular-cli/pull/21854.
We already limit this to `>= v16.10.0` in preparation to only
supporting the LTS minors of Node v16.
BREAKING CHANGE: NodeJS versions older than `v12.20.0` are no longer
supported due to the Angular packages using the NodeJS package exports
feature with subpath patterns.
PR Close#43740
In addition to the existing `exports` conditional exports we ship
as part of APF v13, we want to expose the non-bundled ESM2020 output
through the `esm2020` conditional name. Additionally we will expose
the flat ES2020 files through the `es2020` conditional field, allowing
consumers (like the CLI) to prioritize certain formats.
e.g. consider the case with RXJS where it currently defaults to
the ESM5 output. The CLI could now set `es2015` as the conditional
to leverage the ES2015 output of RXJS. This unveils a problem though
since this would also mean that `ES2015` output of the framework Angular
packages would be used instead of the available ES2020 output. Here is
the additional `es2020` conditional helpful as it allows the CLI to
prioritize `es2020`, fallback to `es2015` and lastly fallback to `default`.
if none do match for a certain package.
PR Close#43740
DEPRECATION:
In ViewEngine, [JIT compilation](https://angular.io/guide/glossary#jit) required special providers (like `Compiler`, `CompilerFactory`, etc) to be injected in the app and corresponding methods to be invoked. With Ivy, JIT compilation takes place implicitly if the Component, NgModule, etc have not already been [AOT compiled](https://angular.io/guide/glossary#aot). Those special providers were made available in Ivy for backwards-compatibility with ViewEngine to make the transition to Ivy smoother. Since ViewEngine is deprecated and will soon be removed, those symbols are now deprecated as well:
- `ModuleWithComponentFactories`
- `Compiler`
- `CompilerFactory`
- `JitCompilerFactory`
- `NgModuleFactory`
Important note: this deprecation doesn't affect JIT mode in Ivy (JIT remains available with Ivy).
PR Close#43710
Bumps the minimum required TypeScript version to 4.4.2 and removes the integration tests for 4.1, 4.2 and 4.3.
BREAKING CHANGE:
TypeScript versions older than 4.4.2 are no longer supported.
PR Close#43642
Currently when `ngc-wrapped` runs in external/consumer workspaces, like
in the Angular Components project, the `ngc-wrapped` binary relies on
the linker due to the patched module resolution in `rules_nodejs` no
longer being default. The reliance on the linker of `rules_nodejs` is
problematic for workers as the required `node_modules` are not
re-linked for every build. This was previously not an issue before the
APF v13 changes because the `compiler-cli` module was loaded only once
through an import statement.
As of APF v13, the compiler-cli module is loaded dynamically for every
build. This dynamic import can then break as the worker does not
initially load the compiler-cli module when becoming online. Instead,
the module is loaded on the first build where the node modules might not
be linked properly anymore (due to e.g. other targets running at the same time).
We fix thi issue by doing the following things:
1. Enabling the patched module resolution for consumer/external
workspaces. This would match how we use ngc-wrapped inside FW as
well.
2. Caching the compiler CLI module. Instead of re-fetching the module
through dynamic imports for every build (in a worker), we should use
the cached version. This is semantically the same as with APF v12
where a single import statement at file top-level was used.
Technically, NodeJS should cache the module, but it doesn't hurt
directly caching it as the module resolution will be patched by
`rules_nodejs` and could perform unnecessary tasks.
PR Close#43690
This commit removes the option to enable the VE language service and removes the VE bundle entirely.
It also updates the name of the ivy bundle to "language-service.js" now that there is only one.
PR Close#43723
Previously, all asset-groups from `ngsw-config.json` were processed in
parallel. For each asset-group, we retrieved all files for the current
build, filtered out files that were already matched by other
asset-groups, determined which of the remaining files belonged to the
current asset-group and generated entries for the `ngsw.json` manifest.
This process was susceptible to race conditions when there were files
that would be matched by multiple asset-groups. This made the generation
of the `ngsw.json` manifest non-deterministic and violated the rule that
each file would belong to the first asset-group that matched it (based
on the asset-groups' order of appearance in `ngsw-config.json`), thus
leading to broken ServiceWorker behavior.
This commit fixes it by ensuring that the generation process is
deterministic and that asset-groups are processed in the proper order.
NOTE 1:
The generation process has been broken since the beginning, but we have
only noticed this recently. This is possibly related to the CLI's
switching from a virtual file system host (which has more consistent
timing characteristics) to the Node.js built-in `fs.promises` in
angular/angular-cli@d3bc530c10.
NOTE 2:
This commit also ensures that files in the `ngsw.json` hash-table are in
alphabetic order. Previously, the files were added to the hash-table in
blocks corresponding to each asset-group.
This change is not necessary (i.e. the order of keys in the hash-table
makes no difference in behavior), but it makes it easier to scan for a
file (for example, for debugging purposes).
PR Close#43679
This commit introduces a new `SwUpdate#versionUpdates` observalbe, which provides more granular
information about Service Worker version updates than the already existing `SwUpdate#available`
observable.
The new events emitted by `SwUpdate#versionUpdates` basically add the possibility for application to
get notified if a new version is available on the server (not yet downloaded) and if an installation
of a new version failed.
Closes#39840
DEPRECATED: The `SwUpdate#availalbe` observable is deprecated.
The new `SwUpdate#versionUpdates` observable provides the same information and more. Therefore, it
is possible to rebuild the same behavior as `SwUpdate#availalbe` using the events emitted by
`SwUpdate#versionUpdates` and filtering for `VersionReadyEvent` events.
As a result, the `SwUpdate#availalbe` observable is now redundant.
PR Close#43668
Previously `activateUpdate` and `checkForUpdate` returned `Promise<void>`, which did not provide any
information of the actual outcome of the operation. Developers needed to subscribe to a
corresponding observable to obtain the outcome.
With this commit `SwUpdate#activateUpdate` will return `Promise<boolean>` which resolves to `true` if
an update was activated, to `false` if no new version is available and rejects in case of any error.
`SwUpdate#checkForUpdate` also returns a `Promise<boolean>` which resolves to `true` if an update is available, to `false` if no update was found and rejects in case of any error.
Closes#39840
BREAKING CHANGE: The return type of `SwUpdate#activateUpdate` and `SwUpdate#checkForUpdate` changed to `Promise<boolean>`.
Although unlikely, it is possible that this change will cause TypeScript type-checking to fail in
some cases. If necessary, update your types to account for the new
return type.
DEPRECATED: The `SwUpdate#activated` observable is deprecated.
The `SwUpdate#activated` observable only emits values as a direct response to calling
`SwUpdate#activateUpdate()` and was only useful for determining whether the call resulted in an
update or not. Now, the return value of `SwUpdate#activateUpdate()` can be used to determine the
outcome of the operation and therefore using `SwUpdate#activated` does not offer any benefit.
PR Close#43668
Previously, when a router-outlet is conditionally shown with an ngIf, and a sub-route was re-attached
via a custom RouteReuseStrategy, router-outlet would try to mount a destroyed component into the view
if the router-outlet is destroyed and re-initialized.
This commit fixes it by unsetting context.attachRef when router-outlet is destroyed, so when the
router-outlet is being initialized again, it no longer sees an attachRef that it needs to mount to the
view.
Fixes#43696
PR Close#43697
Fixes a unit test that now fails, because rethrowing errors is enabled by default. The problem is that we're checking the behavior of a component that throws during `ngOnDestroy`, but since the `resetTestingModule` call itself throws, the test is considered as failing.
PR Close#43714
Refs #42966.
Previously, checking a template with the syntax:
```html
<div>{{ foo() ?? 'test' }}</div>
```
Where `foo()` returns a nullable value:
```typescript
@Component(/* ... */)
class TestCmp {
foo: (): string | null => null;
}
```
Would always log a nullish coalescing not nullable warning. This is because [`getSymbolOfNode(node.left)`](https://github.com/angular/angular/blob/fe691935091aaf7090864c8111a15f7cc7e53b6c/packages/compiler-cli/src/ngtsc/typecheck/extended/checks/nullish_coalescing_not_nullable/index.ts#L30) would return the [symbol of the function (`foo`)](https://github.com/angular/angular/blob/fe691935091aaf7090864c8111a15f7cc7e53b6c/packages/compiler-cli/src/ngtsc/typecheck/src/template_symbol_builder.ts#L536-L538) rather than the symbol of its returned value (`foo()`). Fixed this by getting the symbol for the whole expression's span, rather than just the function receiver.
Also made some minor refactorings to `template_symbol_builder` to make a similar change to safe method calls. This behavior was originally for the language service in order to handle quick info, as the user highlighting a function name would actually apply to the entire expression. This is no longer true as the language service will correctly request the type from the function rather than the `Call` expression, so these hacks are not necessary anymore. This broke two existing test cases of exactly this behavior which were easily updated. Also added a test to the language service to confirm that it is not broken by this change.
PR Close#43572
`source-map` is only used during testing and therefore there is no need to list it as a dependency.
(cherry picked from commit ae7dc75bdce713acaa1658734791317a274982da)
PR Close#43644
Since the `destroyAfterEach` teardown behavior is enabled by default now, existing tests that depended on the old behavior can start to fail. These changes add an automated migration that explicitly adds `destroyAfterEach: false` to existing tests.
The migration works by looking for `initTestEnvironment` calls across the entire app and adding the flag to them. If no calls were found, the migration will add the flag to all `configureTestingModule` and `withModule` calls instead.
PR Close#43353
NgModule factories are obsolete with Ivy and most of the operations can already be performed with NgModule classes without retreieving corresponding factories. NgModule factories were useful to generate an `NgModuleRef` (via `NgModuleFactory.create` method). This commit adds a new function to create an instance of the `NgModuleRef` class without having the need to create a factory first.
PR Close#43580
This commit adds a new function called `getNgModuleById` to the public API surface of the framework. The `getNgModuleById` function allows to retrieve loaded NgModule class by id (specified via `@NgModule.id`). The function is a replacement for the `getModuleFactory` function.
DEPRECATION:
The `getModuleFactory` function is deprecated in favor of the `getNgModuleById` one. With Ivy it's possible to work with NgModule classes directly, without retrieving corresponding factories, so the `getNgModuleById` should be used instead.
PR Close#43580
When compiling your application using the AOT compiler, your templates
are type-checked according to a certain strictness level. Before Angular 9
there existed only two strictness levels of template type checking as
determined by [the `fullTemplateTypeCheck` compiler option](guide/angular-compiler-options).
In version 9 the `strictTemplates` family of compiler options has been
introduced as a more fine-grained approach to configuring how strict your
templates are being type-checked.
The `fullTemplateTypeCheck` flag is being deprecated in favor of the new
`strictTemplates` option and its related compiler options. Projects that
currently have `fullTemplateTypeCheck: true` configured can migrate to
the following set of compiler options to achieve the same level of
type-checking.
```json
{
"angularCompilerOptions": {
"strictTemplates": true,
"strictInputTypes": false,
"strictNullInputTypes": false,
"strictAttributeTypes": false,
"strictOutputEventTypes": false,
"strictDomEventTypes": false,
"strictDomLocalRefTypes": false,
"strictSafeNavigationTypes": false,
"strictContextGenerics": false,
}
}
```
PR Close#43224
The `@angular/core` migrations are currently published as CommonJS and also not bundled. Schematics, of which migrations are a type, are currently required to be CommonJS modules due to the Schematics Runtime not yet supporting ESM-based schematics. To ensure that the migration files are loaded as CommonJS modules, a nested `package.json` file has been introduced within the `schematics` directory of the package to set the `type` field for all containing JavaScript files as CommonJS. Since the migrations are also not currently bundled and the `devmode` output used to build the migrations will replace all relative imports with fully-qualified module specifiers, an additional `exports` entry must be added to allow the fully-qualified module specifiers to correctly resolve. If `devmode` did not change the relative imports the additional entry would not be needed. Bundling would also remedy the situation and is the long-term path, especially once the migrations are converted to ESM. Additional followup changes should investigate bundling each migration. The additional `exports` entry should be removed if either `devmode` behavior is changed or the migrations are bundled.
PR Close#43657
Currently, migrations and schematics must be in CommonJS format. However, framework packages will only be ESM from v13 and onward. To support this configuration, dynamic import expressions are now used to load `@angular/compiler-cli` and its new secondary entry point `@angular/compiler-cli/private/migrations`. Dynamic imports within Node.js allow the `@angular/core` migrations’ CommonJS code to load ESM code. Unfortunately, TypeScript will currently, unconditionally down-level dynamic import into a require call. `require` calls cannot load ESM code and will result in a runtime error. To workaround this, a Function constructor is used to prevent TypeScript from changing the dynamic import. Once TypeScript provides support for keeping the dynamic import this workaround can be dropped and replaced with a standard dynamic import. Due to the use of the dynamic import, a reference to the dynamically loaded modules must now be passed to all locations that use values from the modules.
PR Close#43657
The Router code currently has special-case handling around when and how
the internal state is reset. Specifically, it only resets the internal
tracking of the state when an error is thrown, which does not happen
when guards reject or resolvers return `EMPTY`. Other than the
navigation URL not matching a config, guards rejecting would be the main
cause of a navigation being turned down.
This change updates the router code to always reset the internal state
in the same way, regardless of the reason for navigation cancellation.
In the end, this will only affect _very_ specific use-cases with
`UrlHandlingStrategy`. Because the internal state is not updated until
the end of the transition pipe, the state reset generally doesn't do
anything at all. However, because the `rawUrlTree` is reset by calling
`urlHandlingStrategy.merge` with the _attempted_ `rawUrl` that failed,
the resulting browser URL reset could be different than before (but will
now be consistent with how the URL is reset in other scenarios, like a
URL not matching a `Route` config).
PR Close#43651
Internally, g3 code still uses the `loadChildren: string` syntax. We
need to continue to provide this functionality with an internal patch.
This change makes that patch easier by only touching stub files that
support the `loadChildren: string` (other than `router_config_loader`).
PR Close#43660
This commits sets the JS target for all command line tools to
NodeJS v12. ESbuild will automatically downlevel the ES2020 features
we currently use to make them compatible with NodeJS v12 <-> ES2019.
ES2020 is the prodmode output, but we still support Node v12 so
there needs to be some downleveling for now.
Note: This is a separate commit because initially the target was
set to Node v14 to match up with the prodmode Bazel output.
PR Close#43431
Similar to the other private entry-points we have added for localize,
bazel or the migrations, we should expose the tooling code through
a dedicated private export. This will make the compiler-cli exports
more consistent and it will become easier for the CLI to export
necessary code.
PR Close#43431
Currently, some tests in the `compiler-cli/integrationtest` package fail
on Windows because there are spec files which are not Bazel-generated.
When Bazel runs these tests on Windows, the spec file is resolved to
the actual source file (since there is no runfile symlinking/sandboxing).
This breaks the execution of the CJS spec file since it resides in th
`packages/compiler-cli` source folder which has a `package.json` set to
`type: module`.
We fix this by adding a `package.json` file for the integration test
folder and setting `module` to `commonjs`.
PR Close#43431
With the APF v13 package output, deep files can no longer be imported.
Since we do not intend to bundle the compiler into the compiler-cli, we
need to switch all deep imports to the primary entry-point.
PR Close#43431
Updates the dynamic-compiler test to be compatible with the APF v13.
As of v13, the packages no longer come with metadata.json files and
now need to be processed with the babel linker plugin. This commit
sets up the linker plugin, and switches away from the deprecated
systemjs approach to a simpler rollup code-splitting variant.
PR Close#43431
In the current Bazel setup, we run CommonJS as devmode output, and ESM
for prodmode output. This means that consumers of the
`@angular/bazel` package will end up using the prodmode-built ESM
package of the compiler-cli. This commit adds interop logic to be able
to load the compiler-cli as strict ESM package.
We cannot switch devmode to ESM, as this would require some changes
in `rules_nodejs` and potentially the reduction of both output flavors
into a single one (which is a future project anyway). This is out of
scope for now and inside g3, there is still devmode output as well.
PR Close#43431
Ngcc relies on cluster for distributing work. The master controller
sends messages to the workers as soon as the worker becomes `online`.
The online event is sent as part of the NodeJS cluster logic itself.
This does not work well because technically `online` could emit before the
worker started listening (this seems to be case now with ESM as the
imports are loaded in a way where `online` emits too early; before the
worker actually listens for messages).
We fix this by explicitly notifying the master when the worker
is ready for retrieving IPC messages/or tasks. This is more safe
anyway as it's not clearly specified when `online` emits.
PR Close#43431
Given that we ship all of compiler-cli and localize in ESM
mode now, we need to use a ESM compatible version of Yargs.
The latest version seems ESM compatible but with some small
API changes. This commit updates Yargs and updates the command
line option code to use the new API.
PR Close#43431
Updates the lock file resolution logic in ngcc to work with ESM output.
The compiler-cli is now shipped in bundles, so the actual module resolution
needs to stay to keep the lock file path consistent regardless of where the
lock file code is bundled into. The ngcc integration test needs to be updated
though since the `ngcc` entry-point will always reside in the `bundles/` directory
now.
It has been considered using the top-level `package.json` of the compiler-cli
package, but that caused problems in tests down the line because the ngcc
tests only have the `@angular/compiler-cli/ngcc/...` targets linked into
the node modules. It's not worth changing this and reworking tests if ngcc
is going away in the future anyway (+ it has been like that before!).
PR Close#43431
Switches the compiler-cli usage of `__filename` to `import.meta.url`
when ESM bundles are generated. Unfortunately we cannot start using
only `import.meta` yet as we still build and run all code in Angular
in CommonJS module output for devmode tests.
This commit also fixes various instances where a jasmine spy was applied on
a namespace export that will break with ES module (and the interop for
CommonJS output). We fix these spies by using a default import.
PR Close#43431
Removes the remaining usages of dynamic require statements in the
package output. Since we declare all shipped packages as strict ESM,
we cannot use dynamic require statements anymore. This commit switches
these usages to actual `import` statements.
Note: Tsickle continues to remain an optional dependency since bundling
does not work with its UMD package output. Also tsickle is rarely used by
consumers, if at all, so bundling does not really provide any significant
value. To continue keeping tsickle optional (since it's still needed by the
`annotateForClosureCompiler` option which is also respected in ngtsc), we
pass-through a tsickle instance as a parameter to `main`. This allows us to
keep the compile functions synchronous without having to refactor the majority
of the watch compilation code, and majority of tests for ngc, ngtsc.
Consumers (like the `ngc` bin entry-point) can then load tsickle based on their
module format. e.g. tsickle can be imported through `require` to keep everything
sync, but in ESM, the dynamic import can be used beforehand to pass `tsickle` to
the `main` function. We can revisit this in the future but for now this does the
trick without exceeding the scope of this commit..
PR Close#43431
As outlined in the previous commit which enabled the `esModuleInterop`
TypeScript compiler option, we need to update all namespace imports
for `typescript` to default imports. This is needed to allow for
TypeScript to be imported at runtime from an ES module.
Similar changes are needed for modules like `semver` where the types incorrectly
suggest named exports that will not exist at runtime when imported from ESM.
This commit refactors all imports to match with the lint rule we have
configured in the previous commit. See the previous commit for more
details on why certain imports have been changed.
A special case are the imports to `@babel/core` and `@babel/types`. For
these a special interop is needed as both default imports, or named
imports break the other module format. e.g default imports would work
well for ESM, but it breaks for CJS. For CJS, the named imports would
only work, but in ESM, only the default export exist. We work around
this for now until the devmode is using ESM as well (which would be
consistent with prodmode and gives us more valuable test results). More
details on the interop can be found in the `babel_core.ts` files (two
interops are needed for both localize/or the compiler-cli).
PR Close#43431
Enables the `esModuleInterop` for all TypeScript compilations in the
project. This allows us to emit proper ESM-compatible code. e.g.
consider the following import:
```ts
import * as ts from 'typescript';
```
This import currently will break at runtime in NodeJS because the
`typescript` package is not shipping ESM. It's still a CommonJS module.
ES modules are able to import from `typescript` though, using an import
statement as above, but everything in `module.exports` is being exposed
as the `default` named export. TypeScript at runtime does not have any
other named exports, so for actual ESM compatibility, all of our imports
need to be switched to:
```
import ts from 'typescript';
```
The `esModuleInterop` option allows this to work even though the
`d.ts` file of TS currently suggests that there are _only_ named exports.
The TypeScript language service will now suggest the correct import form as
shown above. It doesn't enforce that unfortunately, but this commit also
adds a lint rule that enforces certain patterns so that we emit imports
that are compatible with both ESM and CJS output (CJS still needed here
since tests run with CJS devmode output still; this is a future project
to switch that over to ESM!)
PR Close#43431
This wires up the `@angular/localize/tools` entry-point. For context:
This entry-point is being created to avoid deep imports into
`@angular/localize/src/tools/<..>` like the CLI relies on. Deep imports
do not play well with strict ESM, and now that all APF packages are
strict ESM, the tool code needs to be either strict ESM as well.
We use ESBuild to create individual bundles for the CLI entry-points,
and the actual tool entry-point. We use a bundler because this enables
the localize code be ESM compatible. Without a bundler, all relative imports
within the `tools` entry-point would need to explicitly have the `.js`
extension. This would be cumbersome and hard to maintain/enforce or
validate.
One might wonder why this is not a standard APF entry-point then. The
answer is that the APF entry-points do not support exposing the CLI
binaries (like `yarn localize-translate`). This could be done through
tertiary entry-points, but using ESBuild directly gives us more control
for now. We might want to revisit this in the future again.
PR Close#43431
Moves the `src/tools` folder of the `@angular/localize` package into the
top-level of the package. This is in preparation of actually exposing an
entry-point for the tools that can be accessed using
`@angular/localize/tools`.
We want to expose such an entry-point because the CLI currently
deep-imports into various places of the tools, but this will not
work well with strict ESM because the localize tool depends on the
v13 strict ESM packages like the `@angular/compiler` or
`@angular/compiler-cli`.
PR Close#43431
As part of v13, all APF packages use the `exports` field which defines
the public entry-points/mappings for a package. so-called package exports.
The `ng_package` rule creates all the necessary mappings/sub-path exports
for the entry-points of `@angular/common`. Though, since the locale files are
generated separately and are not an actual entry-point, we need to expose these
files publicly so that they can be imported/resolved by consumers.
PR Close#43431
We switched the build output for the compiler-cli to use esbuild-generated
bundles.
This means that actual devmode ES5 sources, or prodmode ES2020 non-bundled
sources are not actually needed. Only the types are needed, and this commit
makes sure only the type definitions are shipped. This reduces the code size
of the compiler-cli and also helps with avoiding incorrect module resolution.
PR Close#43431
Updates the service-worker package to export the worker script and
schema, so that these files can be resolved and included by consumers.
Additionally, the CLI bundle is updated to be using ESM as it
transitively relies on the `core` entry-point of the package which
already uses ESM. Also this is required because the script is part
of the the service-worker package which has `type: module` applied.
PR Close#43431
Similar to other code that is shipped as part of `@angular/common`
(with APF v13), we should ship the generated locale files as ESM
files as well. This is necessary/reasonable because we explicitly
set `type: "module"` for the common package, so it makes sense to
have the same apply for the locale sub-directory.
Note: The global locale scripts remain having the `.js` extension
and will continue to be unmodified. They are CJS/ESM compatible either
way, but refer to browser globals.
PR Close#43431
Updates the `sideeEffects` field in `package.json` files to reflect the
new APF v13 format where files use the `.mjs` extension, and are located
in new directories (like the `fesm2020` folder).
PR Close#43431
The view engine language-service tests currently rely on the `npm_package` output
that is built locally. They rely on the package output mostly for
compiling test scenarios (with dependencies on e.g. forms), and for
the testing the metadata extraction (testing proper suggestions for VE).
The reliance on these packages becomes problematic with the new Angular
Package Format v13 where no metadata files are shipped. To continue
being able to test View Engine language-service compatibility, we will
use the v12.x framework packages for some of the test scenarios.
PR Close#43431
In order to support ESM for the `platform-server` package, we need to
remove two usages of dynamic imports and replace them with their
corresponding/equivalent import statement. This will also allow ESBuild
to recognize this import. Note that we want to keep these imports external, so
we explicitly specify the `externals` option for the `ng_package` rule.
PR Close#43431