To improve the readability and discoverability of any warnings or errors present
during build, the diagnostic messages will be shown after the build stats are
displayed. For large projects the amount of generated files previously could cause
warnings to scroll off the screen and potentially be missed.
Turns out this isn't needed for `application` builder to correctly resolve inputs. Not using `process.cwd` should make this builder a little less brittle for monorepo use cases or when running `ng test` inside a subdirectory.
This is a new `@angular-devkit/build-angular:web-test-runner` builder which invokes Web Test Runner to execute unit tests in a real browser.
The implementation calls `application` builder under the hood with some option overrides build the application to a temporary directory and then runs Web Test Runner on the output. This set up is still minimal, but sufficient to run and pass tests in the generated `ng new` application.
The `schema.json` file is directly copied from the `karma` builder, since this is intended to serve as a migration target for users coming from Karma. Most of the options don't actually work yet, which is logged when they are used.
The most interesting part of this change is configuring Jasmine to execute in Web Test Runner. This is done through the `testRunnerHtml` option which allows us to control the HTML page tests are executed on. We use `test_page.html` which very carefully controls the loading process. I opted to make a single `<script type="module">` which dynamic imports all the relevant pieces so the ordering can be directly controlled more easily. This is better than trying to manage multiple `<script>` tags and pass data between them. Ideally everything would be bundled into a single entry point, however this is not feasible due to the way that ordering requirements do not align with typical `import` structure. Jasmine must come before polyfills which must come before the runner which invokes user code. In an ideal world, this ordering relationship would be represented in `import` statements, but this is not practically feasible because Angular CLI doesn't own all the files (`./polyfills.js` is user-defined) and Jasmine's loading must be split into two places so Zone.js can properly patch it.
`jasmine_runner.js` serves the purpose of executing Jasmine tests and reporting their results to Web Test Runner. I tried to write `jasmine_runner.js` in TypeScript and compile it with a `ts_library`. Unfortunately I don't think this is feasible because it needs to import `@web/test-runner-core` at runtime. This dependency has some code generated at runtime in Web Test Runner, meaning we cannot bundle this dependency and must mark it as external and dynamic `import()` the package at runtime. This works fine in native ESM, but compiling with TypeScript outputs CommonJS code by default (and I don't believe our `@build_bazel_rules_nodejs` setup can easily change that), so any `import('@web/test-runner-core')` becomes `require('@web/test-runner-core')` which fails because that package is ESM-only. The `loadEsmModule` trick does work here either because Web Test Runner is applying Node module resolution at serve time, meaning it looks for `import('@web/test-runner-core')` and rewrites it to something like `import('/node_modules/@web/test-runner-core')`. In short, there is no easy syntax which circumvents the TypeScript compiler while also being statically analyzable to Web Test Runner.
Previously an entry point `foo` would be incorrectly treated as a relative path, which meant it was not possible to use an NPM package as an entry point. This now requires `./foo` for relative paths while `foo` is treated as a module specifier referring to an NPM package called `foo`.
Due to the file structure of Bazel Windows builds, type annotations are
required in certain locations to successfully build the project. Function
return type annotations are generally recommended anyway within the code.
The previously unused `reuseResults` option for the JavaScript transformer used by the
`application` builder has been removed and replaced with an optional cache option. This
option is currently unused by will allow the caching of JavaScript transformations including
the Angular linker.
Several parts of application builder use slightly different variants of an in-memory
cache. To avoid duplication of code, unified cache infrastructure is now available for
use internally. This also allows for expanded use in other areas of the build system
including the future potential for adding additional backing cache stores.
To ensure that Vite does not unintentionally attempt to prebundle a module that was explicitly
marked as external (typically via the `externalDependencies` build option), the full list of
externalized imports is now filtered by the dependencies specified within the external configuration.
Vite currently will include a module for prebundling if it is present in the include list even though
it may also be present in the exclude list.
This commits, changes the behaviour in the esbuild based builders by emitting component sourcemaps in external files instead of inlining them.
Closes#24049 and closes#26676
When processing a Web Worker reference in application code, the Web Worker entry point is bundled
in a separate action. The external dependencies configuration was previously not passed on to this
action which caused the Web Worker bundling to attempt to bundle any configured external dependencies.
This could lead to build errors if the dependency does not exist within the project.
Experimental programmatically added build extensions are now passed to the internal application builder
when used with the development server. Previously, the plugins were not passed in a manner that would
allow them to be used if the `application` builder was selected as the builder for dev server usage.
The metadata used by the development server to determine the prebundling and externalization behavior
is now created using the external configurations of each bundling operation context directly instead
of the higher level `externalDependencies` build option. This better captures the explicitly defined
external values as each bundling operation configuration could contain additional values based on
the needs and/or customization of each. This will have no current noticeable behavior change as the
default behavior currently does not differ from the higher level option.
The promise creation overhead when calculating the estimated transfer size of the output files during an
optimized build has been reduced by directly using the `brotliCompress` Node.js function instead of using
a promisified variant. Node.js Only provides a callback-based async variant for brotli compression. This
change allows for a single promise to be used.
The long-form variant of the `index` option for the `application` builder now supports
an addition sub-option named `preloadInitial`. This new option is a boolean option that controls
the generation of initial preload related link elements in the generated index HTML file
for the application. Preload related link elements include `preload`, `modulepreload`,
and `preconnect` link rels for initial JavaScript and stylesheet application files.
This update introduces the ability for users to define the locations for storing `media`, `browser`, and `server` files.
You can achieve this by utilizing the extended `outputPath` option.
```json
{
"projects": {
"my-app": {
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": {
"base": "dist/my-app",
"browser": "",
"server": "node-server",
"media": "resources"
}
}
}
}
}
}
}
```
While not recommended, choosing to set the `browser` option empty will result in files being output directly under the specified `base` path. It's important to note that this action will generate certain files like `stats.json` and `prerendered-routes.json` that aren't intended for deployment in this directory.
**Validation rules:**
- `browser` and `server` are relative to the configuration set in the `base` option.
- When SSR is enabled, `browser` cannot be set to an empty string, and cannot be the same as `server`.
- `media` is relative to the value specified in the `browser` option.
- `media` cannot be set to an empty string.
- `browser`, `media`, or `server` cannot contain slashes.
Closes: #26632 and closes: #26057
Similar to the `dev-server` builder, the `application` builder's programmatic usage can now transform
the index HTML that is generated during a build. As is the case for the existing builder JavaScript
exports from the package, the new export (`buildApplication`) is also considered experimental and does
not provide the support nor semver guarantees that the builders have when used via `angular.json` configuration.
The third parameter of the `buildApplication` function can now be an extensions object with one of the fields
being `indexHtmlTransformer`. This newly introduced field allows adjusting the index HTML content.
Closes#26299
When an optimized Sass stylesheet becomes an empty string the AOT Angular host adapter
was previously treating this as a falsy value and using the original content of the
stylesheet. Empty strings are now considered valid values and will be passed to the
AOT compiler as such.
This improvement harmonizes the proxy configuration loading mechanisms between the dev-server and ssr-dev-server. Previously, these servers used different methods for loading the proxy configuration, leading to inconsistencies. Notably, the ssr-dev-server was limited to loading configurations only in JSON format. This change enables the ssr-dev-server to support various configuration formats, aligning it with the dev-server's capabilities and improving overall developer experience.
Before this update, removing the modified file entry from `typeScriptFileCache` when a file was saved but unmodified created an issue. The TypeScript compiler didn't re-emit the file using `emitNextAffectedFile` because the file hashes remained unchanged. Consequently, this led to missing files in the esbuild compilation process.
In the current update, we no longer delete entries from typeScriptFileCache. This adjustment resolves the problem by ensuring the proper handling of file recompilation and prevents files from going missing during the esbuild compilation.
Closes#26635
The load result caching capabilities of the Angular compiler plugin used within the
`application` and `browser-esbuild` builders is now used for both stylesheet and
template component resources when building in JIT mode. This limits the amount of
file system access required during a rebuild in JIT mode and also more accurately
captures the full set of watched files.
Prior to this change, watching of an `npm link` of a library in another workspace when `preserveSymlinks` was set to `true` was not being picked up as `node_modules` files were always ignored.
Closes#25753