mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-15 18:13:38 +08:00
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.
This commit is contained in:
parent
b3082355c0
commit
69ecddaa7d
@ -29,7 +29,7 @@ describe('Browser Builder allow js', () => {
|
||||
'src/main.ts': `import { a } from './my-js-file'; console.log(a);`,
|
||||
});
|
||||
|
||||
host.replaceInFile('tsconfig.json', '"target": "es2017"', '"target": "es5", "allowJs": true');
|
||||
host.replaceInFile('tsconfig.json', '"target": "es2020"', '"target": "es5", "allowJs": true');
|
||||
|
||||
const run = await architect.scheduleTarget(targetSpec);
|
||||
const output = (await run.result) as BrowserBuilderOutput;
|
||||
@ -50,7 +50,7 @@ describe('Browser Builder allow js', () => {
|
||||
'src/main.ts': `import { a } from './my-js-file'; console.log(a);`,
|
||||
});
|
||||
|
||||
host.replaceInFile('tsconfig.json', '"target": "es2017"', '"target": "es5", "allowJs": true');
|
||||
host.replaceInFile('tsconfig.json', '"target": "es2020"', '"target": "es5", "allowJs": true');
|
||||
|
||||
const overrides = { aot: true };
|
||||
|
||||
@ -73,7 +73,7 @@ describe('Browser Builder allow js', () => {
|
||||
'src/main.ts': `import { a } from './my-js-file'; console.log(a);`,
|
||||
});
|
||||
|
||||
host.replaceInFile('tsconfig.json', '"target": "es2017"', '"target": "es5", "allowJs": true');
|
||||
host.replaceInFile('tsconfig.json', '"target": "es2020"', '"target": "es5", "allowJs": true');
|
||||
|
||||
const overrides = { watch: true };
|
||||
|
||||
|
@ -152,7 +152,7 @@ describe('Browser Builder lazy modules', () => {
|
||||
const { files } = await browserBuild(architect, host, target);
|
||||
expect(files['src_one_ts.js']).not.toBeUndefined();
|
||||
expect(files['src_two_ts.js']).not.toBeUndefined();
|
||||
expect(files['default-node_modules_angular_common_fesm2015_http_mjs.js']).toBeDefined();
|
||||
expect(files['default-node_modules_angular_common_fesm2020_http_mjs.js']).toBeDefined();
|
||||
});
|
||||
|
||||
it(`supports disabling the common bundle`, async () => {
|
||||
@ -165,6 +165,6 @@ describe('Browser Builder lazy modules', () => {
|
||||
const { files } = await browserBuild(architect, host, target, { commonChunk: false });
|
||||
expect(files['src_one_ts.js']).not.toBeUndefined();
|
||||
expect(files['src_two_ts.js']).not.toBeUndefined();
|
||||
expect(files['default-node_modules_angular_common_fesm2015_http_mjs.js']).toBeUndefined();
|
||||
expect(files['default-node_modules_angular_common_fesm2020_http_mjs.js']).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
@ -29,7 +29,7 @@ describe('Browser Builder resolve json module', () => {
|
||||
|
||||
host.replaceInFile(
|
||||
'tsconfig.json',
|
||||
'"target": "es2017"',
|
||||
'"target": "es2020"',
|
||||
'"target": "es5", "resolveJsonModule": true',
|
||||
);
|
||||
|
||||
|
@ -8,13 +8,13 @@
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es2017",
|
||||
"target": "es2020",
|
||||
"module": "es2020",
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
],
|
||||
"lib": [
|
||||
"es2017",
|
||||
"es2020",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
|
@ -13,7 +13,7 @@
|
||||
"node_modules/@types"
|
||||
],
|
||||
"lib": [
|
||||
"es2017",
|
||||
"es2020",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
|
@ -8,9 +8,9 @@
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es2017",
|
||||
"target": "es2020",
|
||||
"typeRoots": ["node_modules/@types"],
|
||||
"lib": ["es2017", "dom"]
|
||||
"lib": ["es2020", "dom"]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": true,
|
||||
|
@ -7,10 +7,10 @@
|
||||
"declaration": false,
|
||||
"moduleResolution": "node",
|
||||
"experimentalDecorators": true,
|
||||
"target": "es2017",
|
||||
"target": "es2020",
|
||||
"module": "esnext",
|
||||
"typeRoots": ["node_modules/@types"],
|
||||
"lib": ["es2017", "dom"]
|
||||
"lib": ["es2020", "dom"]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"disableTypeScriptVersionCheck": true
|
||||
|
@ -4,6 +4,11 @@
|
||||
"version": "14.0.0",
|
||||
"factory": "./update-14/angular-packages-version-prefix",
|
||||
"description": "Update Angular packages 'dependencies' and 'devDependencies' version prefix to '^' instead of '~'."
|
||||
},
|
||||
"update-tsconfig-target": {
|
||||
"version": "14.0.0",
|
||||
"factory": "./update-14/update-tsconfig-target",
|
||||
"description": "Update TypeScript compilation target to 'ES2020'."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import { Rule } from '@angular-devkit/schematics';
|
||||
import { JSONFile } from '../../utility/json-file';
|
||||
import { getWorkspace } from '../../utility/workspace';
|
||||
import { Builders } from '../../utility/workspace-models';
|
||||
|
||||
/** Migration to update tsconfig compilation target option to es2020. */
|
||||
export default function (): Rule {
|
||||
return async (host) => {
|
||||
/** Builders for which the migration will run. */
|
||||
const supportedBuilders = [Builders.Karma, Builders.NgPackagr, Builders.Browser];
|
||||
|
||||
/** Compilation targets values that should not be amended. */
|
||||
const skipTargets = ['es2020', 'es2021', 'es2022', 'esnext'];
|
||||
|
||||
const uniqueTsConfigs = new Set(['/tsconfig.json']);
|
||||
|
||||
// Find all tsconfig files which are refereced by the builders.
|
||||
const workspace = await getWorkspace(host);
|
||||
for (const project of workspace.projects.values()) {
|
||||
for (const target of project.targets.values()) {
|
||||
if (!supportedBuilders.includes(target.builder as Builders)) {
|
||||
// Unknown builder.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Update all other known CLI builders that use a tsconfig.
|
||||
const allOptions = [target.options ?? {}, ...Object.values(target.configurations ?? {})];
|
||||
for (const opt of allOptions) {
|
||||
if (typeof opt?.tsConfig === 'string') {
|
||||
uniqueTsConfigs.add(opt.tsConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modify tsconfig files
|
||||
const targetJsonPath = ['compilerOptions', 'target'];
|
||||
for (const tsConfigPath of uniqueTsConfigs) {
|
||||
const json = new JSONFile(host, tsConfigPath);
|
||||
const target = json.get(targetJsonPath);
|
||||
|
||||
// Update compilation target when it's current set lower than es2020.
|
||||
if (typeof target === 'string' && !skipTargets.includes(target.toLowerCase())) {
|
||||
json.modify(targetJsonPath, 'es2020');
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import { EmptyTree } from '@angular-devkit/schematics';
|
||||
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
|
||||
import { parse as parseJson } from 'jsonc-parser';
|
||||
import { Builders, ProjectType, WorkspaceSchema } from '../../utility/workspace-models';
|
||||
|
||||
describe('Migration to update target compiler options', () => {
|
||||
const schematicName = 'update-tsconfig-target';
|
||||
const schematicRunner = new SchematicTestRunner(
|
||||
'migrations',
|
||||
require.resolve('../migration-collection.json'),
|
||||
);
|
||||
|
||||
function createJsonFile(tree: UnitTestTree, filePath: string, content: {}) {
|
||||
tree.create(filePath, JSON.stringify(content, undefined, 2));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function readJsonFile(tree: UnitTestTree, filePath: string): any {
|
||||
return parseJson(tree.readContent(filePath).toString());
|
||||
}
|
||||
|
||||
let tree: UnitTestTree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = new UnitTestTree(new EmptyTree());
|
||||
|
||||
// Workspace configuration
|
||||
const angularConfig: WorkspaceSchema = {
|
||||
version: 1,
|
||||
projects: {
|
||||
app: {
|
||||
root: '',
|
||||
sourceRoot: 'src',
|
||||
projectType: ProjectType.Application,
|
||||
prefix: 'app',
|
||||
architect: {
|
||||
build: {
|
||||
builder: Builders.Browser,
|
||||
options: {
|
||||
tsConfig: 'src/tsconfig.app.json',
|
||||
main: '',
|
||||
polyfills: '',
|
||||
},
|
||||
configurations: {
|
||||
production: {
|
||||
tsConfig: 'src/tsconfig.app.prod.json',
|
||||
},
|
||||
},
|
||||
},
|
||||
test: {
|
||||
builder: Builders.Karma,
|
||||
options: {
|
||||
karmaConfig: '',
|
||||
tsConfig: 'src/tsconfig.spec.json',
|
||||
},
|
||||
},
|
||||
server: {
|
||||
builder: Builders.Server,
|
||||
options: {
|
||||
tsConfig: 'src/tsconfig.server.json',
|
||||
outputPath: '',
|
||||
main: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
createJsonFile(tree, 'angular.json', angularConfig);
|
||||
|
||||
// Create tsconfigs
|
||||
const compilerOptions = { target: 'es5', module: 'esnext' };
|
||||
|
||||
// Workspace
|
||||
createJsonFile(tree, 'tsconfig.json', { compilerOptions });
|
||||
|
||||
// Application
|
||||
createJsonFile(tree, 'src/tsconfig.app.json', { compilerOptions });
|
||||
createJsonFile(tree, 'src/tsconfig.app.prod.json', { compilerOptions });
|
||||
createJsonFile(tree, 'src/tsconfig.spec.json', { compilerOptions });
|
||||
|
||||
// Server
|
||||
createJsonFile(tree, 'src/tsconfig.server.json', { compilerOptions });
|
||||
});
|
||||
|
||||
it(`should update target in workspace 'tsconfig.json'`, async () => {
|
||||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
|
||||
const { target } = readJsonFile(newTree, 'tsconfig.json').compilerOptions;
|
||||
expect(target).toBe('es2020');
|
||||
});
|
||||
|
||||
it(`should update target in 'tsconfig.json' which is referenced in option`, async () => {
|
||||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
|
||||
const { target } = readJsonFile(newTree, 'src/tsconfig.spec.json').compilerOptions;
|
||||
expect(target).toBe('es2020');
|
||||
});
|
||||
|
||||
it(`should update target in 'tsconfig.json' which is referenced in a configuration`, async () => {
|
||||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
|
||||
const { target } = readJsonFile(newTree, 'src/tsconfig.app.prod.json').compilerOptions;
|
||||
expect(target).toBe('es2020');
|
||||
});
|
||||
|
||||
it(`should not update target in 'tsconfig.server.json'`, async () => {
|
||||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
|
||||
const { target } = readJsonFile(newTree, 'src/tsconfig.server.json').compilerOptions;
|
||||
expect(target).toBe('es5');
|
||||
});
|
||||
|
||||
it('should not update target if it is greater than es2020', async () => {
|
||||
const tsConfigPath = 'src/tsconfig.app.json';
|
||||
tree.delete(tsConfigPath);
|
||||
createJsonFile(tree, tsConfigPath, { compilerOptions: { target: 'es2021' } });
|
||||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
|
||||
const { target } = readJsonFile(newTree, tsConfigPath).compilerOptions;
|
||||
expect(target).toBe('es2021');
|
||||
});
|
||||
});
|
@ -16,7 +16,7 @@
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "es2017",
|
||||
"target": "es2020",
|
||||
"module": "es2020",
|
||||
"lib": [
|
||||
"es2020",
|
||||
|
@ -37,11 +37,11 @@ export default async function () {
|
||||
await expectFileToMatch('dist/test-project/3rdpartylicenses.txt', /MIT/);
|
||||
|
||||
const indexContent = await readFile('dist/test-project/index.html');
|
||||
const mainES2017Path = indexContent.match(/src="(main\.[a-z0-9]{0,32}\.js)"/)[1];
|
||||
const mainPath = indexContent.match(/src="(main\.[a-z0-9]{0,32}\.js)"/)[1];
|
||||
|
||||
// Content checks
|
||||
await expectFileToMatch(`dist/test-project/${mainES2017Path}`, bootstrapRegExp);
|
||||
await expectFileToMatch(`dist/test-project/${mainPath}`, bootstrapRegExp);
|
||||
|
||||
// Size checks in bytes
|
||||
verifySize(mainES2017Path, 141032);
|
||||
verifySize(mainPath, 141032);
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { expectFileNotToExist, expectFileToMatch, readFile, writeFile } from '../../utils/fs';
|
||||
import { ng } from '../../utils/process';
|
||||
import { updateJsonFile } from '../../utils/project';
|
||||
import { expectToFail } from '../../utils/utils';
|
||||
import { externalServer, langTranslations, setupI18nConfig } from './setup';
|
||||
|
||||
@ -8,11 +7,7 @@ export default async function () {
|
||||
// Setup i18n tests and config.
|
||||
await setupI18nConfig();
|
||||
|
||||
// Ensure a es2017 build is used.
|
||||
await writeFile('.browserslistrc', 'Chrome 65');
|
||||
await updateJsonFile('tsconfig.json', (config) => {
|
||||
config.compilerOptions.target = 'es2017';
|
||||
});
|
||||
|
||||
await ng('build', '--source-map');
|
||||
for (const { lang, outputPath, translation } of langTranslations) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user