Skip to content

Commit

Permalink
Upgrade to Angular 19 (#19772)
Browse files Browse the repository at this point in the history
Nx migration:
 - bump '@angular/**' packages to version '^19.0.3'
 - bump '@ng-select/ng-select' to version '^14.1.0'
 - bump 'angular-oauth2-oidc' to version '19.0.0'
 - bump 'ngx-infinite-scroll' to version '^19.0.0'
 - bump 'zone.js' to version '0.15.0'
 - bump '@angular-devkit/**' libraries to version '^19.0.4'
 - bump '@angular-eslint/**' libraries to version '19.0.2'
 - bump '@nx/**' libraries to version '^20.2.2'
 - bump '@schematics/angular' to version '^19.0.4'
 - bump 'jest-preset-angular' to version '14.4.2'
 - bump 'ng-packagr' to version '^19.0.1'
 - bump 'nx' to version '^20.2.2'
 - bump '@ngrx/**' libraries to version '^19.0.0'
 - bump 'typescript' to version '^5.6.3'
 - bump '@typescript-eslint' to '8.18.1'
 - bump '@angular-builders/custom-webpack' to version '19.0.0'
 - add standalone: false to all components, directives and pipes
    for more, see: angular/angular#57643
 - add rule "@angular-eslint/prefer-standalone": "off" in eslint files
 - remove deprecated "angular-eslint/no-host-metadata-property"
   for more, see: angular-eslint/angular-eslint#2113
 - update '@angular/ssr' import paths to use the new '/node' entry point when 'CommonEngine' is detected
   for more, see: angular/angular-cli#28278

Unit tests issues:
 - update snapshots
 - adjust ssr/engine tests to use new required standalone: false property
 - adjust Jest config for setup/ssr library to use beasties from node_modules instead of the internalized one provided with @angular/ssr due to issues with not supported ES format
   for more, see: angular/angular-cli#28228
   and: angular/angular-cli#28726

Schematics:
 - refactor `server.ts` to use `dist/server/index.server.html` and adjust schematics 
 - #19878

Migration docs
- migration to Angular v19
  • Loading branch information
pawelfras authored Jan 23, 2025
1 parent 6c6f000 commit 53674c5
Show file tree
Hide file tree
Showing 1,007 changed files with 10,697 additions and 5,658 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
],
"plugins": ["deprecation", "@typescript-eslint", "@nx", "@stylistic/ts"],
"rules": {
"@angular-eslint/no-host-metadata-property": "off",
"deprecation/deprecation": "warn",
"prefer-arrow/prefer-arrow-functions": "off",
"space-before-function-paren": "off",
Expand All @@ -30,6 +29,7 @@
"no-fallthrough": "off",
"prefer-const": "off",
"@angular-eslint/use-lifecycle-interface": "error",
"@angular-eslint/prefer-standalone": "off",
"@stylistic/ts/quotes": "off",
"@stylistic/ts/member-delimiter-style": [
"error",
Expand Down
15 changes: 12 additions & 3 deletions core-libs/setup/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,18 @@ const { defaultTransformerOptions } = require('jest-preset-angular/presets');
/** @type {import('ts-jest/dist/types').JestConfigWithTsJest} */
module.exports = {
preset: 'jest-preset-angular',
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths || {}, {
prefix: '<rootDir>/',
}),
moduleNameMapper: {
...pathsToModuleNameMapper(compilerOptions.paths || {}, {
prefix: '<rootDir>/',
}),
// mapping required to use `beasties` from node modules that has proper ES module format
// instead of the version internalized by the Angular Team which file format is not supported
// by Jest.
// for more, see: https://github.com/angular/angular-cli/pull/28228
// and: https://github.com/angular/angular-cli/pull/28726
'^../third_party/beasties/index.js$':
'<rootDir>/../../node_modules/beasties',
},
setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
transform: {
'^.+\\.(ts|js|mjs|html|svg)$': [
Expand Down
6 changes: 3 additions & 3 deletions core-libs/setup/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
"tslib": "^2.8.1"
},
"peerDependencies": {
"@angular/core": "^18.2.9",
"@angular/ssr": "^18.2.9",
"@angular/core": "^19.0.3",
"@angular/ssr": "^19.0.4",
"@spartacus/cart": "2211.32.0",
"@spartacus/core": "2211.32.0",
"@spartacus/order": "2211.32.0",
"@spartacus/user": "2211.32.0"
},
"optionalDependencies": {
"@angular/platform-server": "^18.2.9",
"@angular/platform-server": "^19.0.3",
"express": "^4.21.2"
},
"publishConfig": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { CommonEngineOptions, CommonEngineRenderOptions } from '@angular/ssr';
import {
CommonEngineOptions,
CommonEngineRenderOptions,
} from '@angular/ssr/node';
import { NgSetupOptions } from '../engine/ng-express-engine';
import {
OptimizedSsrEngine,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ exports[`CxCommonEngine should handle APP_INITIALIZER errors the standard Angula

exports[`CxCommonEngine should handle errors propagated from SSR 1`] = `"test error"`;

exports[`CxCommonEngine should not override providers passed to options 1`] = `"<html data-critters-container><head></head><body><cx-token ng-version="18.2.9" ng-server-context="ssr">message:test</cx-token></body></html>"`;
exports[`CxCommonEngine should not override providers passed to options 1`] = `"<html data-beasties-container><head></head><body><cx-token ng-version="19.0.3" ng-server-context="ssr">message:test</cx-token></body></html>"`;

exports[`CxCommonEngine should return html if no errors 1`] = `"<html data-critters-container><head></head><body><cx-mock ng-version="18.2.9" ng-server-context="ssr">some template</cx-mock></body></html>"`;
exports[`CxCommonEngine should return html if no errors 1`] = `"<html data-beasties-container><head></head><body><cx-mock ng-version="19.0.3" ng-server-context="ssr">some template</cx-mock></body></html>"`;
8 changes: 7 additions & 1 deletion core-libs/setup/ssr/engine/cx-common-engine.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import { PROPAGATE_ERROR_TO_SERVER } from '../error-handling/error-response/prop
import { CxCommonEngine } from './cx-common-engine';

// Test how the CxCommonEngine handles successful server-side rendering
@Component({ selector: 'cx-mock', template: 'some template' })
@Component({
selector: 'cx-mock',
template: 'some template',
standalone: false,
})
export class SuccessComponent {}

@NgModule({
Expand All @@ -22,6 +26,7 @@ export class SuccessServerModule {}
@Component({
selector: 'cx-response',
template: ``,
standalone: false,
})
export class WithPropagatedErrorComponent {
constructor() {
Expand All @@ -43,6 +48,7 @@ export const SOME_TOKEN = new InjectionToken<string>('SOME_TOKEN');
@Component({
selector: 'cx-token',
template: `message:{{ someToken }}`,
standalone: false,
})
export class TokenComponent {
someToken = inject(SOME_TOKEN);
Expand Down
2 changes: 1 addition & 1 deletion core-libs/setup/ssr/engine/cx-common-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
CommonEngine,
CommonEngineOptions,
CommonEngineRenderOptions,
} from '@angular/ssr';
} from '@angular/ssr/node';
import { PROPAGATE_ERROR_TO_SERVER } from '../error-handling/error-response/propagate-error-to-server';

/**
Expand Down
14 changes: 12 additions & 2 deletions core-libs/setup/ssr/engine/ng-express-engine.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ import { ngExpressEngine } from './ng-express-engine';
* - https://github.com/angular/universal/blob/e798d256de5e4377b704e63d993dc56ea35df97d/modules/express-engine/spec/mock.server.module.ts
*
*/
@Component({ selector: 'cx-mock', template: 'some template' })
@Component({
selector: 'cx-mock',
template: 'some template',
standalone: false,
})
export class MockComponent {}

/**
Expand Down Expand Up @@ -57,7 +61,11 @@ export class MockServerModule {}
* - https://github.com/angular/universal/blob/e798d256de5e4377b704e63d993dc56ea35df97d/modules/express-engine/spec/mock.server.module.ts
*
*/
@Component({ selector: 'cx-request', template: `url:{{ _req.url }}` })
@Component({
selector: 'cx-request',
template: `url:{{ _req.url }}`,
standalone: false,
})
export class RequestComponent {
constructor(@Inject(REQUEST) public readonly _req: any) {}
}
Expand Down Expand Up @@ -94,6 +102,7 @@ export class RequestServerModule {}
@Component({
selector: 'cx-response',
template: `statusCode:{{ _res.statusCode }}`,
standalone: false,
})
export class ResponseComponent {
constructor(@Inject(RESPONSE) public readonly _res: any) {}
Expand Down Expand Up @@ -144,6 +153,7 @@ export const SOME_TOKEN = new InjectionToken<string>('SOME_TOKEN');
@Component({
selector: 'cx-token',
template: `message:{{ _someToken.message }}`,
standalone: false,
})
export class TokenComponent {
constructor(@Inject(SOME_TOKEN) public readonly _someToken: any) {}
Expand Down
5 changes: 4 additions & 1 deletion core-libs/setup/ssr/engine/ng-express-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
*/

import { StaticProvider } from '@angular/core';
import { CommonEngineOptions, CommonEngineRenderOptions } from '@angular/ssr';
import {
CommonEngineOptions,
CommonEngineRenderOptions,
} from '@angular/ssr/node';
import { Request, Response } from 'express';
import { REQUEST, RESPONSE } from '../tokens/express.tokens';
import { CxCommonEngine } from './cx-common-engine';
Expand Down
5 changes: 4 additions & 1 deletion core-libs/setup/ssr/optimized-engine/rendering-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ export class RenderingCache {
if (this.options?.cacheSize) {
this.renders.delete(key);
if (this.renders.size >= this.options.cacheSize) {
this.renders.delete(this.renders.keys().next().value);
const oldestKey = this.renders.keys().next().value;
if (oldestKey !== undefined) {
this.renders.delete(oldestKey);
}
}
}
// cache only if shouldCacheRenderingResult return true
Expand Down
38 changes: 0 additions & 38 deletions docs/migration/2211_ng18/migration.md

This file was deleted.

File renamed without changes.
67 changes: 67 additions & 0 deletions docs/migration/2211_ng19/migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# (EARLY NOTES) Migrating a custom app to use Spartacus with Angular v18

Before upgrading Spartacus to the new version with Angular 18, you need to first:

- upgrade Spartacus to version 2211.32.1
- install Node 22 version
- upgrade `@types/node` to version 22
```bash
npm i @types/node@22
```
- upgrade Angular to version v18 and then to v19

## Update Angular to 18 and 19

### Update Angular to 18 and 3rd party deps to be compatible with Angular 18

> **Warning**
>
> Do not select `use-application-builder` migration when migrating to Angular 18. Applications created before SPA 2211.19 doesn't support this builder. Applications created starting from 2211.19 already support it.
Follow the [Angular guidelines for upgrading from v17 to v18](https://angular.dev/update-guide?v=17.0-18.0&l=3) and bump the Angular version locally, and update other 3rd party dependencies from Angular ecosystem to versions compatible with Angular 18 (e.g. `@ng-select/ng-select@13`, `@ngrx/store@18`, `ngx-infinite-scroll@18`):

```bash
ng update @angular/core@18 @angular/cli@18 @ng-select/ng-select@13 @ngrx/store@18 ngx-infinite-scroll@18 --force
git add .
git commit -m "update angular 18 and 3rd party deps angular 18 compatible"
```


### Update Angular to 19 and 3rd party deps to be compatible with Angular 19

> **Warning**
>
> Hit SPACE to unselect `use-application-builder` migration when migrating to Angular 19. Applications created before SPA 2211.19 doesn't support this builder. Applications created starting from 2211.19 already support it.
Follow the [Angular guidelines for upgrading from v18 to v19](https://angular.dev/update-guide?v=18.0-19.0&l=3) and bump the Angular version locally, and update other 3rd party dependencies from Angular ecosystem to versions compatible with Angular 19 (e.g. `@ng-select/ng-select@14`, `@ngrx/store@19`, `ngx-infinite-scroll@19`):

```bash
ng update @angular/cli@19 @angular/core@19 ngx-infinite-scroll@19 @ng-select/ng-select@14 @ngrx/store@19 angular-oauth2-oidc@19 --force
git add .
git commit -m "update angular 19 and 3rd party deps angular 19 compatible"
```



## Run Spartacus update

After successfully updating the application to Angular 19, execute this command to initiate the Spartacus update process.

```bash
ng update @spartacus/schematics@latest
```

### If using Server Side Rendering (SSR) and `application` builder

For applications with SSR support that use the Angular's `application` builder (i.e. having in `angular.json` the following value: `... "architect": { "build": { "builder": "@angular-devkit/build-angular:application", ...`), you need to adjust the `server.ts` file to be compatible with the output generated by this builder.

```diff
/* ... */
- const indexHtml = join(browserDistFolder, 'index.html');
+ const indexHtml = join(serverDistFolder, 'index.server.html');
```





7 changes: 6 additions & 1 deletion feature-libs/asm/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"extends": "../../.eslintrc.json",
"ignorePatterns": ["schematics/**/*.d.ts"]
"ignorePatterns": ["schematics/**/*.d.ts"],
"overrides": [
{
"files": ["*.ts"]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {

@Pipe({
name: 'cxTranslate',
standalone: false,
})
class MockTranslatePipe implements PipeTransform {
transform(): any {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export enum BIND_CART_DIALOG_ACTION {
@Component({
selector: 'cx-asm-bind-cart-dialog',
templateUrl: './asm-bind-cart-dialog.component.html',
standalone: false,
})
export class AsmBindCartDialogComponent {
BIND_CART_ACTION = BIND_CART_DIALOG_ACTION;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import createSpy = jasmine.createSpy;
@Component({
selector: 'cx-icon',
template: '',
standalone: false,
})
class MockCxIconComponent {
@Input() type: ICON_TYPE;
Expand Down Expand Up @@ -85,6 +86,7 @@ class MockActiveCartService implements Partial<ActiveCartFacade> {

@Pipe({
name: 'cxTranslate',
standalone: false,
})
class MockTranslatePipe implements PipeTransform {
transform(): any {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import { AsmComponentService } from '../services/asm-component.service';
selector: 'cx-asm-bind-cart',
templateUrl: './asm-bind-cart.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: false,
})
export class AsmBindCartComponent implements OnInit, OnDestroy {
activeCartValidator: ValidatorFn = (control) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const duplicatedUidErrorResponse: HttpErrorModel = {
@Component({
selector: 'cx-icon',
template: '',
standalone: false,
})
class MockCxIconComponent {
@Input() type: ICON_TYPE;
Expand All @@ -99,6 +100,7 @@ class MockAsmCreateCustomerFacade implements Partial<AsmCreateCustomerFacade> {

@Directive({
selector: '[cxFocus]',
standalone: false,
})
export class MockKeyboadFocusDirective {
@Input('cxFocus') config: FocusConfig = {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { CreatedCustomer } from './asm-create-customer-form.model';
@Component({
selector: 'cx-asm-create-customer-form',
templateUrl: './asm-create-customer-form.component.html',
standalone: false,
})
export class AsmCreateCustomerFormComponent {
createdCustomer: CreatedCustomer;
Expand Down
Loading

0 comments on commit 53674c5

Please sign in to comment.