Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions packages/angular/cli/lib/config/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -950,11 +950,6 @@
},
"default": []
},
"es5BrowserSupport": {
"description": "Enables conditionally loaded ES2015 polyfills.",
"type": "boolean",
"default": false
},
"rebaseRootRelativeCssUrls": {
"description": "Change root relative URLs in stylesheets to include base HREF and deploy URL. Use only for compatibility and transition. The behavior of this option is non-standard and will be removed in the next major release.",
"type": "boolean",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ export interface BuildOptions {
statsJson: boolean;
forkTypeChecker: boolean;
profile?: boolean;
/** @deprecated since version 8 **/
es5BrowserSupport?: boolean;

main: string;
polyfills?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,7 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
tsConfig.options.target || ScriptTarget.ES5,
);

if (
buildOptions.es5BrowserSupport ||
(buildOptions.es5BrowserSupport === undefined && buildBrowserFeatures.isEs5SupportNeeded())
) {
if (buildBrowserFeatures.isEs5SupportNeeded()) {
const polyfillsChunkName = 'polyfills-es5';
entryPoints[polyfillsChunkName] = [path.join(__dirname, '..', 'es5-polyfills.js')];
if (differentialLoadingMode) {
Expand Down
5 changes: 0 additions & 5 deletions packages/angular_devkit/build_angular/src/browser/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -350,11 +350,6 @@
"default": false,
"x-deprecated": "Use \"NG_BUILD_PROFILING\" environment variable instead."
},
"es5BrowserSupport": {
"description": "Enables conditionally loaded ES2015 polyfills.",
"type": "boolean",
"x-deprecated": "This will be determined from the list of supported browsers specified in the 'browserslist' file."
},
"rebaseRootRelativeCssUrls": {
"description": "Change root relative URLs in stylesheets to include base HREF and deploy URL. Use only for compatibility and transition. The behavior of this option is non-standard and will be removed in the next major release.",
"type": "boolean",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ export async function generateWebpackConfig(
// Under downlevel differential loading we copy the assets outside of webpack.
assets: [],
esVersionInFileName: true,
es5BrowserSupport: undefined,
};
}

Expand Down
4 changes: 4 additions & 0 deletions packages/schematics/angular/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ ts_library(
"//packages/angular_devkit/schematics",
"//packages/angular_devkit/schematics/tasks",
"//packages/schematics/angular/third_party/github.com/Microsoft/TypeScript",
"@npm//@types/browserslist",
"@npm//@types/caniuse-lite",
"@npm//@types/node",
"@npm//rxjs",
"@npm//tslint",
Expand Down Expand Up @@ -98,6 +100,8 @@ ts_library(
"//packages/angular_devkit/schematics",
"//packages/angular_devkit/schematics/testing",
"//packages/schematics/angular/third_party/github.com/Microsoft/TypeScript",
"@npm//@types/browserslist",
"@npm//@types/caniuse-lite",
"@npm//@types/jasmine",
"@npm//@types/node",
"@npm//rxjs",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@
"version": "10.0.0-beta.1",
"factory": "./update-10/update-dependencies",
"description": "Workspace dependencies updates."
},
"remove-es5-browser-support-option": {
"version": "10.0.0-beta.2",
"factory": "./update-10/remove-es5-browser-support",
"description": "Remove deprecated 'es5BrowserSupport' browser builder option. The inclusion for ES5 polyfills will be determined from the browsers listed in the browserslist configuration."
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* @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 { Path, getSystemPath, logging, normalize, resolve, workspaces } from '@angular-devkit/core';
import { Rule } from '@angular-devkit/schematics';
import { getWorkspace, updateWorkspace } from '../../utility/workspace';
import { Builders, ProjectType } from '../../utility/workspace-models';

export default function (): Rule {
return async (host, context) => {
const workspace = await getWorkspace(host);

for (const [projectName, project] of workspace.projects) {
if (project.extensions.projectType !== ProjectType.Application) {
// Only interested in application projects
continue;
}

for (const [, target] of project.targets) {
// Only interested in Angular Devkit Browser builder
if (target?.builder !== Builders.Browser) {
continue;
}

const isES5Needed = await isES5SupportNeeded(
resolve(
normalize(host.root.path),
normalize(project.root),
),
);

// Check options
if (target.options) {
target.options = removeE5BrowserSupportOption(projectName, target.options, isES5Needed, context.logger);
}

// Go through each configuration entry
if (!target.configurations) {
continue;
}

for (const [configurationName, options] of Object.entries(target.configurations)) {
target.configurations[configurationName] = removeE5BrowserSupportOption(
projectName,
options,
isES5Needed,
context.logger,
configurationName,
);
}
}
}

return updateWorkspace(workspace);
};
}

type TargetOptions = workspaces.TargetDefinition['options'];

function removeE5BrowserSupportOption(
projectName: string,
options: TargetOptions,
isES5Needed: boolean | undefined,
logger: logging.LoggerApi,
configurationName = '',
): TargetOptions {
if (typeof options?.es5BrowserSupport !== 'boolean') {
return options;
}

const configurationPath = configurationName ? `configurations.${configurationName}.` : '';

if (options.es5BrowserSupport && isES5Needed === false) {
logger.warn(
`Project '${projectName}' doesn't require ES5 support, but '${configurationPath}es5BrowserSupport' was set to 'true'.\n` +
`ES5 polyfills will no longer be added when building this project${configurationName ? ` with '${configurationName}' configuration.` : '.'}\n` +
`If ES5 polyfills are needed, add the supported ES5 browsers in the browserslist configuration.`,
);
} else if (!options.es5BrowserSupport && isES5Needed === true) {
logger.warn(
`Project '${projectName}' requires ES5 support, but '${configurationPath}es5BrowserSupport' was set to 'false'.\n` +
`ES5 polyfills will be added when building this project${configurationName ? ` with '${configurationName}' configuration.` : '.'}\n` +
`If ES5 polyfills are not needed, remove the unsupported ES5 browsers from the browserslist configuration.`,
);
}

return {
...options,
es5BrowserSupport: undefined,
};
}

/**
* True, when one or more browsers requires ES5 support
*/
async function isES5SupportNeeded(projectRoot: Path): Promise<boolean | undefined> {
// y: feature is fully available
// n: feature is unavailable
// a: feature is partially supported
// x: feature is prefixed
const criteria = [
'y',
'a',
];

try {
// tslint:disable-next-line:no-implicit-dependencies
const browserslist = await import('browserslist');
const supportedBrowsers = browserslist(undefined, {
path: getSystemPath(projectRoot),
});

// tslint:disable-next-line:no-implicit-dependencies
const { feature, features } = await import('caniuse-lite');
const data = feature(features['es6-module']);

return supportedBrowsers
.some(browser => {
const [agentId, version] = browser.split(' ');

const browserData = data.stats[agentId];
const featureStatus = (browserData && browserData[version]) as string | undefined;

// We are only interested in the first character
// Ex: when 'a #4 #5', we only need to check for 'a'
// as for such cases we should polyfill these features as needed
return !featureStatus || !criteria.includes(featureStatus.charAt(0));
});
} catch {
return undefined;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* @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 { JsonObject } from '@angular-devkit/core';
import { EmptyTree } from '@angular-devkit/schematics';
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
import { BuilderTarget, Builders, ProjectType, WorkspaceSchema } from '../../utility/workspace-models';

function getBuildTarget(tree: UnitTestTree): BuilderTarget<Builders.Browser, JsonObject> {
return JSON.parse(tree.readContent('/angular.json')).projects.app.architect.build;
}

function createWorkSpaceConfig(tree: UnitTestTree, es5BrowserSupport: boolean | undefined) {
const angularConfig: WorkspaceSchema = {
version: 1,
projects: {
app: {
root: '',
sourceRoot: 'src',
projectType: ProjectType.Application,
prefix: 'app',
architect: {
build: {
builder: Builders.Browser,
options: {
es5BrowserSupport,
sourceMaps: true,
buildOptimizer: false,
// tslint:disable-next-line:no-any
} as any,
configurations: {
one: {
es5BrowserSupport,
vendorChunk: false,
buildOptimizer: true,
},
two: {
es5BrowserSupport,
vendorChunk: false,
buildOptimizer: true,
sourceMaps: false,
},
// tslint:disable-next-line:no-any
} as any,
},
},
},
},
};

tree.create('/angular.json', JSON.stringify(angularConfig, undefined, 2));
}

describe(`Migration to remove deprecated 'es5BrowserSupport' option`, () => {
const schematicName = 'remove-es5-browser-support-option';

const schematicRunner = new SchematicTestRunner(
'migrations',
require.resolve('../migration-collection.json'),
);

let tree: UnitTestTree;
beforeEach(() => {
tree = new UnitTestTree(new EmptyTree());
});

it(`should remove option when set to 'false'`, async () => {
createWorkSpaceConfig(tree, false);

const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
const { options, configurations } = getBuildTarget(newTree);

expect(options.es5BrowserSupport).toBeUndefined();
expect(configurations).toBeDefined();
expect(configurations?.one.es5BrowserSupport).toBeUndefined();
expect(configurations?.two.es5BrowserSupport).toBeUndefined();
});

it(`should remove option and when set to 'true'`, async () => {
createWorkSpaceConfig(tree, true);

const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
const { options, configurations } = getBuildTarget(newTree);

expect(options.es5BrowserSupport).toBeUndefined();
expect(configurations).toBeDefined();
expect(configurations?.one.es5BrowserSupport).toBeUndefined();
expect(configurations?.two.es5BrowserSupport).toBeUndefined();
});
});
1 change: 0 additions & 1 deletion packages/schematics/angular/utility/workspace-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ export interface BrowserBuilderOptions extends BrowserBuilderBaseOptions {
maximumWarning?: string;
maximumError?: string;
}[];
es5BrowserSupport?: boolean;
webWorkerTsConfig?: string;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ export default async function () {
compilerOptions['target'] = 'es5';
});

await updateJsonFile('angular.json', workspaceJson => {
const appArchitect = workspaceJson.projects['test-project'].architect;
appArchitect.build.options.es5BrowserSupport = false;
});

await writeFile('.browserslistrc', 'last 2 Chrome versions');
await ng('build');
await expectFileNotToExist('dist/test-project/polyfills-es5.js');
Expand All @@ -25,21 +20,6 @@ export default async function () {
<script src="main.js" defer></script>
`);

await ng('build', `--es5BrowserSupport`);
await expectFileToMatch('dist/test-project/polyfills-es5.js', 'core-js');
await expectFileToMatch('dist/test-project/index.html', oneLineTrim`
<script src="runtime.js" defer></script>
<script src="polyfills-es5.js" nomodule defer></script>
<script src="polyfills.js" defer></script>
<script src="styles.js" defer></script>
<script src="vendor.js" defer></script>
<script src="main.js" defer></script>
`);

await updateJsonFile('angular.json', workspaceJson => {
const appArchitect = workspaceJson.projects['test-project'].architect;
appArchitect.build.options.es5BrowserSupport = undefined;
});
await writeFile('.browserslistrc', 'IE 10');
await ng('build');
await expectFileToMatch('dist/test-project/polyfills-es5.js', 'core-js');
Expand Down
3 changes: 3 additions & 0 deletions tests/legacy-cli/e2e/tests/update/update-7.0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export default async function() {
// Create new project from previous version files.
// We must use the original NPM packages to force a real update.
await createProjectFromAsset('7.0-project', true);
// Update to version 8, to use the self update CLI feature.
await ng('update', '@angular/cli@8');

fs.writeFileSync('.npmrc', 'registry = http://localhost:4873', 'utf8');

// Update the CLI.
Expand Down