Skip to content

Commit 359d4f9

Browse files
alan-agius4alexeagle
authored andcommitted
feat(@schematics/angular): migrate existing ES5 projects to support differential loading
With this change, differential loading will be enabled as we add an non ever green browser and change the tsconfig script target to es2015.
1 parent 5b6502b commit 359d4f9

File tree

3 files changed

+193
-0
lines changed

3 files changed

+193
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. 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+
import {
9+
JsonParseMode,
10+
isJsonObject,
11+
join,
12+
normalize,
13+
parseJson,
14+
parseJsonAst,
15+
} from '@angular-devkit/core';
16+
import { Rule, Tree } from '@angular-devkit/schematics';
17+
import {
18+
findPropertyInAstObject,
19+
insertPropertyInAstObjectInOrder,
20+
} from '../../utility/json-utils';
21+
22+
// tslint:disable-next-line:max-line-length
23+
const browserslistContent = `# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
24+
# For additional information regarding the format and rule options, please see:
25+
# https://github.com/browserslist/browserslist#queries
26+
27+
# Googlebot uses an older version of Chrome
28+
# For additional information see: https://developers.google.com/search/docs/guides/rendering
29+
30+
> 0.5%
31+
last 2 versions
32+
Firefox ESR
33+
not dead
34+
not IE 9-11 # For IE 9-11 support, remove 'not'.
35+
not Chrome 41 # For Googlebot support, remove 'not'.`;
36+
37+
export function updateES5Projects(): Rule {
38+
return (host: Tree) => {
39+
const tsConfigPath = '/tsconfig.json';
40+
const buffer = host.read(tsConfigPath);
41+
if (!buffer) {
42+
return host;
43+
}
44+
45+
const tsCfgAst = parseJsonAst(buffer.toString(), JsonParseMode.Loose);
46+
47+
if (tsCfgAst.kind !== 'object') {
48+
return host;
49+
}
50+
51+
const compilerOptions = findPropertyInAstObject(tsCfgAst, 'compilerOptions');
52+
if (!compilerOptions || compilerOptions.kind !== 'object') {
53+
return host;
54+
}
55+
56+
const scriptTarget = findPropertyInAstObject(compilerOptions, 'target');
57+
if (scriptTarget && scriptTarget.value === 'es2015') {
58+
return host;
59+
}
60+
61+
const recorder = host.beginUpdate(tsConfigPath);
62+
if (scriptTarget) {
63+
const { start, end } = scriptTarget;
64+
recorder.remove(start.offset, end.offset - start.offset);
65+
recorder.insertLeft(start.offset, '"es2015"');
66+
} else {
67+
insertPropertyInAstObjectInOrder(recorder, compilerOptions, 'target', 'es2015', 4);
68+
}
69+
host.commitUpdate(recorder);
70+
71+
return updateBrowserlist;
72+
};
73+
}
74+
75+
function updateBrowserlist(): Rule {
76+
return (tree) => {
77+
const angularConfigContent = tree.read('angular.json') || tree.read('.angular.json');
78+
79+
if (!angularConfigContent) {
80+
return;
81+
}
82+
83+
const angularJson = parseJson(angularConfigContent.toString(), JsonParseMode.Loose);
84+
85+
if (!isJsonObject(angularJson) || !isJsonObject(angularJson.projects)) {
86+
// If that field isn't there, no use...
87+
return;
88+
}
89+
90+
// For all projects
91+
for (const projectName of Object.keys(angularJson.projects)) {
92+
const project = angularJson.projects[projectName];
93+
if (!isJsonObject(project)) {
94+
continue;
95+
}
96+
if (typeof project.root != 'string' || project.projectType !== 'application') {
97+
continue;
98+
}
99+
100+
const browserslistPath = join(normalize(project.root), '/browserslist');
101+
const source = tree.read(browserslistPath);
102+
if (!source) {
103+
tree.create(browserslistPath, browserslistContent);
104+
} else {
105+
const recorder = tree.beginUpdate(browserslistPath);
106+
recorder.insertRight(source.length, '\nChrome 41 # Googlebot');
107+
tree.commitUpdate(recorder);
108+
}
109+
}
110+
111+
return tree;
112+
};
113+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. 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+
12+
13+
describe('Migration to version 8', () => {
14+
describe('Migrate ES5 projects to enable differential loading', () => {
15+
const tsConfigPath = '/tsconfig.json';
16+
const oldTsConfig = {
17+
compilerOptions: {
18+
module: 'es2015',
19+
moduleResolution: 'node',
20+
typeRoots: [
21+
'node_modules/@types',
22+
],
23+
},
24+
};
25+
26+
const schematicRunner = new SchematicTestRunner(
27+
'migrations',
28+
require.resolve('../migration-collection.json'),
29+
);
30+
31+
let tree: UnitTestTree;
32+
33+
beforeEach(async () => {
34+
tree = new UnitTestTree(new EmptyTree());
35+
tree = await schematicRunner.runExternalSchematicAsync(
36+
require.resolve('../../collection.json'), 'ng-new',
37+
{
38+
name: 'migration-test',
39+
version: '1.2.3',
40+
directory: '.',
41+
},
42+
tree,
43+
).toPromise();
44+
tree.overwrite(tsConfigPath, JSON.stringify(oldTsConfig, null, 2));
45+
});
46+
47+
it(`should update 'target' to es2015 when property exists`, () => {
48+
const tree2 = schematicRunner.runSchematic('migration-07', {}, tree.branch());
49+
const { target } = JSON.parse(tree2.readContent(tsConfigPath)).compilerOptions;
50+
expect(target).toBe('es2015');
51+
});
52+
53+
it(`should create 'target' property when doesn't exists`, () => {
54+
const tree2 = schematicRunner.runSchematic('migration-07', {}, tree.branch());
55+
const compilerOptions = {
56+
...oldTsConfig.compilerOptions,
57+
target: undefined,
58+
};
59+
60+
tree.overwrite(tsConfigPath, JSON.stringify({ compilerOptions }, null, 2));
61+
const { target } = JSON.parse(tree2.readContent(tsConfigPath)).compilerOptions;
62+
expect(target).toBe('es2015');
63+
});
64+
65+
it(`should update browserslist file to add an non evergreen browser`, () => {
66+
const tree2 = schematicRunner.runSchematic('migration-07', {}, tree.branch());
67+
expect(tree2.readContent('/browserslist')).toContain('Chrome 41');
68+
});
69+
70+
it(`should create browserslist file if it doesn't exist`, () => {
71+
tree.delete('/browserslist');
72+
const tree2 = schematicRunner.runSchematic('migration-07', {}, tree.branch());
73+
expect(tree2.exists('/browserslist')).toBe(true);
74+
expect(tree2.readContent('/browserslist'))
75+
.toContain('Googlebot support');
76+
});
77+
});
78+
});

packages/schematics/angular/migrations/update-8/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
chain,
1212
} from '@angular-devkit/schematics';
1313
import { updatePackageJson, updateTsLintConfig } from './codelyzer-5';
14+
import { updateES5Projects } from './differential-loading';
1415
import { dropES2015Polyfills } from './drop-es6-polyfills';
1516

1617
export default function(): Rule {
@@ -19,6 +20,7 @@ export default function(): Rule {
1920
updateTsLintConfig(),
2021
updatePackageJson(),
2122
dropES2015Polyfills(),
23+
updateES5Projects(),
2224
]);
2325
};
2426
}

0 commit comments

Comments
 (0)