Node.js v18 will reach its End-of-Life on 2025-04-30 and as a result will
not be supported with the upcoming Angular v20.
Node.js Release Schedule: https://github.com/nodejs/release#release-schedule
BREAKING CHANGE: Node.js v18 is no longer supported with Angular.
Before updating a project to Angular v20, the Node.js version must be
at least 20.11.1. For the full list of supported Node.js versions,
see https://angular.dev/reference/versions.
Ensures that the SSR router gives precedence to the first matching route, addressing the issue where later conflicting routes.
This change prevents the incorrect prioritization of routes and ensures the intended route is matched first, aligning routing behavior.
Closes: #29539
This commit adds support for custom route matchers in Angular SSR, allowing fine-grained control over the `renderMode` (Server, Client) for individual routes, including those defined with matchers.
Routes with custom matchers are **not** supported during prerendering and must explicitly define a `renderMode` of either server or client.
The following configuration demonstrates how to use glob patterns (including recursive `**`) to define server-side rendering (SSR) or client-side rendering (CSR) for specific parts of the 'product' route and its child routes.
```typescript
// app.routes.ts
import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: '',
component: DummyComponent,
},
{
path: 'product',
component: DummyComponent,
children: [
{
path: '',
component: DummyComponent,
},
{
path: 'list',
component: DummyComponent,
},
{
matcher: () => null, // Example custom matcher (always returns null)
component: DummyComponent,
},
],
},
];
```
```typescript
// app.routes.server.ts
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{ path: '**', renderMode: RenderMode.Client },
{ path: 'product', renderMode: RenderMode.Prerender },
{ path: 'product/list', renderMode: RenderMode.Prerender },
{ path: 'product/**/overview/details', renderMode: RenderMode.Server },
];
```
Closes#29284
Switches the beasties bundling to `rules_js`, using rollup directly from
the node modules installation.
Notably we are facing a small issue that doesn't cause any issues right
now, because rollup tries to dereference symlinks by default given
a bug: https://github.com/aspect-build/rules_js/issues/1827.
This means we can't rely on the jailed resolution, but in practice it
shouldn't cause an issue at this point.
This file is currently no longer necessary after migrating all consumers
to their `rules_js` variants, so we can delete the file.
In follow-ups we will consider renaming `defaults2.bzl` back to this
file, or have a better name altogether.
When redirecting to the preferred locale, the previous implementation used the full URL for the 302 redirect to i18n subpaths based on the user's preferred locale. This update ensures that the redirect now uses the locale-specific pathname instead of the full URL.
Closes#29514
This commit renames `provideServerRoutesConfig` to `provideServerRouting` and updates the second parameter to use the `ServerRoutes` features.
This change improves alignment with the framework's API conventions and the way features are integrated.
### Example Usage:
Before:
```typescript
provideServerRoutesConfig(serverRoutes, { appShellRoute: 'shell' })
```
After:
```typescript
provideServerRouting(serverRoutes, withAppShell(AppShellComponent))
```
Updated route matching logic to prioritize closest matches, improving the accuracy of dynamic route resolution. Also we optimized performance by eliminating unnecessary recursive checks, reducing overhead during route matching.
Closes#29452
Migrates the SSR tesst to run natively via `rules_js`. Notably, we still
need the bundling in between as the tests and SSR plain code is not
valid ESM technically; due to lack of extensions.
We'll need to revisit this in the future, or at the very least come up
with a `rules_js`-variant of the `spec_bundle`; but for this is
sufficient and unblocks other packages.
This change modifies the `getPathSegments` function to use `stripTrailingSlash`, providing a more consistent and reliable way to handle trailing slashes in paths. This update also resolves issues causing CI failures.
This fix ensures that catch-all routes (e.g., wildcard routes like `**`) are handled correctly when a base href is configured in an Angular SSR application.
Closes#29397
Although route matchers are not supported with the SSR Routing API, they still function with the legacy `CommonEngine`. Therefore, no error should be issued in this case.
Closes#29420
This is necessary as `rules_js` requires this "common name" when dealing
with Yarn workspaces, linking first party dependencies automatically.
In the future, we may be able to send a PR to `rules_js` to support a
custom name somehow.
Refined and clarified the descriptions for various schematics options to improve their readability and accuracy. These changes aim to make the documentation more user-friendly and accessible for developers.
Closes#25571
Previously, when the application was served behind a proxy, server-side redirects generated an incorrect Location header, causing navigation issues. This fix updates `createRequestUrl` to use the port from the Host header, ensuring accurate in proxy environments. Additionally, the Location header now only contains the pathname, improving compliance with redirect handling in such setups.
Closes#29151
A timeout was added during route extraction to resolve an issue where 'adev' would hang in production builds.
The root cause is currently unclear, but this change ensures the build completes successfully.
When users access the root route `/` without providing a locale, the application now redirects them to their preferred locale based on the `Accept-Language` header.
This enhancement leverages the user's browser preferences to determine the most appropriate locale, providing a seamless and personalized experience without requiring manual locale selection.
Enhance performance when using SSR by adding `modulepreload` links to lazy-loaded routes. This ensures that the required modules are preloaded in the background, improving the user experience and reducing the time to interactive.
Closes#26484
Previously, the `baseHref` option under each locale allowed for generating a unique base href for specific locales. However, users were still required to handle file organization manually, and `baseHref` appeared to be primarily designed for this purpose.
This commit introduces a new `subPath` option, which simplifies the i18n process, particularly in static site generation (SSG) and server-side rendering (SSR). When the `subPath` option is used, the `baseHref` is ignored. Instead, the `subPath` serves as both the base href and the name of the directory containing the localized version of the app.
Below is an example configuration showcasing the use of `subPath`:
```json
"i18n": {
"sourceLocale": {
"code": "en-US",
"subPath": ""
},
"locales": {
"fr-BE": {
"subPath": "fr",
"translation": "src/i18n/messages.fr-BE.xlf"
},
"de-BE": {
"subPath": "de",
"translation": "src/i18n/messages.de-BE.xlf"
}
}
}
```
The following tree structure demonstrates how the `subPath` organizes localized build output:
```
dist/
├── app/
│ └── browser/ # Default locale, accessible at `/`
│ ├── fr/ # Locale for `fr-BE`, accessible at `/fr`
│ └── de/ # Locale for `de-BE`, accessible at `/de`
```
DEPRECATED: The `baseHref` option under `i18n.locales` and `i18n.sourceLocale` in `angular.json` is deprecated in favor of `subPath`.
The `subPath` defines the URL segment for the locale, serving as both the HTML base HREF and the directory name for output. By default, if not specified, `subPath` will use the locale code.
Closes#16997 and closes#28967
This update addresses excessive log noise caused by the following warning:
`NG0912: Component ID generation collision detected. Components 'AppComponent' and 'AppComponent' with selector 'app-root' generated the same component ID. To fix this, you can change the selector of one of those components or add an extra host attribute to force a different ID. Find more at https://angular.dev/errors/NG0912`.