-
Notifications
You must be signed in to change notification settings - Fork 12k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(@schematics/angular): update compiler options target and module …
…settings With this change we update the target and module settings of various compilation units. - We replace ES5 target in protractor. Protractor runs on Node.Js which support ES2018 - For applications we now use `ES2020` instead of `ESNext` as a module to avoid unexpected changes in behaviour This changes also adds a migration to update existing projects and also removes `module` from the Universal tsconfig as per #17352 to enable lazy loading on the server.
- Loading branch information
1 parent
13b0763
commit 0fd3c55
Showing
15 changed files
with
283 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
124 changes: 124 additions & 0 deletions
124
...ages/schematics/angular/migrations/update-10/update-module-and-target-compiler-options.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
/** | ||
* @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 { dirname, join, normalize } from '@angular-devkit/core'; | ||
import { Rule, Tree } from '@angular-devkit/schematics'; | ||
import { findPropertyInAstObject, removePropertyInAstObject } from '../../utility/json-utils'; | ||
import { getWorkspace } from '../../utility/workspace'; | ||
import { Builders } from '../../utility/workspace-models'; | ||
import { readJsonFileAsAstObject } from '../update-9/utils'; | ||
|
||
|
||
interface ModuleAndTargetReplamenent { | ||
oldModule?: string; | ||
newModule?: string | false; | ||
oldTarget?: string; | ||
newTarget?: string; | ||
} | ||
|
||
export default function (): Rule { | ||
return async host => { | ||
// Workspace level tsconfig | ||
updateModuleAndTarget(host, 'tsconfig.json', { | ||
oldModule: 'esnext', | ||
newModule: 'es2020', | ||
}); | ||
|
||
const workspace = await getWorkspace(host); | ||
// Find all tsconfig which are refereces used by builders | ||
for (const [, project] of workspace.projects) { | ||
for (const [, target] of project.targets) { | ||
// E2E builder doesn't reference a tsconfig but it uses one found in the root folder. | ||
if (target.builder === Builders.Protractor && typeof target.options?.protractorConfig === 'string') { | ||
const tsConfigPath = join(dirname(normalize(target.options.protractorConfig)), 'tsconfig.json'); | ||
|
||
updateModuleAndTarget(host, tsConfigPath, { | ||
oldTarget: 'es5', | ||
newTarget: 'es2018', | ||
}); | ||
|
||
continue; | ||
} | ||
|
||
// Update all other known CLI builders that use a tsconfig | ||
const tsConfigs = [ | ||
target.options || {}, | ||
...Object.values(target.configurations || {}), | ||
] | ||
.filter(opt => typeof opt?.tsConfig === 'string') | ||
.map(opt => (opt as { tsConfig: string }).tsConfig); | ||
|
||
const uniqueTsConfigs = [...new Set(tsConfigs)]; | ||
|
||
if (uniqueTsConfigs.length < 1) { | ||
continue; | ||
} | ||
|
||
switch (target.builder as Builders) { | ||
case Builders.Server: | ||
uniqueTsConfigs.forEach(p => { | ||
updateModuleAndTarget(host, p, { | ||
oldModule: 'commonjs', | ||
// False will remove the module | ||
// NB: For server we no longer use commonjs because it is bundled using webpack which has it's own module system. | ||
// This ensures that lazy-loaded works on the server. | ||
newModule: false, | ||
}); | ||
}); | ||
break; | ||
case Builders.Karma: | ||
case Builders.Browser: | ||
case Builders.NgPackagr: | ||
uniqueTsConfigs.forEach(p => { | ||
updateModuleAndTarget(host, p, { | ||
oldModule: 'esnext', | ||
newModule: 'es2020', | ||
}); | ||
}); | ||
break; | ||
} | ||
} | ||
} | ||
}; | ||
} | ||
|
||
function updateModuleAndTarget(host: Tree, tsConfigPath: string, replacements: ModuleAndTargetReplamenent) { | ||
const jsonAst = readJsonFileAsAstObject(host, tsConfigPath); | ||
if (!jsonAst) { | ||
return; | ||
} | ||
|
||
const compilerOptionsAst = findPropertyInAstObject(jsonAst, 'compilerOptions'); | ||
if (compilerOptionsAst?.kind !== 'object') { | ||
return; | ||
} | ||
|
||
const { oldTarget, newTarget, newModule, oldModule } = replacements; | ||
|
||
const recorder = host.beginUpdate(tsConfigPath); | ||
if (newTarget) { | ||
const targetAst = findPropertyInAstObject(compilerOptionsAst, 'target'); | ||
if (targetAst?.kind === 'string' && oldTarget === targetAst.value.toLowerCase()) { | ||
const offset = targetAst.start.offset + 1; | ||
recorder.remove(offset, targetAst.value.length); | ||
recorder.insertLeft(offset, newTarget); | ||
} | ||
} | ||
|
||
if (newModule === false) { | ||
removePropertyInAstObject(recorder, compilerOptionsAst, 'module'); | ||
} else if (newModule) { | ||
const moduleAst = findPropertyInAstObject(compilerOptionsAst, 'module'); | ||
if (moduleAst?.kind === 'string' && oldModule === moduleAst.value.toLowerCase()) { | ||
const offset = moduleAst.start.offset + 1; | ||
recorder.remove(offset, moduleAst.value.length); | ||
recorder.insertLeft(offset, newModule); | ||
} | ||
} | ||
|
||
host.commitUpdate(recorder); | ||
} |
141 changes: 141 additions & 0 deletions
141
...schematics/angular/migrations/update-10/update-module-and-target-compiler-options_spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
/** | ||
* @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 { JsonParseMode, parseJson } from '@angular-devkit/core'; | ||
import { EmptyTree } from '@angular-devkit/schematics'; | ||
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; | ||
import { Builders, ProjectType, WorkspaceSchema } from '../../utility/workspace-models'; | ||
|
||
describe('Migration to update target and module compiler options', () => { | ||
const schematicName = 'update-module-and-target-compiler-options'; | ||
|
||
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)); | ||
} | ||
|
||
// tslint:disable-next-line: no-any | ||
function readJsonFile(tree: UnitTestTree, filePath: string): any { | ||
// tslint:disable-next-line: no-any | ||
return parseJson(tree.readContent(filePath).toString(), JsonParseMode.Loose) as any; | ||
} | ||
|
||
function createWorkSpaceConfig(tree: UnitTestTree) { | ||
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', | ||
}, | ||
}, | ||
e2e: { | ||
builder: Builders.Protractor, | ||
options: { | ||
protractorConfig: 'src/e2e/protractor.conf.js', | ||
devServerTarget: '', | ||
}, | ||
}, | ||
server: { | ||
builder: Builders.Server, | ||
options: { | ||
tsConfig: 'src/tsconfig.server.json', | ||
outputPath: '', | ||
main: '', | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
createJsonFile(tree, 'angular.json', angularConfig); | ||
} | ||
|
||
|
||
let tree: UnitTestTree; | ||
beforeEach(() => { | ||
tree = new UnitTestTree(new EmptyTree()); | ||
createWorkSpaceConfig(tree); | ||
|
||
// Create tsconfigs | ||
const compilerOptions = { target: 'es2015', 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 }); | ||
|
||
// E2E | ||
createJsonFile(tree, 'src/e2e/protractor.conf.js', ''); | ||
createJsonFile(tree, 'src/e2e/tsconfig.json', { compilerOptions: { module: 'commonjs', target: 'es5' } }); | ||
|
||
// Universal | ||
createJsonFile(tree, 'src/tsconfig.server.json', { compilerOptions: { module: 'commonjs' } }); | ||
}); | ||
|
||
it(`should update module and target in workspace 'tsconfig.json'`, async () => { | ||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
const { module } = readJsonFile(newTree, 'tsconfig.json').compilerOptions; | ||
expect(module).toBe('es2020'); | ||
}); | ||
|
||
it(`should update module and target in 'tsconfig.json' which is referenced in option`, async () => { | ||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
const { module } = readJsonFile(newTree, 'src/tsconfig.spec.json').compilerOptions; | ||
expect(module).toBe('es2020'); | ||
}); | ||
|
||
it(`should update module and target in 'tsconfig.json' which is referenced in a configuration`, async () => { | ||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
const { module } = readJsonFile(newTree, 'src/tsconfig.app.prod.json').compilerOptions; | ||
expect(module).toBe('es2020'); | ||
}); | ||
|
||
it(`should update target to es2018 in E2E 'tsconfig.json'`, async () => { | ||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
const { module, target } = readJsonFile(newTree, 'src/e2e/tsconfig.json').compilerOptions; | ||
expect(module).toBe('commonjs'); | ||
expect(target).toBe('es2018'); | ||
}); | ||
|
||
|
||
it(`should remove module in 'tsconfig.server.json'`, async () => { | ||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
const { module, target } = readJsonFile(newTree, 'src/tsconfig.server.json').compilerOptions; | ||
expect(module).toBeUndefined(); | ||
expect(target).toBeUndefined(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters