With the Angular CLI currently being a CommonJS package, this change uses a dynamic import to load `@angular/localize` which may be ESM. CommonJS code can load ESM code via a dynamic import. Unfortunately, TypeScript will currently, unconditionally downlevel 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.
With Angular Package Format v13, we will be using a more recent version of rollup. Rollup
always suffixed exports to avoid collisions, but with the most recent version, the order
has changed slightly changed. e.g. previously for `@angular/core`, there were two instances
of the `ViewEncapsulation` enum part of the `fesm` bundle. The second instance of the enum
orginated from the compiler <--> core facade and it got renamed to avoid conflicts with the
actual declaration of `ViewEncapsulation`. Now this has changed, and the first export is
being renamed instead. This now breaks at runtime because the first export is being incorrectly
transformed by the adjust enum plugin of `build-angular`. The plugin always had this problem
of incorrectly transforming the enums, but it never surfaced because only the face enum has been
transformed (which is not used at runtime). e.g.
consider the following input in `core.mjs`:
```
var ViewEncapsulation$1;
(function (ViewEncapsulation) {
ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
})(ViewEncapsulation$1 || (ViewEncapsulation$1 = {}));
```
this is transformed into:
```
var ViewEncapsulation$1 = /*#__PURE__*/(() => {
ViewEncapsulation$1 = ViewEncapsulation$1 || {};
ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
}());
```
Note how the enum assignment for `Emulated` incorrectly still uses the non-suffixed
identifier that previously was part of the callee wrapper function.
The `proxyConfig` option now supports loading ESM configuration files in addition to JSON and CommonJS files. ESM files (such as those ending with `.mjs`) must provide a default export with the configuration object.
For example, a `proxy.config.mjs` containing the follow is now possible:
```
export default { "/api/*": { "target": "http://127.0.0.1:5001" } };
```
Closes#21623
Absolute import paths, especially on Windows, must be `file://` URLs when using ESM. Otherwise, Windows drive letters (e.g., `C:`) would be interpreted as a protocol instead of a drive letter when performing the import.
With the Angular CLI currently being a CommonJS package, this change uses a dynamic import to load `@angular/service-worker/config` which may be ESM. CommonJS code can load ESM code via a dynamic import. Unfortunately, TypeScript will currently, unconditionally downlevel 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.
This is a followup PR for #21771 that addresses partial compilation linker usage.
With the Angular CLI currently being a CommonJS package, this change uses a dynamic import to load `@angular/compiler-cli/linker[/babel]` which may be ESM. CommonJS code can load ESM code via a dynamic import. Unfortunately, TypeScript will currently, unconditionally downlevel 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.
In the event that the Angular CLI is executed on a platform that does not yet have native support for esbuild, the WASM-based variant of esbuild will now be used. If the first attempt to optimize a file fails to execute the native variant of esbuild, future executions will instead use the WASM-based variant instead which will execute regardless of the native platform. The WASM-based variant, unfortunately, can be significantly slower than the native version (some cases can be several times slower). For install time concerns regarding the esbuild post-install step, esbuild is now listed as an optional dependency which will allow the post-install step to fail but allow the full npm install to pass. This install scenario should only occur in the event that the esbuild native binary cannot be installed or is otherwise unavailable.
This uses a dynamic import to load `@angular/compiler-cli` which may be ESM. CommonJS code can load ESM code via a dynamic import. Unfortunately, TypeScript will currently, unconditionally downlevel 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.
Partial Webpack configuration generators are used to create the various aspects of the final Webpack configuration for build, testing, and serving. They previously could only be synchronous but may need to perform asynchronous actions to setup the Webpack configuration in the future. This is particularly relevant as the CLI transitions from CommonJS to ESM wherein synchronous require calls need to be replaced with asynchronous dynamic imports. For dynamic imports to be successfully used the configuration generators need to support asynchronous operations.
The `@angular/compiler-cli` is used as a peer dependency and has the potential to not be present. As a result static imports should only be used for types and value imports should be dynamic so that they can be guarded in the event of package absence. There are still several instances of static imports for values but these will be corrected in follow-ups.
Polyfill related packages should not be downlevelled due to the nature of their code which may need to perform feature testing or leverage native capabilities to extract browser support information necessary to properly polyfill a given browser. In the case of `web-streams-polyfill`, it leverages the `%AsyncIteratorPrototype%`, when available, to fully polyfill its stream implementations. To access `%AsyncIteratorPrototype%`, a native async generator is needed and therefore the code present in the package cannot have this case of a native async generator downlevelled. `core-js` is also excluded for similar (and additional reasons).
The browser targets provided by `browserslist` have several differences than what `esbuild` expects for the Safari browsers. The first is that the iOS Safari is named `ios_saf` within browserslist and `ios` by esbuild. The former is now converted to the later when generating the target list for esbuild. The second difference is that `browserslist` supports a `TP` (Technology Preview) version for Safari but esbuild expects a numeric value for all versions. Since a TP version of Safari is assumed to be the latest unreleased version and as a result supports all currently known features, a high version number (999) is used as a replacement when generating the target list for esbuild.
BREAKING CHANGE:
The dev-server now uses WebSockets to communicate changes to the browser during HMR and live-reloaded. If during your development you are using a proxy you will need to enable proxying of WebSockets.
The `no-useless-escape` eslint rule has now been enabled which removes unneeded characters and complexity from string literals and regular expressions. All files that were in violation of this rule have also been corrected.
With this change we provide the list of supported browsers to Esbuild during CSS optimizations, so it can perform optimizations based on the browser support needed.
Closes#21594
When using custom builders, it is possible to remove entries from the webpack-configuration
manually. This may eventually lead to undefined entryPoints in async-chunks.ts and aborts
the compilation.
Application code (TS files) will only contain native async if the TypeScript configuration target is ES2017+. However, third-party libraries can contain native async regardless of the target option. To address these third-party libraries, all non-application files need to be analyzed to determine if they must have native async downlevelled. The analysis is first resource path based and then a string match search for the async keyword. This approach has the potential for rare false positives (for example, the word async in a comment) but the outcome would only be a small amount of additional processing for that one file due to the no-op transformation. This is in contrast to a more exact method covering those rare false positives but that would require a more expensive analysis operation on every file and result in longer overall build times.
`esbuild` and `terser` are now used to optimize global scripts in addition to the previous performance enhancement of optimizing application bundles. This change removes the need for the `terser-webpack-plugin` as a direct dependency and provides further production build time improvements for applications which use global scripts (`scripts` option in the `angular.json` file).
Since `esbuild` does not support optimizing a script with ES2015+ syntax when targetting ES5, the JavaScript optimizer will fallback to only using terser in the event that such a situation occurs. This will only happen if ES5 is the output target for an application and a global script contains ES2015+ syntax. In that case, the global script is technically already invalid for the target environment and may fail at runtime but this is and has been considered a configuration issue. Global scripts must be compatible with the target environment/browsers.
The `getEsVersionForFileName` helper function was previously used for recently removed differential loading support but is now unused and can also be removed.
The Node.js `path` builtin module is already imported and provides the necessary functionality to extract the base file name needed within this helper function. By using `path`, all imports from `@angular-devkit/core` can be eliminated from the file.
The architect runtime no longer requires builder options to include the JsonObject in its type definition when calling `createBuilder`. The remaining cases in this package have been removed.
With this change we deprecate deployUrl which in many case causes unexpected and undesired behaviour. Such as #12322, #21432 and #6666. This is because one of the drawbacks of deploy Url is that this url needs to be injected all over the bundles.
This option was previously introduced to handle application that only assets are hosted on a CDN. This setup is now mostly considered as legacy as it is recommended that the entire application is hosted on a CDN. That said, this legacy behaviour can still be achieved by setting the `baseHref` to the CDN address, while setting the `APP_BASE_HREF` to the application address.
Closes#12322 and closes#6666
Esbuild now support CSS sourcemaps which now makes it possible to be used to optimize global CSS.
With this change we also reduce the amount of dependencies by removing `css-minimizer-webpack-plugin` which brings in a number of transitive depedencies which we no longer use.
The legacy standalone build optimizer was still used when targetting ES5 due to the new babel-based build optimizer only supporting the analysis of ES2015+ code. Mainly due to the presence of native classes, the new build optimizer is faster and significantly less complex. To fully remove the legacy build optimizer, ES5 downleveling of application code is now also performed by babel when the TypeScript configuration specifies an ES5 target. TypeScript will now internally emit ES2015 in this configuration and ES2015 code will be used as the input to the remainder of the build pipeline. This has been the behavior for third-party packages and now all code will be consistently downleveled to ES5 using the same tooling.
With this change we update service worker ngsw-config resources extensions.
- Remove `eot`. Old IE font format. Not supported by browsers which support service worker.
- Remove `ani`. Not supported by browsers.
- Add `jpeg` as common alias for `jpg`.
- Add `apng` as modern alternative to `gif`.
- Add `avif` a modern image format.
Closes#21526
An application's TypeScript configuration was previously being loaded multiple times in several different aspects of the build setup process. These aspects need to access specific compiler options relevant to that particular area of the setup. However, loading the configuration can be expensive due to the process also calculating the root files for the TypeScript compilation which can result in a large amount of file access. To improve the setup performance, the number of times the TypeScript configuration will be loaded has now been reduced with further reductions possible with additional refactorings.
Applications can now only be built with Ivy. However, several checks were still present in the code to determine if Ivy was enabled. Since Ivy is always enabled these checks have since become unused code and can be removed.
The static property optimization pass analyzes the initializers of static properties for possible side effects to determine if optimization is safe to perform. Previously the pure annotation of the form `@__PURE__` was not considered during the analysis. This has now been corrected and all of the following forms are supported: `@__PURE__`, `#__PURE__`, and `@pureOrBreakMyCode`.
Not removing inline sourcemaps when vendor sourcemaps is disabled causes an issue during the JS optimization sourcemap merging phase.
```
Optimization error [936.cf7797927c7f989bd40d.js]: Error: Transformation map 1 must have exactly one source file.
```
When vendor sourcemaps is disabled we are not interested into the said sourcemaps so now we remove the inline sourcemap.
Closes#21508
When in watch mode (`ng serve`/`ng build --watch`), Webpack's `copy-webpack-plugin` is currently used to implement the project `assets` option within `angular.json`. Files specified by the `assets` option are intended to be copied to the output unmodified and in their original form. However, if any JavaScript assets were present they previously would have been unintentionally subject to their respective optimization plugins which would result in modified asset outputs and the potential for breakage of the assets. `ng build` outside of watch mode uses a direct file copy with copy-on-write (where supported) to process assets and is therefore not affected by this situation.
When the `copy-webpack-plugin` is used, it adds a `copied` flag to an asset's info metadata. This flag is now used to exclude all such copied JavaScript assets from optimization.
`asset.map` can be `null` which causes an unhandled exception.
```
Error: Optimization error [generated/js/custom-elements-es5-polyfills.js]: TypeError: Cannot destructure property 'mappings' of 'map' as it is null.
at decodeSourceMap (/angular/aio/node_modules/@ampproject/remapping/dist/remapping.umd.js:178:15)
at Array.map (<anonymous>)
at buildSourceMapTree (/angular/aio/node_modules/@ampproject/remapping/dist/remapping.umd.js:725:37)
at Object.remapping [as default] (/angular/aio/node_modules/@ampproject/remapping/dist/remapping.umd.js:831:23)
at default_1 (/angular/aio/node_modules/@angular-devkit/build-angular/src/webpack/plugins/javascript-optimizer-worker.js:44:44)
```
AIO CI failure: https://app.circleci.com/pipelines/github/angular/angular/35940/workflows/c9c91ad3-1645-4a88-bb5b-6a06a9b887b9/jobs/1032993
All Angular builders are now located within one subdirectory of the `src` directory. This organization provides better discovery of the builders and will allow builder specific code to be stored in a single area.
In the Angular version check, the rxjs version was acquired by resolving and reading the rxjs package's package.json file. However, the rxjs version checks were removed in a previous major.
The Webpack configuration setup previously walked up the directory structure to find all `node_modules` directories and then pass this list to Webpack's `resolverLoader.modules` option. This was previously done to ensure that hoisted packages were properly resolved. However, all loader paths are now fully resolved prior to being added to the Webpack configuration. Since loader paths will now be absolute, Webpack no longer needs to resolve them which makes the resolve settings no longer necessary.
Webpack 5 supports setting a module's alias to `false` to signify that a module should be ignored. This option removes the need for the `empty.js` file as an alias option value.
The workaround code was gated on the presence of Node.js 10 but the CLI no longer supports Node.js 10 and will execute with an error if attempted. As a result, the workaround code would never be executed.
BREAKING CHANGE:
With this change we removed several deprecated builder options
- `extractCss` has been removed from the browser builder. CSS is now always extracted.
- `servePathDefaultWarning` and `hmrWarning` have been removed from the dev-server builder. These options had no effect.
BREAKING CHANGE:
The automatic inclusion of Angular-required ES2015 polyfills to support ES5 browsers has been removed. Previously when targetting ES5 within the application's TypeScript configuration or listing an ES5 requiring browser in the browserslist file, Angular-required polyfills were included in the built application. However, with Angular no longer supporting IE11, there are now no browsers officially supported by Angular that would require these polyfills. As a result, the automatic inclusion of these ES2015 polyfills has been removed. Any polyfills manually added to an application's code are not affected by this change.
BREAKING CHANGE:
Differential loading support has been removed. With Angular no longer supporting IE11, there are now no browsers officially supported by Angular that require ES5 code. As a result, differential loading's functionality for creating and conditionally loading ES5 and ES2015+ variants of an application is no longer required.