Skip to content

Commit 69ecdda

Browse files
alan-agius4dgp1130
authored andcommitted
feat(@schematics/angular): update new and existing projects compilation target to ES2020
With this change we update the TypeScript compilation target to `ES2020` for both new and existing projects. This is because all browsers that Angular supports (https://angular.io/guide/browser-support) support `ES2020` features without the need for polyfills.
1 parent b308235 commit 69ecdda

File tree

13 files changed

+205
-22
lines changed

13 files changed

+205
-22
lines changed

packages/angular_devkit/build_angular/src/builders/browser/specs/allow-js_spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ describe('Browser Builder allow js', () => {
2929
'src/main.ts': `import { a } from './my-js-file'; console.log(a);`,
3030
});
3131

32-
host.replaceInFile('tsconfig.json', '"target": "es2017"', '"target": "es5", "allowJs": true');
32+
host.replaceInFile('tsconfig.json', '"target": "es2020"', '"target": "es5", "allowJs": true');
3333

3434
const run = await architect.scheduleTarget(targetSpec);
3535
const output = (await run.result) as BrowserBuilderOutput;
@@ -50,7 +50,7 @@ describe('Browser Builder allow js', () => {
5050
'src/main.ts': `import { a } from './my-js-file'; console.log(a);`,
5151
});
5252

53-
host.replaceInFile('tsconfig.json', '"target": "es2017"', '"target": "es5", "allowJs": true');
53+
host.replaceInFile('tsconfig.json', '"target": "es2020"', '"target": "es5", "allowJs": true');
5454

5555
const overrides = { aot: true };
5656

@@ -73,7 +73,7 @@ describe('Browser Builder allow js', () => {
7373
'src/main.ts': `import { a } from './my-js-file'; console.log(a);`,
7474
});
7575

76-
host.replaceInFile('tsconfig.json', '"target": "es2017"', '"target": "es5", "allowJs": true');
76+
host.replaceInFile('tsconfig.json', '"target": "es2020"', '"target": "es5", "allowJs": true');
7777

7878
const overrides = { watch: true };
7979

packages/angular_devkit/build_angular/src/builders/browser/specs/lazy-module_spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ describe('Browser Builder lazy modules', () => {
152152
const { files } = await browserBuild(architect, host, target);
153153
expect(files['src_one_ts.js']).not.toBeUndefined();
154154
expect(files['src_two_ts.js']).not.toBeUndefined();
155-
expect(files['default-node_modules_angular_common_fesm2015_http_mjs.js']).toBeDefined();
155+
expect(files['default-node_modules_angular_common_fesm2020_http_mjs.js']).toBeDefined();
156156
});
157157

158158
it(`supports disabling the common bundle`, async () => {
@@ -165,6 +165,6 @@ describe('Browser Builder lazy modules', () => {
165165
const { files } = await browserBuild(architect, host, target, { commonChunk: false });
166166
expect(files['src_one_ts.js']).not.toBeUndefined();
167167
expect(files['src_two_ts.js']).not.toBeUndefined();
168-
expect(files['default-node_modules_angular_common_fesm2015_http_mjs.js']).toBeUndefined();
168+
expect(files['default-node_modules_angular_common_fesm2020_http_mjs.js']).toBeUndefined();
169169
});
170170
});

packages/angular_devkit/build_angular/src/builders/browser/specs/resolve-json-module_spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ describe('Browser Builder resolve json module', () => {
2929

3030
host.replaceInFile(
3131
'tsconfig.json',
32-
'"target": "es2017"',
32+
'"target": "es2020"',
3333
'"target": "es5", "resolveJsonModule": true',
3434
);
3535

packages/angular_devkit/build_angular/test/hello-world-app/tsconfig.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
"moduleResolution": "node",
99
"emitDecoratorMetadata": true,
1010
"experimentalDecorators": true,
11-
"target": "es2017",
11+
"target": "es2020",
1212
"module": "es2020",
1313
"typeRoots": [
1414
"node_modules/@types"
1515
],
1616
"lib": [
17-
"es2017",
17+
"es2020",
1818
"dom"
1919
]
2020
},

packages/angular_devkit/build_angular/test/hello-world-lib/tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"node_modules/@types"
1414
],
1515
"lib": [
16-
"es2017",
16+
"es2020",
1717
"dom"
1818
]
1919
},

packages/angular_devkit/build_webpack/test/angular-app/tsconfig.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
"moduleResolution": "node",
99
"emitDecoratorMetadata": true,
1010
"experimentalDecorators": true,
11-
"target": "es2017",
11+
"target": "es2020",
1212
"typeRoots": ["node_modules/@types"],
13-
"lib": ["es2017", "dom"]
13+
"lib": ["es2020", "dom"]
1414
},
1515
"angularCompilerOptions": {
1616
"enableIvy": true,

packages/angular_devkit/build_webpack/test/basic-app/tsconfig.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
"declaration": false,
88
"moduleResolution": "node",
99
"experimentalDecorators": true,
10-
"target": "es2017",
10+
"target": "es2020",
1111
"module": "esnext",
1212
"typeRoots": ["node_modules/@types"],
13-
"lib": ["es2017", "dom"]
13+
"lib": ["es2020", "dom"]
1414
},
1515
"angularCompilerOptions": {
1616
"disableTypeScriptVersionCheck": true

packages/schematics/angular/migrations/migration-collection.json

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
"version": "14.0.0",
55
"factory": "./update-14/angular-packages-version-prefix",
66
"description": "Update Angular packages 'dependencies' and 'devDependencies' version prefix to '^' instead of '~'."
7+
},
8+
"update-tsconfig-target": {
9+
"version": "14.0.0",
10+
"factory": "./update-14/update-tsconfig-target",
11+
"description": "Update TypeScript compilation target to 'ES2020'."
712
}
813
}
914
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { Rule } from '@angular-devkit/schematics';
10+
import { JSONFile } from '../../utility/json-file';
11+
import { getWorkspace } from '../../utility/workspace';
12+
import { Builders } from '../../utility/workspace-models';
13+
14+
/** Migration to update tsconfig compilation target option to es2020. */
15+
export default function (): Rule {
16+
return async (host) => {
17+
/** Builders for which the migration will run. */
18+
const supportedBuilders = [Builders.Karma, Builders.NgPackagr, Builders.Browser];
19+
20+
/** Compilation targets values that should not be amended. */
21+
const skipTargets = ['es2020', 'es2021', 'es2022', 'esnext'];
22+
23+
const uniqueTsConfigs = new Set(['/tsconfig.json']);
24+
25+
// Find all tsconfig files which are refereced by the builders.
26+
const workspace = await getWorkspace(host);
27+
for (const project of workspace.projects.values()) {
28+
for (const target of project.targets.values()) {
29+
if (!supportedBuilders.includes(target.builder as Builders)) {
30+
// Unknown builder.
31+
continue;
32+
}
33+
34+
// Update all other known CLI builders that use a tsconfig.
35+
const allOptions = [target.options ?? {}, ...Object.values(target.configurations ?? {})];
36+
for (const opt of allOptions) {
37+
if (typeof opt?.tsConfig === 'string') {
38+
uniqueTsConfigs.add(opt.tsConfig);
39+
}
40+
}
41+
}
42+
}
43+
44+
// Modify tsconfig files
45+
const targetJsonPath = ['compilerOptions', 'target'];
46+
for (const tsConfigPath of uniqueTsConfigs) {
47+
const json = new JSONFile(host, tsConfigPath);
48+
const target = json.get(targetJsonPath);
49+
50+
// Update compilation target when it's current set lower than es2020.
51+
if (typeof target === 'string' && !skipTargets.includes(target.toLowerCase())) {
52+
json.modify(targetJsonPath, 'es2020');
53+
}
54+
}
55+
};
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { EmptyTree } from '@angular-devkit/schematics';
10+
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
11+
import { parse as parseJson } from 'jsonc-parser';
12+
import { Builders, ProjectType, WorkspaceSchema } from '../../utility/workspace-models';
13+
14+
describe('Migration to update target compiler options', () => {
15+
const schematicName = 'update-tsconfig-target';
16+
const schematicRunner = new SchematicTestRunner(
17+
'migrations',
18+
require.resolve('../migration-collection.json'),
19+
);
20+
21+
function createJsonFile(tree: UnitTestTree, filePath: string, content: {}) {
22+
tree.create(filePath, JSON.stringify(content, undefined, 2));
23+
}
24+
25+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
26+
function readJsonFile(tree: UnitTestTree, filePath: string): any {
27+
return parseJson(tree.readContent(filePath).toString());
28+
}
29+
30+
let tree: UnitTestTree;
31+
32+
beforeEach(() => {
33+
tree = new UnitTestTree(new EmptyTree());
34+
35+
// Workspace configuration
36+
const angularConfig: WorkspaceSchema = {
37+
version: 1,
38+
projects: {
39+
app: {
40+
root: '',
41+
sourceRoot: 'src',
42+
projectType: ProjectType.Application,
43+
prefix: 'app',
44+
architect: {
45+
build: {
46+
builder: Builders.Browser,
47+
options: {
48+
tsConfig: 'src/tsconfig.app.json',
49+
main: '',
50+
polyfills: '',
51+
},
52+
configurations: {
53+
production: {
54+
tsConfig: 'src/tsconfig.app.prod.json',
55+
},
56+
},
57+
},
58+
test: {
59+
builder: Builders.Karma,
60+
options: {
61+
karmaConfig: '',
62+
tsConfig: 'src/tsconfig.spec.json',
63+
},
64+
},
65+
server: {
66+
builder: Builders.Server,
67+
options: {
68+
tsConfig: 'src/tsconfig.server.json',
69+
outputPath: '',
70+
main: '',
71+
},
72+
},
73+
},
74+
},
75+
},
76+
};
77+
78+
createJsonFile(tree, 'angular.json', angularConfig);
79+
80+
// Create tsconfigs
81+
const compilerOptions = { target: 'es5', module: 'esnext' };
82+
83+
// Workspace
84+
createJsonFile(tree, 'tsconfig.json', { compilerOptions });
85+
86+
// Application
87+
createJsonFile(tree, 'src/tsconfig.app.json', { compilerOptions });
88+
createJsonFile(tree, 'src/tsconfig.app.prod.json', { compilerOptions });
89+
createJsonFile(tree, 'src/tsconfig.spec.json', { compilerOptions });
90+
91+
// Server
92+
createJsonFile(tree, 'src/tsconfig.server.json', { compilerOptions });
93+
});
94+
95+
it(`should update target in workspace 'tsconfig.json'`, async () => {
96+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
97+
const { target } = readJsonFile(newTree, 'tsconfig.json').compilerOptions;
98+
expect(target).toBe('es2020');
99+
});
100+
101+
it(`should update target in 'tsconfig.json' which is referenced in option`, async () => {
102+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
103+
const { target } = readJsonFile(newTree, 'src/tsconfig.spec.json').compilerOptions;
104+
expect(target).toBe('es2020');
105+
});
106+
107+
it(`should update target in 'tsconfig.json' which is referenced in a configuration`, async () => {
108+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
109+
const { target } = readJsonFile(newTree, 'src/tsconfig.app.prod.json').compilerOptions;
110+
expect(target).toBe('es2020');
111+
});
112+
113+
it(`should not update target in 'tsconfig.server.json'`, async () => {
114+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
115+
const { target } = readJsonFile(newTree, 'src/tsconfig.server.json').compilerOptions;
116+
expect(target).toBe('es5');
117+
});
118+
119+
it('should not update target if it is greater than es2020', async () => {
120+
const tsConfigPath = 'src/tsconfig.app.json';
121+
tree.delete(tsConfigPath);
122+
createJsonFile(tree, tsConfigPath, { compilerOptions: { target: 'es2021' } });
123+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
124+
const { target } = readJsonFile(newTree, tsConfigPath).compilerOptions;
125+
expect(target).toBe('es2021');
126+
});
127+
});

packages/schematics/angular/workspace/files/tsconfig.json.template

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"experimentalDecorators": true,
1717
"moduleResolution": "node",
1818
"importHelpers": true,
19-
"target": "es2017",
19+
"target": "es2020",
2020
"module": "es2020",
2121
"lib": [
2222
"es2020",

tests/legacy-cli/e2e/tests/build/prod-build.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ export default async function () {
3737
await expectFileToMatch('dist/test-project/3rdpartylicenses.txt', /MIT/);
3838

3939
const indexContent = await readFile('dist/test-project/index.html');
40-
const mainES2017Path = indexContent.match(/src="(main\.[a-z0-9]{0,32}\.js)"/)[1];
40+
const mainPath = indexContent.match(/src="(main\.[a-z0-9]{0,32}\.js)"/)[1];
4141

4242
// Content checks
43-
await expectFileToMatch(`dist/test-project/${mainES2017Path}`, bootstrapRegExp);
43+
await expectFileToMatch(`dist/test-project/${mainPath}`, bootstrapRegExp);
4444

4545
// Size checks in bytes
46-
verifySize(mainES2017Path, 141032);
46+
verifySize(mainPath, 141032);
4747
}

tests/legacy-cli/e2e/tests/i18n/ivy-localize-es2015.ts

-5
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
import { expectFileNotToExist, expectFileToMatch, readFile, writeFile } from '../../utils/fs';
22
import { ng } from '../../utils/process';
3-
import { updateJsonFile } from '../../utils/project';
43
import { expectToFail } from '../../utils/utils';
54
import { externalServer, langTranslations, setupI18nConfig } from './setup';
65

76
export default async function () {
87
// Setup i18n tests and config.
98
await setupI18nConfig();
109

11-
// Ensure a es2017 build is used.
1210
await writeFile('.browserslistrc', 'Chrome 65');
13-
await updateJsonFile('tsconfig.json', (config) => {
14-
config.compilerOptions.target = 'es2017';
15-
});
1611

1712
await ng('build', '--source-map');
1813
for (const { lang, outputPath, translation } of langTranslations) {

0 commit comments

Comments
 (0)