mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-16 10:33:43 +08:00
feat(@schematics/angular): add migration to enable AOT by default
With this change we enable the AOT option for the browser builder when an application will use Ivy as rendering engine.
This commit is contained in:
parent
87b01ffd6a
commit
f4691a545a
@ -15,7 +15,7 @@ import {
|
||||
removePropertyInAstObject,
|
||||
} from '../../utility/json-utils';
|
||||
import { Builders } from '../../utility/workspace-models';
|
||||
import { getAllOptions, getTargets, getWorkspace } from './utils';
|
||||
import { getAllOptions, getTargets, getWorkspace, isIvyEnabled } from './utils';
|
||||
|
||||
export const ANY_COMPONENT_STYLE_BUDGET = {
|
||||
type: 'anyComponentStyle',
|
||||
@ -32,6 +32,7 @@ export function UpdateWorkspaceConfig(): Rule {
|
||||
updateStyleOrScriptOption('styles', recorder, target);
|
||||
updateStyleOrScriptOption('scripts', recorder, target);
|
||||
addAnyComponentStyleBudget(recorder, target);
|
||||
updateAotOption(tree, recorder, target);
|
||||
}
|
||||
|
||||
for (const { target } of getTargets(workspace, 'test', Builders.Karma)) {
|
||||
@ -45,6 +46,41 @@ export function UpdateWorkspaceConfig(): Rule {
|
||||
};
|
||||
}
|
||||
|
||||
function updateAotOption(tree: Tree, recorder: UpdateRecorder, builderConfig: JsonAstObject) {
|
||||
const options = findPropertyInAstObject(builderConfig, 'options');
|
||||
if (!options || options.kind !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const tsConfig = findPropertyInAstObject(options, 'tsConfig');
|
||||
// Do not add aot option if the users already opted out from Ivy.
|
||||
if (tsConfig && tsConfig.kind === 'string' && !isIvyEnabled(tree, tsConfig.value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add aot to options.
|
||||
const aotOption = findPropertyInAstObject(options, 'aot');
|
||||
|
||||
if (!aotOption) {
|
||||
insertPropertyInAstObjectInOrder(recorder, options, 'aot', true, 12);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (aotOption.kind !== 'true') {
|
||||
const { start, end } = aotOption;
|
||||
recorder.remove(start.offset, end.offset - start.offset);
|
||||
recorder.insertLeft(start.offset, 'true');
|
||||
}
|
||||
|
||||
// Remove aot properties from other configurations as they are no redundant
|
||||
const configOptions = getAllOptions(builderConfig, true);
|
||||
for (const options of configOptions) {
|
||||
removePropertyInAstObject(recorder, options, 'aot');
|
||||
}
|
||||
}
|
||||
|
||||
function updateStyleOrScriptOption(property: 'scripts' | 'styles', recorder: UpdateRecorder, builderConfig: JsonAstObject) {
|
||||
const options = getAllOptions(builderConfig);
|
||||
|
||||
@ -75,12 +111,6 @@ function addAnyComponentStyleBudget(recorder: UpdateRecorder, builderConfig: Jso
|
||||
const options = getAllOptions(builderConfig, true);
|
||||
|
||||
for (const option of options) {
|
||||
const aotOption = findPropertyInAstObject(option, 'aot');
|
||||
if (!aotOption || aotOption.kind !== 'true') {
|
||||
// AnyComponentStyle only works for AOT
|
||||
continue;
|
||||
}
|
||||
|
||||
const budgetOption = findPropertyInAstObject(option, 'budgets');
|
||||
if (!budgetOption) {
|
||||
// add
|
||||
|
@ -169,5 +169,84 @@ describe('Migration to version 9', () => {
|
||||
expect(config.configurations.production.budgets).toEqual([ANY_COMPONENT_STYLE_BUDGET]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('aot option', () => {
|
||||
it('should update aot option when false', async () => {
|
||||
let config = getWorkspaceTargets(tree);
|
||||
config.build.options.aot = false;
|
||||
updateWorkspaceTargets(tree, config);
|
||||
|
||||
const tree2 = await schematicRunner.runSchematicAsync('migration-09', {}, tree.branch()).toPromise();
|
||||
config = getWorkspaceTargets(tree2).build;
|
||||
expect(config.options.aot).toBe(true);
|
||||
});
|
||||
|
||||
it('should add aot option when not defined', async () => {
|
||||
let config = getWorkspaceTargets(tree);
|
||||
config.build.options.aot = undefined;
|
||||
updateWorkspaceTargets(tree, config);
|
||||
|
||||
const tree2 = await schematicRunner.runSchematicAsync('migration-09', {}, tree.branch()).toPromise();
|
||||
config = getWorkspaceTargets(tree2).build;
|
||||
expect(config.options.aot).toBe(true);
|
||||
});
|
||||
|
||||
it('should not aot option when opted-out of Ivy', async () => {
|
||||
const tsConfig = JSON.stringify(
|
||||
{
|
||||
extends: './tsconfig.json',
|
||||
angularCompilerOptions: {
|
||||
enableIvy: false,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
);
|
||||
|
||||
tree.overwrite('/tsconfig.app.json', tsConfig);
|
||||
|
||||
let config = getWorkspaceTargets(tree);
|
||||
config.build.options.aot = false;
|
||||
updateWorkspaceTargets(tree, config);
|
||||
|
||||
const tree2 = await schematicRunner.runSchematicAsync('migration-09', {}, tree.branch()).toPromise();
|
||||
config = getWorkspaceTargets(tree2).build;
|
||||
expect(config.options.aot).toBe(false);
|
||||
});
|
||||
|
||||
it('should not aot option when opted-out of Ivy in workspace', async () => {
|
||||
const tsConfig = JSON.stringify(
|
||||
{
|
||||
angularCompilerOptions: {
|
||||
enableIvy: false,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
);
|
||||
|
||||
tree.overwrite('/tsconfig.json', tsConfig);
|
||||
|
||||
let config = getWorkspaceTargets(tree);
|
||||
config.build.options.aot = false;
|
||||
updateWorkspaceTargets(tree, config);
|
||||
|
||||
const tree2 = await schematicRunner.runSchematicAsync('migration-09', {}, tree.branch()).toPromise();
|
||||
config = getWorkspaceTargets(tree2).build;
|
||||
expect(config.options.aot).toBe(false);
|
||||
});
|
||||
|
||||
it('should remove aot option from production configuration', async () => {
|
||||
let config = getWorkspaceTargets(tree);
|
||||
config.build.options.aot = false;
|
||||
config.build.configurations.production.aot = true;
|
||||
updateWorkspaceTargets(tree, config);
|
||||
|
||||
const tree2 = await schematicRunner.runSchematicAsync('migration-09', {}, tree.branch()).toPromise();
|
||||
config = getWorkspaceTargets(tree2).build;
|
||||
expect(config.options.aot).toBe(true);
|
||||
expect(config.configurations.production.aot).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import { JsonAstObject, JsonParseMode, parseJsonAst } from '@angular-devkit/core';
|
||||
import { JsonAstObject, JsonParseMode, dirname, normalize, parseJsonAst, resolve } from '@angular-devkit/core';
|
||||
import { SchematicsException, Tree } from '@angular-devkit/schematics';
|
||||
import { getWorkspacePath } from '../../utility/config';
|
||||
import { findPropertyInAstObject } from '../../utility/json-utils';
|
||||
@ -81,3 +81,40 @@ export function getWorkspace(host: Tree): JsonAstObject {
|
||||
|
||||
return parseJsonAst(content, JsonParseMode.Loose) as JsonAstObject;
|
||||
}
|
||||
|
||||
export function isIvyEnabled(tree: Tree, tsConfigPath: string): boolean {
|
||||
// In version 9, Ivy is turned on by default
|
||||
// Ivy is opted out only when 'enableIvy' is set to false.
|
||||
|
||||
const buffer = tree.read(tsConfigPath);
|
||||
if (!buffer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const tsCfgAst = parseJsonAst(buffer.toString(), JsonParseMode.Loose);
|
||||
|
||||
if (tsCfgAst.kind !== 'object') {
|
||||
return true;
|
||||
}
|
||||
|
||||
const ngCompilerOptions = findPropertyInAstObject(tsCfgAst, 'angularCompilerOptions');
|
||||
if (ngCompilerOptions && ngCompilerOptions.kind === 'object') {
|
||||
const enableIvy = findPropertyInAstObject(ngCompilerOptions, 'enableIvy');
|
||||
|
||||
if (enableIvy) {
|
||||
return !!enableIvy.value;
|
||||
}
|
||||
}
|
||||
|
||||
const configExtends = findPropertyInAstObject(tsCfgAst, 'extends');
|
||||
if (configExtends && configExtends.kind === 'string') {
|
||||
const extendedTsConfigPath = resolve(
|
||||
dirname(normalize(tsConfigPath)),
|
||||
normalize(configExtends.value),
|
||||
);
|
||||
|
||||
return isIvyEnabled(tree, extendedTsConfigPath);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
107
packages/schematics/angular/migrations/update-9/utils_spec.ts
Normal file
107
packages/schematics/angular/migrations/update-9/utils_spec.ts
Normal file
@ -0,0 +1,107 @@
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. 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 { HostTree } from '@angular-devkit/schematics';
|
||||
import { isIvyEnabled } from './utils';
|
||||
|
||||
describe('migrations update-9 utils', () => {
|
||||
describe('isIvyEnabled', () => {
|
||||
let tree: HostTree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = new HostTree();
|
||||
});
|
||||
|
||||
it('should return false when disabled in base tsconfig', () => {
|
||||
tree.create('tsconfig.json', JSON.stringify({
|
||||
angularCompilerOptions: {
|
||||
enableIvy: false,
|
||||
},
|
||||
}));
|
||||
|
||||
tree.create('foo/tsconfig.app.json', JSON.stringify({
|
||||
extends: '../tsconfig.json',
|
||||
}));
|
||||
|
||||
expect(isIvyEnabled(tree, 'foo/tsconfig.app.json')).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true when enable in child tsconfig but disabled in base tsconfig', () => {
|
||||
tree.create('tsconfig.json', JSON.stringify({
|
||||
angularCompilerOptions: {
|
||||
enableIvy: false,
|
||||
},
|
||||
}));
|
||||
|
||||
tree.create('foo/tsconfig.app.json', JSON.stringify({
|
||||
extends: '../tsconfig.json',
|
||||
angularCompilerOptions: {
|
||||
enableIvy: true,
|
||||
},
|
||||
}));
|
||||
|
||||
expect(isIvyEnabled(tree, 'foo/tsconfig.app.json')).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when disabled in child tsconfig but enabled in base tsconfig', () => {
|
||||
tree.create('tsconfig.json', JSON.stringify({
|
||||
angularCompilerOptions: {
|
||||
enableIvy: true,
|
||||
},
|
||||
}));
|
||||
|
||||
tree.create('foo/tsconfig.app.json', JSON.stringify({
|
||||
extends: '../tsconfig.json',
|
||||
angularCompilerOptions: {
|
||||
enableIvy: false,
|
||||
},
|
||||
}));
|
||||
|
||||
expect(isIvyEnabled(tree, 'foo/tsconfig.app.json')).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when disabled in base with multiple extends', () => {
|
||||
tree.create('tsconfig.json', JSON.stringify({
|
||||
angularCompilerOptions: {
|
||||
enableIvy: false,
|
||||
},
|
||||
}));
|
||||
|
||||
tree.create('foo/tsconfig.project.json', JSON.stringify({
|
||||
extends: '../tsconfig.json',
|
||||
}));
|
||||
|
||||
tree.create('foo/tsconfig.app.json', JSON.stringify({
|
||||
extends: './tsconfig.project.json',
|
||||
}));
|
||||
|
||||
expect(isIvyEnabled(tree, 'foo/tsconfig.app.json')).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true when enable in intermediate tsconfig with multiple extends', () => {
|
||||
tree.create('tsconfig.json', JSON.stringify({
|
||||
angularCompilerOptions: {
|
||||
enableIvy: false,
|
||||
},
|
||||
}));
|
||||
|
||||
tree.create('foo/tsconfig.project.json', JSON.stringify({
|
||||
extends: '../tsconfig.json',
|
||||
angularCompilerOptions: {
|
||||
enableIvy: true,
|
||||
},
|
||||
}));
|
||||
|
||||
tree.create('foo/tsconfig.app.json', JSON.stringify({
|
||||
extends: './tsconfig.project.json',
|
||||
}));
|
||||
|
||||
expect(isIvyEnabled(tree, 'foo/tsconfig.app.json')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user