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 of v13, the package output will be using partial compilation output.
This breaks the Bazel setup similar to how it breaks Angular Components.
The problem is that `@bazel/concatjs` relies heavily on the UMD files
that previously existed in APF, plus it assumed that ngcc pre-processed
the files in the `node_modules`. This is no longer the case as there are
no UMD files, and the code is not fully-compiled by the Angular
compiler.
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
The CLI has been updated with various changes to support for ESM package
output of the framework. This commit updates to a next version of the
CLI v13 that contains these necessary changes, allowing us to test/validate
our package changes through integration tests or AIO examples.
This update also contains a fix for the adjust enum babel optimization
that broke with the latest rollup version.
PR Close#43431
Temporarily disables the `components-repo-unit-tests` job due to APF
v13 which is currently not handled properly in the components repo. The
components repo would need to be updated first to properly handle v13
APF output (with linker processing and an alternative to UMD bundles
which the majority of tests currently rely on).
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
Sets the executable bit for the build-packages-dist script so that
the script can be invoked directly without having to explicitly
prefix it with the `node` command.
PR Close#43431
Updates the platform-server integration test to rely on the v13 partial
compilation packages. This involves setting up the Babel linker plugin.
This is a great addition for coverage of the Babel linker plugin.
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
This just came up while working on an integration test that also
relies on RxJS v7. It looks like the RxJS package has not been pinned
for the v7 test, so that the test actually always ran v6 by accident.
This commit fixes that.
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
The bazel integration tests are currently not compatible with Windows.
Tests never get to run because the created tar packages for NPM packages
are built using an outdated `pkg_tar` rule that creates invalid
tarballs. We fix this by using the non-deprecated windows-compatible
`rules_pkg` implementation.
Additionally, we copy all `package.json` files of integration tests to
the bazel bin directory as otherwise the file would be accidentally
modified as a source on Windows.
PR Close#43431
Technically this change would not be needed as the NPM package
output is always built with Ivy now (using the transition). There
is no View Engine output anymore. We still want to limit the tests
to only run with the `--config=ivy` define setting as some API goldens
tests could accidentally rely on plain `ng_module` output / additionally
we wouldn't need to run the API golden tests multiple times.
PR Close#43431
The View Engine ngc tests currently rely on the `npm_package` output
that is built locally. This becomes problematic with the new Angular
Package Format v13 where no metadata files are shipped. To continue
being able to test View Engine compilation, we will use the v12.x
framework packages for running the View Engine test.
Note: This means that we no longer test metadata extraction directly
for our framework packages, but given that any change to View Engine
will still land in patch, where the VE packaging still occurs, we should
be covered here.
PR Close#43431
Basic integration tests are those which do not require significant
changes as others. The larger ones will have individual commits.
For v13, the NPM package output will always be using partial compilation
output. This makes the ngcc integration test fail because the actual
Angular framework packages are no longer processable. We fix this, and
keep the ngcc test coverage by relying on the v12.x framework packages
in the integration test.
The terser integration test needs to point to the new Flat ESM module
file location. We now output FESM2020 instead of FESM2015. This also
requires us to use the latest version of terser.
The `side-effects` test currently is not maintained by us and relies
on View Engine build output. In the partial compilation output the
partial declarations are not marked with `@PURE` and are not removed
therefore. We would need to update the side-effect test to use the
linker Babel plugin instead. This is currently out-of-scope though
so we disable the test for now.
PR Close#43431
ngcc currently dynamially loads the `Transformer` code. It does this
to avoid unnecessary parsing and loading of transformer-related code
if there is nothing to process (so-called noop case). Unfortunately
this dynamic require is not recognized by ESBuild. The import needs
to be discovered as otheriwse the transformer code would not be included
in the bundled package output of the CLI.
The ngcc code needs to use an async runtime import as it would work
in ES modules. This introduces async code into to the compililation
pipeline, breaking the `ngccMain` synchronous invocation feature.
To avoid this, we just move the dynamic require/async import to
the file top-level so that we do not break synchronous processing
which the CLI relies on. This has the downside of slowing-down
the noop case a little but I believe that should be mitigated
through bundling of ngcc anyway. In the future with full-ESM
we won't be able to get around this anyway (unless we remove the
sync variant of ngcc processing).
PR Close#43431
Exposes code needed by the Angular CLI. Previously the CLI used
deep imports for most of these things, but now with bundling
the CLI, we no longer support deep imports.
We will expose the necessary dependencies for the linker as part
of the primary entry-point (I think that is more maintable than
re-exporting them as part of the linker). We also expose the ngcc
entry-point for the CLI with a new constant that will point to the
ngcc command line entry-point (which the CLI relies on).
PR Close#43431
Updates all API goldens to match with the new NPM package output
which now contains partial declaration static members. These
can serve as additional checks guarding against changes to
the public API (e.g. if a selector of a directive changes accidentally)
PR Close#43431
In preparation for the v13 Angular Package Format, where partial
declarations are emitted only, the AOT compiler test is updated
to rely on package artifacts from v12 instead. This allows us
to switch to the new package format without breaking the tests
which require metadata files to exist in the NPM packages.
PR Close#43431
The Angular Core and localize package currently use deep imports for
code that is shipped. This is problematic as we want to ship the
compiler-cli as full-ESM. To achieve this we need to use a bundler and
this breaks deep imports.
We use a bundler for the compiler CLI because for full ESM
compatibility, we would need to explicitly add the `.js` extension
to all relative imports. This is very cumbersome and prone to mistakes
so to mitigate this problem in a safe way, we bundle the compiler-cli.
Note: Deep imports continue to exist for the language service as it
bundles the compiler-cli.
PR Close#43431
After updating to a more recent version of rollup, rollup started to
complain because the `inject` and `ɵɵinject` functions are being re-exported
twice in the `@angular/core` public API entry-point.
Rollup threw errors like:
```
[!] Error: “ɵɵinject” cannot be exported from node_modules/@angular/core/esm2015/src/di/injector_compatibility.js as it is a reexport that references itself.
```
A similar error is shown for `CodegenComponentFactoryResolver`.
It seems like Rollup ideally would not throw here, similar to TypeScript
which detects that these exports are the same and just dedupes them, but
it's low-effort fixing this for now.
PR Close#43431
After updating to a more recent version of rollup, rollup started to
complain because the `TreeParseResult` class is being re-exported
twice in the `index.ts -> public-api.ts -> compiler.ts` entry-point.
Rollup threw errors like:
```
Error: "ParseTreeResult" cannot be exported from
<..>/ml_parser/parser.mjs as it is a re-export that references itself.
```
It seems like Rollup ideally would not throw here, similar to TypeScript
which detects that these exports are the same and just dedupes them, but
it's low-effort fixing this for now and actually is a good opportunity
to make the public API a little more easy understand (when looking at
the `compiler.ts` file).
PR Close#43431
This commit proposes adding myself to the codeowners for `bazel`. I
have made various changes for quite some time to `@angular/bazel` and
with the new APF v13 changes, a lot of code was simplified.
As one of the primary consumers of `@angular/bazel` (in the name of the
Angular components repo), I think it would be reasonable to have an eye
on changes to the Bazel package.
PR Close#43431
As part of APF v13, we ship Angular framework packages using partial
compilation. This is done in preparation of VE removal, and to
eventually get rid of `ngcc` processing.
The new library format allows libraries to switch away from the View
Engine package format without shipping Angular definitions with
instructions to NPM. This would make libraries tightly coupled to
specific versions of `@angular/core`.
Since Angular core is always compatible with itself, we always should
compile Angular core using full compilation mode. It is unreasonable
to ship Angular core with partial compilation output, especially since
we would need to export the linker `declare` functions in
`r3_symbols.ts` otherwise.
PR Close#43431
All other frameworks packages are now using APF v13 and are strict
ESM packages. The compiler-cli does not use APF and is currently shipped
with its devmode ES5 CommonJS sources. This is problematic as CommonJS
cannot simply import from ECMAScript modules (like `@angular/compiler`).
To fix this we use a bundler that allows us to ship the compiler-cli as
a strict ESM package. Note: An ESM can import from an ESM without any
problems. This is what we need hre.
Unfortunatley we need a bundler here because converting the compiler-cli
to ESM is non-trivial as relative imports would need an explicit
`.js` extension. This work can be simplified by using a bundler that
avoids relative imports completely.
Note: This commit uses code-splitting to create multiple bundle
entry-points for `yarn ngc, `yarn ngcc` etc. This commit removed
the old `ivy-ngcc` entry-point that just printed an error message
(to reduce amount of bundles having to be configured).
PR Close#43431
For APF v13, terser has been updated to v5, and the prodmode output
has changed from ES2015 to ES2020. This results in some changes in
the symbol extractor test. Here are the two causes of changes:
* As said in the previous commit, Terser drops the initializer for
variables which are set to `undefined`. We have updated the symbol
extractor to always capture such declarations w/o initializer now.
This means that a couple of declarations that a couple of new
symbols are captured now. These previously didn't have an initializer
even without Terser, and just didn't show up before.
* Terser changed its inline mechanism for functions that recursively
call themselves. Such functions are no longer inlined and therefore
show up in goldens now.
PR Close#43431
Updates the symbol extractor test to work with Terser v5 that
drops the variable declaration initializer if it is explicitly set
to `undefined`. We want to capture such identifiers in the bundles
as otherwise the majority of top-level declarations which are intially
set to `undefined` would be hidden in size goldens.
PR Close#43431
With the changes to support APF v13 in the `ng_package` rule, we have
removed the ambiguous `entry_point` attribute. The attribute suggested
that it would be used for determining the primary entry-point input
file. This was not the case as the flat module output file is consulted
for bundling et at. The attribute has been renamed to match its
purposed (renamed to `primary_bundle_name`).
We no longer need to set that attribute because the primary bundle
name is (1) not of relevance for consumers and (2) the rule already
infers the bundle name properly from the Bazel package.
PR Close#43431
This commit implements partial compilation APF v13 for the
`ng_package` rule. The changes involve the following things:
1. Requesting the partial compilation output for all targets (and
its transitives) in the `deps` or `srcs` attributes.
2. Downleveling of ES2020 prodmode output to a FESM2015 file.
3. Cleanup of file resolution. Previusly, execroot file paths (which are
passed to the packager tool) were composed manually. This is prone to
mistakes and breaks with transitions.
A lot of this code can be simplified by passing the necessary Bazel
`File` information as JSON. This also simplifies the packager tool
significantly (and makes it more readable..)
4. Remoal of UMD bundles. This also allows us remove the `globals` rule
attribute with `externals` (we do not need any UMD global identifier
names anymore).
5. The `package.json` will set the `exports` field and use subpath
exports to make module resolution work for ESM consumers.
6. TSLib is also always set as `external` now. Previously it had to be
added as `dep` to the `ng_package` rule as UMD files bundled `tslib`.
7. The `include_devmode_srcs` option has been removed. This option was
an addition to APF that allowed the `@angular/compiler` to ship
non-flattened ES5 CommonJS sources. We want to keep APF consistent
and not allow such exceptions. Compiler is now a strict APF package
as well, and the compiler-cli just needs to go through the primary
entry-point for things it needs (or it bundles the necessary parts
into the CLI.)
Overall, these are all changes. A lot of changes to make the packager
rule and tool more readable and Bazel-idiomatic were made as well. This
allows us to easier make packaging changes in the future, and it's more
future-proof if we ever change how inputs (like `ng_module` targets) are
generated (e.g. consider a case where we'd use the `ts_project` rule).
PR Close#43431
Updates the primary tsconfig files to use ES2020 as target and module.
This helps IDEs and reflects what we generate in production, allowing
the use of JS features that are natively supported in APF v13.
PR Close#43431
We should no longer generate VE shims for workspaces which are not named
`angular`. The default is Ivy compilation and this should be opt-in. The
components repository for example does not need any shims as it is using
Ivy for the common development workflows.
PR Close#43431
Previously, the prodmode output was using ES2015 for `ng_module` and
`ts_library` targets. This commit changes it to `ES2020`. This is
necessary as we want to ship es2020 output in APF v13.
PR Close#43431
In preparation for using the partial compilation transition on the
packager, we need to be able to have a reference to the flat module
out file (that is used as "index" file for entry-point ng_module targets).
We need a reference to the file because with transitions applied, the
inputs are not necessarily in the default `bazel-out` directory. The
packager currently only guesses such paths (this worked most of the
time) but guessing the output directory with transitions will become
impossible.. so the paths need to be computed in a Bazel-idiomatic way.
This is more future-proof and correct (and more clean IMO).
PR Close#43431
Removes the `compilation_mode` attribute for the `ng_module` rule. We
remove the attribute since we intend to control the compilation mode
through the partial compilation build setting we have added before.
Note: We could have named the build setting more generically, something
like `ng_compilation_mode`, but I think it's more readable only assuming
there is `partial` compilation, or `full`. We can always change this in
the future as it is not part of the public API.
PR Close#43431
Previously, `ng_module` generated a second `d.ts` bundle in case the
built target was the Angular core target. This was done so that the
packager later on can ship the `r3_symbols.d.ts` file along with the
APF v13 output. Ngcc relied on this file when it processed the Angular
core package. This is no longer needed for Angular Core v13 since it
will come as partially-compiled without the need for ngcc.
The major benefit of no longer generating multiple dts files here is
that we can reasonably pass the bundle through a provider to the packager
which can then use this for determining the `d.ts` file it should link
in the `package.json`.
This is beneficial and needed for using a transition since the packager
input files are no longer in the default `bazel-out`, so it's important
to keep an reference to the actual Bazel `<File>` instance, allowing
us to determine the path properly in the packager (without any
assumptions on the `bazel-out` path..).
PR Close#43431
We created a build setting (bool flag) for controlling whether partial
compilation should be enabled or not. This commit wires up the build
setting so that all `ng_module` targets respect the flag.
This will later be useful when we apply the transition (which always
sets the partial compilation flag to `True`).
PR Close#43431
Moves the `ng_module.bzl` file into a sub-directory called `ng_module`.
This is consistent with other rules in the package. And it also allows
us to ship the `ng_module.bzl` code next to other tightly-coupled files
like the partial compilation transition/flag.
PR Close#43431
Creates, a currently still unused, Bazel transition that will control
a build setting that is enabling the partial compilation mode for
`ng_module` rule targets. This is in preparation of implementing the
Angular Package Format v13 (which should ship in partial compilation).
Note: Various other approaches aside from the `transition` has been
considered. Here is a small summary of the largest ideas that have
been tried for the APF v13 partial compilation refactor.
**Using an aspect for partial compilation in `ng_package`**
Similar to how we had an aspect for ESM5 compilation in the past,
an aspect could be used to create partial compilation prodmode output
for packaging. The aspect would take the existing prodmode compilation
details and "replay" the compilation with a modified tsconfig that
enables partial compilation.
This _can_ work but requires lots of caution and is very prone to
issues. In order to avoid conflicts with the existing prodmode output,
the partial compilation outputs would need to be written to a
sub-directory. This makes module resolution extremely difficult when
`ng_package` creates the FESM bundles. Also it is difficult to merge
multiple of these aspect-compiled folders into a single one for exposing
the non-bundled ESM output. It becomes especially difficult to ensure
that such an aspect target will actually use the _correct_ dependency
type definition when compiled.
e.g. consider a case where a partial compiled target relies on another
Angular target. The dependency will be compiled partially first, but
the other target _needs_ to rely on the partial compilation `d.ts`
output of the dependency (and *NOT* the devmode `.d.ts` output). This
is incorrect and can cause other type-checking issues / or invalid
output. To make this work, the module resolution when invoking
tsc_wrapped would also need to be updated/patched. This is out of scope
and not reasonable to maintain.
**Exposing a third output flavor directly in the rule**
Instead of replying a compilation, we could expose an output flavor
next to `devmode` and `prodmode`. This sounded like the easiest
solution at first, but it will have the same problems as the aspect
approach (in terms of module resoltion and avoiding conflicts of files).
We cannot control how TS emits `.d.ts` or `.js` files (without patching
into the compiler host), so we would need to store the compilation
output in a sub-folder similar to the aspect.. resulting in the same
issues. This is do-able but would require module resolution to be
patched and we do not have control over `@bazel/typescript`. Also,
`@bazel/typescript` does not forsee a third output flavor, so that
logic would need to be changed significantly as well.
PR Close#43431