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): remove Browserslist configuration files fr…
…om projects The Browserslist configuration file is redundant as we set the defaults directly in @angular-devkit/build-angular. https://github.com/angular/angular-cli/blob/8da926966e9f414ceecf60b89acd475ce1b55fc5/packages/angular_devkit/build_angular/src/utils/supported-browsers.ts#L12-L19 With this commit, we remove the `.browserlistrc` configuration file from the schematics application template and through a migration in existing projects when the Browserslist query result matches the default. Users needing a finer grain support should still create a `.browserlistrc` in the root directory of the project.
- Loading branch information
1 parent
71ff22c
commit 9beb878
Showing
7 changed files
with
190 additions
and
24 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
16 changes: 0 additions & 16 deletions
16
packages/schematics/angular/application/files/.browserslistrc.template
This file was deleted.
Oops, something went wrong.
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
8 changes: 7 additions & 1 deletion
8
packages/schematics/angular/migrations/migration-collection.json
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 |
---|---|---|
@@ -1,3 +1,9 @@ | ||
{ | ||
"schematics": {} | ||
"schematics": { | ||
"remove-browserslist-config": { | ||
"version": "15.0.0", | ||
"factory": "./update-15/remove-browserslist-config", | ||
"description": "Remove Browserslist configuration files that matches the Angular CLI default configuration." | ||
} | ||
} | ||
} |
90 changes: 90 additions & 0 deletions
90
packages/schematics/angular/migrations/update-15/remove-browserslist-config.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,90 @@ | ||
/** | ||
* @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 { Path, join } from '@angular-devkit/core'; | ||
import { DirEntry, Rule } from '@angular-devkit/schematics'; | ||
|
||
const validBrowserslistConfigFilenames = new Set(['browserslist', '.browserslistrc']); | ||
|
||
export const DEFAULT_BROWSERS = [ | ||
'last 1 Chrome version', | ||
'last 1 Firefox version', | ||
'last 2 Edge major versions', | ||
'last 2 Safari major versions', | ||
'last 2 iOS major versions', | ||
'Firefox ESR', | ||
]; | ||
|
||
function* visit(directory: DirEntry): IterableIterator<Path> { | ||
for (const path of directory.subfiles) { | ||
if (validBrowserslistConfigFilenames.has(path)) { | ||
yield join(directory.path, path); | ||
} | ||
} | ||
|
||
for (const path of directory.subdirs) { | ||
if (path === 'node_modules') { | ||
continue; | ||
} | ||
|
||
yield* visit(directory.dir(path)); | ||
} | ||
} | ||
|
||
export default function (): Rule { | ||
return async (tree, { logger }) => { | ||
let browserslist: typeof import('browserslist') | undefined; | ||
|
||
try { | ||
browserslist = (await import('browserslist')).default; | ||
} catch { | ||
logger.warn('Skipping migration because the "browserslist" package could not be loaded.'); | ||
|
||
return; | ||
} | ||
|
||
// Set the defaults to match the defaults in build-angular. | ||
browserslist.defaults = DEFAULT_BROWSERS; | ||
|
||
const defaultSupportedBrowsers = new Set(browserslist(DEFAULT_BROWSERS)); | ||
const es5Browsers = new Set(browserslist(['supports es6-module'])); | ||
|
||
for (const path of visit(tree.root)) { | ||
const { defaults: browsersListConfig, ...otherConfigs } = browserslist.parseConfig( | ||
tree.readText(path), | ||
); | ||
|
||
if (Object.keys(otherConfigs).length) { | ||
// The config contains additional sections. | ||
continue; | ||
} | ||
|
||
const browserslistInProject = browserslist( | ||
// Exclude from the list ES5 browsers which are not supported. | ||
browsersListConfig.map((s) => `${s} and supports es6-module`), | ||
{ | ||
ignoreUnknownVersions: true, | ||
}, | ||
); | ||
|
||
if (defaultSupportedBrowsers.size !== browserslistInProject.length) { | ||
continue; | ||
} | ||
|
||
const shouldDelete = browserslistInProject.every((browser) => | ||
defaultSupportedBrowsers.has(browser), | ||
); | ||
|
||
if (shouldDelete) { | ||
// All browsers are the same as the default config. | ||
// Delete file as it's redundant. | ||
tree.delete(path); | ||
} | ||
} | ||
}; | ||
} |
84 changes: 84 additions & 0 deletions
84
packages/schematics/angular/migrations/update-15/remove-browserslist-config_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,84 @@ | ||
/** | ||
* @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 { DEFAULT_BROWSERS } from './remove-browserslist-config'; | ||
|
||
describe('Migration to delete Browserslist configurations', () => { | ||
const schematicName = 'remove-browserslist-config'; | ||
|
||
const schematicRunner = new SchematicTestRunner( | ||
'migrations', | ||
require.resolve('../migration-collection.json'), | ||
); | ||
|
||
let tree: UnitTestTree; | ||
|
||
beforeEach(() => { | ||
tree = new UnitTestTree(new EmptyTree()); | ||
}); | ||
|
||
describe('given the Browserslist config matches the default', () => { | ||
it('should delete ".browserslistrc" file', async () => { | ||
tree.create('/src/app/.browserslistrc', DEFAULT_BROWSERS.join('\n')); | ||
expect(tree.exists('/src/app/.browserslistrc')).toBeTrue(); | ||
|
||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
expect(newTree.exists('/src/app/.browserslistrc')).toBeFalse(); | ||
}); | ||
|
||
it(`should not delete "browserslist" in 'node_modules'`, async () => { | ||
tree.create('/node_modules/browserslist', DEFAULT_BROWSERS.join('\n')); | ||
tree.create('/node_modules/.browserslistrc', DEFAULT_BROWSERS.join('\n')); | ||
|
||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
expect(newTree.exists('/node_modules/browserslist')).toBeTrue(); | ||
expect(newTree.exists('/node_modules/.browserslistrc')).toBeTrue(); | ||
}); | ||
}); | ||
|
||
describe('given the Browserslist config does not match the default', () => { | ||
it('should not delete "browserslist"', async () => { | ||
tree.create('/src/app/browserslist', 'last 1 Chrome version'); | ||
|
||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
expect(newTree.exists('/src/app/browserslist')).toBeTrue(); | ||
}); | ||
|
||
it('should not delete ".browserslistrc"', async () => { | ||
tree.create('/src/app/.browserslistrc', 'last 1 Chrome version'); | ||
|
||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
expect(newTree.exists('/src/app/.browserslistrc')).toBeTrue(); | ||
}); | ||
|
||
it('should delete ".browserslistrc" file when it only includes non supported ES5 browsers', async () => { | ||
tree.create('/src/app/.browserslistrc', [...DEFAULT_BROWSERS, 'IE 10'].join('\n')); | ||
expect(tree.exists('/src/app/.browserslistrc')).toBeTrue(); | ||
|
||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
expect(newTree.exists('/src/app/.browserslistrc')).toBeFalse(); | ||
}); | ||
|
||
it('should not delete ".browserslistrc" file when it includes additional config sections', async () => { | ||
tree.create( | ||
'/src/app/.browserslistrc', | ||
` | ||
${DEFAULT_BROWSERS.join('\n')} | ||
[modern] | ||
last 1 chrome version | ||
`, | ||
); | ||
expect(tree.exists('/src/app/.browserslistrc')).toBeTrue(); | ||
|
||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
expect(newTree.exists('/src/app/.browserslistrc')).toBeTrue(); | ||
}); | ||
}); | ||
}); |