Skip to content

Commit 4820980

Browse files
feat: add Angular 22 support (non-breaking, keeps 18–21) (#212)
* feat: add support for Angular 22 Extends the supported Angular range from 18–21 to 18–22. - package.json: bump devkit upper bounds (architect <0.2300.0, core/schematics <23.0.0) and the @angular/cli peer to <23.0.0; v3.1.0 - README: update supported range to "Angular 18 to 22" - CI: add an Angular 22 ng new / ng add / ng deploy smoke test - tests: add angular-22.json fixture (real ng new v22.0.0 output) plus Angular 22 compatibility assertions No engine/builder changes needed: Angular 22's generated angular.json is structurally identical to 21 (@angular/build:application, no outputPath), which actions.ts already handles. * chore: port Node version range improvement from #211 #211 rightly flagged that engines.node ">=18.0.0" is stale β€” no supported Angular actually runs on Node 18.0–18.18 (Angular 18's real floor is 18.19.1). It set "^20.19.0 || ^22.12.0 || >=24.0.0", but that is Angular 20/21's requirement and is too narrow here: it locks out Node 18/19 needed by the Angular 18/19 users this PR still supports, plus odd majors. Bump to a wide lower bound at the true floor of the oldest supported Angular (18 β†’ 18.19.1). Angular CLI enforces its own stricter per-version Node gate, so we only need a sane floor, not a duplicate of it. * ci: run "Build and test" on pull requests + enable manual dispatch The workflow only triggered on push to main/big-update, so pull requests (including this one) received no CI at all. Add a pull_request trigger (targeting main) so PRs are validated before merge, plus workflow_dispatch for on-demand runs (becomes usable once this lands on the default branch). * ci: drop completed big-update branch from push triggers
1 parent 1694071 commit 4820980

5 files changed

Lines changed: 120 additions & 10 deletions

File tree

β€Ž.github/workflows/main.ymlβ€Ž

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ name: Build and test
22

33
on:
44
push:
5-
branches: [main, big-update]
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
workflow_dispatch:
69

710
jobs:
811
build-and-test:
@@ -124,3 +127,16 @@ jobs:
124127
npx ng deploy
125128
cd /tmp/remote-21.git && git branch | grep gh-pages
126129
echo "Angular 21: build + deploy successful"
130+
131+
- name: Test Angular 22
132+
run: |
133+
cd /tmp
134+
git init --bare remote-22.git
135+
npx @angular/cli@22 new test-app-22 --defaults
136+
cd test-app-22
137+
git remote add origin /tmp/remote-22.git
138+
npm link angular-cli-ghpages
139+
npx ng add angular-cli-ghpages
140+
npx ng deploy
141+
cd /tmp/remote-22.git && git branch | grep gh-pages
142+
echo "Angular 22: build + deploy successful"

β€ŽREADME.mdβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040

4141
A detailed changelog is available in the [releases](https://github.com/angular-schule/angular-cli-ghpages/releases) section.
4242

43-
`angular-cli-ghpages` v3 supports Angular 18 to 21.
43+
`angular-cli-ghpages` v3 supports Angular 18 to 22.
4444
For previous versions of Angular, use v1 or v2.
4545

4646
## ⚠️ Prerequisites <a name="prerequisites"></a>

β€Žsrc/package.jsonβ€Ž

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
22
"name": "angular-cli-ghpages",
3-
"version": "3.0.3",
3+
"version": "3.1.0",
44
"description": "Deploy your Angular app to GitHub Pages or Cloudflare Pages directly from the Angular CLI (ng deploy)",
55
"main": "index.js",
66
"types": "index.d.ts",
77
"engines": {
8-
"node": ">=18.0.0",
8+
"node": ">=18.19.1",
99
"npm": ">=9.0.0"
1010
},
1111
"bin": {
@@ -71,12 +71,12 @@
7171
"typescript": "~5.2.2"
7272
},
7373
"dependencies": {
74-
"@angular-devkit/architect": ">=0.1800.0 <0.2200.0",
75-
"@angular-devkit/core": ">=18.0.0 <22.0.0",
76-
"@angular-devkit/schematics": ">=18.0.0 <22.0.0",
74+
"@angular-devkit/architect": ">=0.1800.0 <0.2300.0",
75+
"@angular-devkit/core": ">=18.0.0 <23.0.0",
76+
"@angular-devkit/schematics": ">=18.0.0 <23.0.0",
7777
"gh-pages": "6.3.0"
7878
},
7979
"peerDependencies": {
80-
"@angular/cli": ">=18.0.0 <22.0.0"
80+
"@angular/cli": ">=18.0.0 <23.0.0"
8181
}
8282
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
{
2+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3+
"version": 1,
4+
"cli": {
5+
"packageManager": "npm"
6+
},
7+
"newProjectRoot": "projects",
8+
"projects": {
9+
"ng22": {
10+
"projectType": "application",
11+
"schematics": {},
12+
"root": "",
13+
"sourceRoot": "src",
14+
"prefix": "app",
15+
"architect": {
16+
"build": {
17+
"builder": "@angular/build:application",
18+
"options": {
19+
"browser": "src/main.ts",
20+
"tsConfig": "tsconfig.app.json",
21+
"assets": [
22+
{
23+
"glob": "**/*",
24+
"input": "public"
25+
}
26+
],
27+
"styles": [
28+
"src/styles.css"
29+
]
30+
},
31+
"configurations": {
32+
"production": {
33+
"budgets": [
34+
{
35+
"type": "initial",
36+
"maximumWarning": "500kB",
37+
"maximumError": "1MB"
38+
},
39+
{
40+
"type": "anyComponentStyle",
41+
"maximumWarning": "4kB",
42+
"maximumError": "8kB"
43+
}
44+
],
45+
"outputHashing": "all"
46+
},
47+
"development": {
48+
"optimization": false,
49+
"extractLicenses": false,
50+
"sourceMap": true
51+
}
52+
},
53+
"defaultConfiguration": "production"
54+
},
55+
"serve": {
56+
"builder": "@angular/build:dev-server",
57+
"configurations": {
58+
"production": {
59+
"buildTarget": "ng22:build:production"
60+
},
61+
"development": {
62+
"buildTarget": "ng22:build:development"
63+
}
64+
},
65+
"defaultConfiguration": "development"
66+
},
67+
"test": {
68+
"builder": "@angular/build:unit-test"
69+
}
70+
}
71+
}
72+
}
73+
}

β€Žsrc/test-fixtures/angular-versions.spec.tsβ€Ž

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
* Key difference relevant to us:
99
* - Angular 18-19: outputPath is a string like "dist/<project>"
10-
* - Angular 20-21: outputPath is MISSING (uses default dist/<project>)
10+
* - Angular 20-22: outputPath is MISSING (uses default dist/<project>)
1111
*/
1212

1313
import { SchematicContext, Tree } from '@angular-devkit/schematics';
@@ -34,6 +34,7 @@ const angular18Config = JSON.parse(fs.readFileSync(path.join(fixturesDir, 'angul
3434
const angular19Config = JSON.parse(fs.readFileSync(path.join(fixturesDir, 'angular-19.json'), 'utf-8'));
3535
const angular20Config = JSON.parse(fs.readFileSync(path.join(fixturesDir, 'angular-20.json'), 'utf-8'));
3636
const angular21Config = JSON.parse(fs.readFileSync(path.join(fixturesDir, 'angular-21.json'), 'utf-8'));
37+
const angular22Config = JSON.parse(fs.readFileSync(path.join(fixturesDir, 'angular-22.json'), 'utf-8'));
3738

3839
describe('Angular Version Compatibility', () => {
3940
describe('Angular 18', () => {
@@ -104,26 +105,46 @@ describe('Angular Version Compatibility', () => {
104105
});
105106
});
106107

108+
describe('Angular 22', () => {
109+
it('has NO outputPath (uses default)', () => {
110+
const options = angular22Config.projects.ng22.architect.build.options;
111+
expect(options.outputPath).toBeUndefined();
112+
});
113+
114+
it('ng add succeeds despite missing outputPath', async () => {
115+
const tree = Tree.empty();
116+
tree.create('angular.json', JSON.stringify(angular22Config));
117+
118+
const result = await ngAdd({ project: 'ng22' })(tree, mockContext);
119+
const resultConfig = JSON.parse(result.read('angular.json')!.toString());
120+
121+
expect(resultConfig.projects.ng22.architect.deploy.builder).toBe('angular-cli-ghpages:deploy');
122+
});
123+
});
124+
107125
describe('Cross-version compatibility', () => {
108126
it('all versions have projectType: application', () => {
109127
expect(angular18Config.projects.ng18.projectType).toBe('application');
110128
expect(angular19Config.projects.ng19.projectType).toBe('application');
111129
expect(angular20Config.projects.ng20.projectType).toBe('application');
112130
expect(angular21Config.projects.ng21.projectType).toBe('application');
131+
expect(angular22Config.projects.ng22.projectType).toBe('application');
113132
});
114133

115134
it('all versions have build target', () => {
116135
expect(angular18Config.projects.ng18.architect.build).toBeDefined();
117136
expect(angular19Config.projects.ng19.architect.build).toBeDefined();
118137
expect(angular20Config.projects.ng20.architect.build).toBeDefined();
119138
expect(angular21Config.projects.ng21.architect.build).toBeDefined();
139+
expect(angular22Config.projects.ng22.architect.build).toBeDefined();
120140
});
121141

122-
it('outputPath evolution: string β†’ string β†’ undefined β†’ undefined', () => {
142+
it('outputPath evolution: string β†’ string β†’ undefined β†’ undefined β†’ undefined', () => {
123143
expect(typeof angular18Config.projects.ng18.architect.build.options.outputPath).toBe('string');
124144
expect(typeof angular19Config.projects.ng19.architect.build.options.outputPath).toBe('string');
125145
expect(angular20Config.projects.ng20.architect.build.options.outputPath).toBeUndefined();
126146
expect(angular21Config.projects.ng21.architect.build.options.outputPath).toBeUndefined();
147+
expect(angular22Config.projects.ng22.architect.build.options.outputPath).toBeUndefined();
127148
});
128149
});
129150
});

0 commit comments

Comments
Β (0)