When using the `application` or `browser-esbuild` builders, a parallel TS/NG compilation will
be used by default via a Node.js Worker. However, when used inside a Web Container, the
build will fail to initialize the compilation instance due to what appears to be a defect
within Web containers involving the transfer/serialization of a MessageChannel's MessagePort
objects. To avoid this problem, the parallel compilation is disabled by default when the
build system detects it is being executed from within a Web Container. A parallel compilation
can still be forced by using the `NG_BUILD_PARALLEL_TS=1` environment variable.
Prior to this commit, the pre-bundling of dependencies was being invalidated for each build. This is because vite uses parts of the config among other things to generate a hash. In our case the config was not always consistent for the same project between different builds.
The main 2 problems areas were:
- Random `root` path
- `include` and `exclude` arrays were not always in the same order.
It appears that Vite currently, has a number of limitation/bugs when using `optimizeDeps` for SSR bundles.
Currently this causes a number of issues:
- Deps are re-optimized everytime the server is started.
- Added deps after a rebuild are not optimized.
- Breaks RxJs (Unless it is added as external). See: #26235
We should follow up with Vite and try to get this solved as this would be a nice feature to use.
Closes#26235 and #26234
Currently, externalMetadata arrays get appended the same items over and over again on every rebuild. This commit cleans the array before it appending the new values.
The `JavaScriptTransformer` class that is responsible for Angular linking and several build optimization
transformations can now be configured to track and reuse previous and pending transformation requests.
This allows for cases where multiple consumers of the class will not cause repeat transformation actions.
Pending results will be stored if the constructor option `reuseResults` is enabled. If two transformation
requests are issued for the same file, the same underlying result will be provided to each. This behavior
currently only applies to file transformation requests.
Vite will only start dependency optimization of SSR modules when the first request comes in.
In some cases, this causes a long waiting time. To mitigate this, we call `ssrLoadModule` to initiate this process before the first request.
This fixes the following warnings
```
Cannot optimize dependency: url, present in 'ssr.optimizeDeps.include'
Cannot optimize dependency: path, present in 'ssr.optimizeDeps.include'
```
The in-memory ESM loader hooks have been adjusted to avoid potential errors when
resolving and loading the bundled server code during prerendering. These errors
could result in hard to diagnose build failures. E2E testing via the deprecated
protractor builder, would silently exit, for instance. To ensure on disk files
including node modules are resolved from the workspace root, a virtual file root
is used for all in memory files. This path does not actually exist but is used to
overlay the in memory files with the actual filesystem for resolution purposes.
A custom URL schema (such as `memory://`) cannot be used for the resolve output
because the in-memory files may use `import.meta.url` in ways that assume a file
URL. `createRequire` from the Node.js `module` builtin is one example of this usage.
When using the esbuild-based builders (`application`/`browser-esbuild`), the secondary Angular compilations
will wait for the primary compilation to finish prior to bundling. This can potentially occur for polyfills
that contain TypeScript files and the server code if enabled. However, if the Angular compilation throws
an error during the start of the bundling process, the secondary compilations were never notified and instead
would wait indefinitely. To avoid this situation, the compilations will now always be notified at the end of
the compilation which will occur regardless. The build error that will be generated in these situations is
currently not ideal and more verbose than needed but will provide information pertaining to the root cause.
This commit splits the retrieval of external dependencies into two. Server imports and browser imports. This is so that we avoid vite from optimizing server or browser only dependencies twice.
This also fixes an issue were in some cases Vite would issue a warning like `Cannot optimize dependency: path, present in 'optimizeDeps.include'`. This was caused because of server only dependencies ended up trying to be optimized for a browser build.
When using the experimental programmatic API for the development server with an esbuild-based
builder (`application`/`browser-esbuild`), express compatible middleware can now be added.
Also, the index HTML transformer that previously only worked with the Webpack-based development
server is also now enabled.
However, usage of these options may result in unexpected application output and/or build failures.
They are also not officially supported and SemVer guarantees are not present.
Stable and supported methods for build process extension are being evaluated for a future release.
The dynamically compiled ESM import helper is now cached to prevent the need
to recompile the helper function everytime a load ESM helper call is made.
This helper is currently used to workaround dynamic import limitations with
the TypeScript compilation output. Once the build process is updated, it will
no longer be required.
The commit introduces dependencies prebundling and optimisation for SSR dependencies. This is primarily needed for Angular linking and async/await downlevelling. To enable this, we need to use the undocumented `optimizeDeps` setting under the `ssr` option. This is because, the top level `optimizeDeps` vite config option only controls browser dependencies.
For the above mentioned option to take effect and transform node packages, we also need to use `noExternal` and use a catch all `RegExp`. Note: setting this option to `true` has a different effect from a catch all `RegExp`, as the former will cause the `external` option to be ignored.
Additionally together with `externalMetadata.explicit` we add Node.js build-ins as `external`.
Closes: #26192
This change fixes an issue were non bundling related errors that happen during prerendering, index generation and bundle budget failures did not cause the build to terminate with an error.
The `server-utils` SSR generated chunk was not previously included in the ESM in memory loader for
prerendering which resulted in the ESM resolver incorrectly attempting to resolve non-relative
dependencies. This would lead to resolution errors when using the development server with caching
enabled. In this scenario, the Angular dependencies would be marked external and the server utilities
output chunk would contain non-relative imports and fail to prerender.
The protractor E2E builder relies on a development server `baseUrl` result property to determine the address
to connect when testing the application. The Vite-based development server now also provides this
property. While the protractor builder is considered deprecated, it is still used in CLI E2E tests.
When using the `scripts` option with the esbuild-based builders (`application`/`browser-esbuild`), the
JavaScript code from the scripts will now be processed based on the targets provided in the application's
browserslist file. This prevents unsupported syntax from being present in the output script chunk that is
generated.
* fix(@angular-devkit/build-angular): Windows Node.js 20 prerendering failure
On Node.js 20 prerendering failed on Windows with `An unhandled exception occurred: No handler function exported` error. This appears to be caused by transforming Piscina CJS bundles using the `JavaScriptTransformer`. interestingly, this does not effect other OS like Linux and Mac.
* fixup! fix(@angular-devkit/build-angular): Windows Node.js 20 prerendering failure
Co-authored-by: Charles <19598772+clydin@users.noreply.github.com>
---------
Co-authored-by: Charles <19598772+clydin@users.noreply.github.com>
When using the application builder in watch mode (including `ng serve`), the file watching
will now only watch files used or relevant to the used files. Previously, all files within
the project root were watched. This previous behavior could result in unneeded rebuilds when
unrelated files were changed. An environment variable named `NG_BUILD_WATCH_ROOT` is also
now available to enable the previous behavior in cases where it is still preferred as well
as for testing and debugging purposes.
Angular v17 adds another dev-mode-only function that needs to be removed called `ɵsetClassDebugInfo`. These changes update the Babel plugin to account for it.
The Worker thread pool that is used by the JavaScript Transformer within the application
builder is now only initialized if there is JavaScript that must be transformed. This
removes any overhead associated with the worker pool if no work is required. This is
particularly useful when using the development server with caching enabled and all the
dependencies have already been prebundled.
The newly introduced incremental bundler result caching is now used for server polyfills. This allows the bundling steps to be skipped in watch mode when no related files have been modified.
The Vite-based development server that is used with the esbuild-based builders (`application`/`browser-esbuild`)
will show an error overlay when the application build encounters an error. This overlay previously provided a
suggestion to edit the `vite.config.js` configuration file to disable the error overlay. Since Vite usage is
encapsulated within the Angular CLI, this suggestion is unactionable and may lead to user confusion due to
no Vite configuration file being present within the project nor would creating one have an effect on the build
process.
Any errors or warnings generated from post-bundling steps of the build will now be formatted and displayed
in a similar manner to the bundling errors and warnings. This should be most noticeable with bundle budgets.
The newly introduced incremental bundler result caching is now used for browser polyfills (`polyfills` option).
This allows the bundling steps to be skipped in watch mode when no related files for have been modified.
When using the application builder with the development server, Web Worker URLs previously may
have been incorrectly resolved. This caused Vite to consider the Web Worker URLs as outside
the project root and generate a special file system URL. While this worked on Mac/Linux, it
would fail on Windows. Since Vite does not appear to support resolve plugins for Web Workers,
the virtual project root for the in-memory build has now been adjusted to allow the referencing
file to have a path that resolves the Web Worker URL to a project relative location.
When CommonJS module checking is enabled in the esbuild-based builders (`application`/`browser-esbuild`),
the checker will now skip all descendants of a CommonJS module. Previously it would only skip them if
the module was not allowed. This change now provides the same module checking behavior as the Webpack-based
check. This makes the build behavior more consistent when migrating to the new build system.
Similar to how the Webpack-based `browser` builder only shows the output files that have changed
during watch mode (including `ng serve`), the esbuild-based builders will now also only show changed
files. For large applications, this can greatly reduce the amount of text shown in the console when
actively developing in watch mode.
There might be cases were currently, the render application promise does not resolve because the application never becomes stable in most cases this is due to errors, this causes the worker to never exit and the build to keep running until it's manually terminated.
With this change, we add a maximum rendering timeout of 30seconds for each page.
The newly introduced incremental bundler result caching is now used for both global styles
(`styles` option) and global scripts (`scripts` option). This allows the bundling steps
to be skipped in watch mode when no related files for either have been modified. This
can be especially beneficial for applications with large global stylesheets.
`ng serve` might fail with: `Cannot read properties of undefined (reading 'explicit')` because `result.externalMetadata` is optional.
This commit guards the access and should fix the issue related to the fix 9768c184e0
When using the Vite-based development server combined with the `externalDependencies` option, Vite
will no longer attempt to resolve the explicitly marked externals.
This is still not ideal since it vite will still transform the import specifier to `/@id/${source}`
but is currently closer to a raw external than a resolved file path. Further investigation with
a possible feature request for Vite may be needed to achieve the desired outcome of an unresolved
and untransformed external import specifier.