diff --git a/packages/angular-cli/blueprints/ng2/files/__path__/main.ts b/packages/angular-cli/blueprints/ng2/files/__path__/main.ts index ac78a713c2d1..46c1c73e209e 100644 --- a/packages/angular-cli/blueprints/ng2/files/__path__/main.ts +++ b/packages/angular-cli/blueprints/ng2/files/__path__/main.ts @@ -1,5 +1,3 @@ -import './polyfills.ts'; - import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { enableProdMode } from '@angular/core'; import { environment } from './environments/environment'; diff --git a/packages/angular-cli/blueprints/ng2/files/__path__/polyfills.ts b/packages/angular-cli/blueprints/ng2/files/__path__/polyfills.ts index 4749399c2da0..1bdd4d3c6ef2 100644 --- a/packages/angular-cli/blueprints/ng2/files/__path__/polyfills.ts +++ b/packages/angular-cli/blueprints/ng2/files/__path__/polyfills.ts @@ -1,5 +1,5 @@ -// This file includes polyfills needed by Angular and is loaded before -// the app. You can add your own extra polyfills to this file. +// This file includes polyfills needed by Angular and is loaded before the app. +// You can add your own extra polyfills to this file. import 'core-js/es6/symbol'; import 'core-js/es6/object'; import 'core-js/es6/function'; @@ -17,3 +17,22 @@ import 'core-js/es6/reflect'; import 'core-js/es7/reflect'; import 'zone.js/dist/zone'; + +// If you need to support the browsers/features below, uncomment the import +// and run `npm install import-name-here'; +// Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html + +// Needed for: IE9 +// import 'classlist.js'; + +// Animations +// Needed for: All but Chrome and Firefox, Not supported in IE9 +// import 'web-animations-js'; + +// Date, currency, decimal and percent pipes +// Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 +// import 'intl'; + +// NgClass on SVG elements +// Needed for: IE10, IE11 +// import 'classlist.js'; diff --git a/packages/angular-cli/blueprints/ng2/files/__path__/test.ts b/packages/angular-cli/blueprints/ng2/files/__path__/test.ts index 430d4df98fa0..9bf72267e9b1 100644 --- a/packages/angular-cli/blueprints/ng2/files/__path__/test.ts +++ b/packages/angular-cli/blueprints/ng2/files/__path__/test.ts @@ -1,7 +1,5 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import './polyfills.ts'; - import 'zone.js/dist/long-stack-trace-zone'; import 'zone.js/dist/proxy.js'; import 'zone.js/dist/sync-test'; diff --git a/packages/angular-cli/blueprints/ng2/files/angular-cli.json b/packages/angular-cli/blueprints/ng2/files/angular-cli.json index 3e7ec03e8d9d..ea13f8072b9f 100644 --- a/packages/angular-cli/blueprints/ng2/files/angular-cli.json +++ b/packages/angular-cli/blueprints/ng2/files/angular-cli.json @@ -13,6 +13,7 @@ ], "index": "index.html", "main": "main.ts", + "polyfills": "polyfills.ts", "test": "test.ts", "tsconfig": "tsconfig.json", "prefix": "<%= prefix %>", diff --git a/packages/angular-cli/lib/config/schema.json b/packages/angular-cli/lib/config/schema.json index 64c07bbd2b9a..67b0473f88e5 100644 --- a/packages/angular-cli/lib/config/schema.json +++ b/packages/angular-cli/lib/config/schema.json @@ -55,6 +55,9 @@ "main": { "type": "string" }, + "polyfills": { + "type": "string" + }, "test": { "type": "string" }, diff --git a/packages/angular-cli/models/webpack-build-common.ts b/packages/angular-cli/models/webpack-build-common.ts index ae2d05e698cd..3efc9dc2aabd 100644 --- a/packages/angular-cli/models/webpack-build-common.ts +++ b/packages/angular-cli/models/webpack-build-common.ts @@ -52,6 +52,10 @@ export function getWebpackCommonConfig( entryPoints['main'] = [path.resolve(appRoot, appConfig.main)]; } + if (appConfig.polyfills) { + entryPoints['polyfills'] = [path.resolve(appRoot, appConfig.polyfills)]; + } + // determine hashing format const hashFormat = getOutputHashFormat(outputHashing); @@ -138,7 +142,7 @@ export function getWebpackCommonConfig( new HtmlWebpackPlugin({ template: path.resolve(appRoot, appConfig.index), filename: path.resolve(appConfig.outDir, appConfig.index), - chunksSortMode: packageChunkSort(['inline', 'styles', 'scripts', 'vendor', 'main']), + chunksSortMode: packageChunkSort(appConfig), excludeChunks: lazyChunks, xhtml: true }), diff --git a/packages/angular-cli/models/webpack-config.ts b/packages/angular-cli/models/webpack-config.ts index 07134219e180..f46231955904 100644 --- a/packages/angular-cli/models/webpack-config.ts +++ b/packages/angular-cli/models/webpack-config.ts @@ -56,7 +56,7 @@ export class NgCliWebpackConfig { let config = webpackMerge(baseConfig, targetConfigPartial); - if (appConfig.main) { + if (appConfig.main || appConfig.polyfills) { const typescriptConfigPartial = isAoT ? getWebpackAotConfigPartial(projectRoot, appConfig, i18nFile, i18nFormat, locale) : getWebpackNonAotConfigPartial(projectRoot, appConfig); diff --git a/packages/angular-cli/plugins/karma.js b/packages/angular-cli/plugins/karma.js index 16c4fc7cafea..a53c2e732181 100644 --- a/packages/angular-cli/plugins/karma.js +++ b/packages/angular-cli/plugins/karma.js @@ -68,6 +68,19 @@ const init = (config) => { .map((file) => config.preprocessors[file]) .map((arr) => arr.splice(arr.indexOf('angular-cli'), 1, 'webpack', 'sourcemap')); + // Add polyfills file + if (appConfig.polyfills) { + const polyfillsFile = path.resolve(appRoot, appConfig.polyfills); + const polyfillsPattern = { + pattern: polyfillsFile, + included: true, + served: true, + watched: true + } + Array.prototype.unshift.apply(config.files, [polyfillsPattern]); + config.preprocessors[polyfillsFile] = ['webpack', 'sourcemap']; + } + // Add global scripts if (appConfig.scripts && appConfig.scripts.length > 0) { const globalScriptPatterns = appConfig.scripts diff --git a/packages/angular-cli/utilities/package-chunk-sort.ts b/packages/angular-cli/utilities/package-chunk-sort.ts index 7c4daeb6dbfa..14c044e87547 100644 --- a/packages/angular-cli/utilities/package-chunk-sort.ts +++ b/packages/angular-cli/utilities/package-chunk-sort.ts @@ -1,17 +1,36 @@ -export function packageChunkSort(packages: string[]) { - return function sort(left: any, right: any) { - let leftIndex = packages.indexOf(left.names[0]); - let rightindex = packages.indexOf(right.names[0]); +import { ExtraEntry, extraEntryParser } from '../models/webpack-build-utils'; - if ( leftIndex < 0 || rightindex < 0) { - // Unknown packages are loaded last - return 1; +// Sort chunks according to a predefined order: +// inline, polyfills, all scripts, all styles, vendor, main +export function packageChunkSort(appConfig: any) { + let entryPoints = ['inline', 'polyfills']; + + const pushExtraEntries = (extraEntry: ExtraEntry) => { + if (entryPoints.indexOf(extraEntry.entry) === -1) { + entryPoints.push(extraEntry.entry); } + }; + + if (appConfig.scripts) { + extraEntryParser(appConfig.scripts, './', 'scripts').forEach(pushExtraEntries); + } + + if (appConfig.styles) { + extraEntryParser(appConfig.styles, './', 'styles').forEach(pushExtraEntries); + } + + entryPoints.push(...['vendor', 'main']); + + return function sort(left: any, right: any) { + let leftIndex = entryPoints.indexOf(left.names[0]); + let rightindex = entryPoints.indexOf(right.names[0]); if (leftIndex > rightindex) { return 1; + } else if (leftIndex < rightindex) { + return -1; + } else { + return 0; } - - return -1; }; } diff --git a/tests/e2e/tests/build/polyfills.ts b/tests/e2e/tests/build/polyfills.ts new file mode 100644 index 000000000000..2fae001ff3e0 --- /dev/null +++ b/tests/e2e/tests/build/polyfills.ts @@ -0,0 +1,16 @@ +import { expectFileToMatch } from '../../utils/fs'; +import { ng } from '../../utils/process'; +import { oneLineTrim } from 'common-tags'; + +export default function () { + return Promise.resolve() + .then(() => ng('build')) + // files were created successfully + .then(() => expectFileToMatch('dist/polyfills.bundle.js', 'core-js')) + .then(() => expectFileToMatch('dist/polyfills.bundle.js', 'zone.js')) + // index.html lists the right bundles + .then(() => expectFileToMatch('dist/index.html', oneLineTrim` + + + `)); +} diff --git a/tests/e2e/tests/build/scripts-array.ts b/tests/e2e/tests/build/scripts-array.ts index f3d2a02ac34e..57cabfa08a2d 100644 --- a/tests/e2e/tests/build/scripts-array.ts +++ b/tests/e2e/tests/build/scripts-array.ts @@ -45,9 +45,10 @@ export default function () { `)) .then(() => expectFileToMatch('dist/index.html', oneLineTrim` + + - `)) diff --git a/tests/e2e/tests/build/styles/styles-array.ts b/tests/e2e/tests/build/styles/styles-array.ts index e43c03160914..7e568ff59ec0 100644 --- a/tests/e2e/tests/build/styles/styles-array.ts +++ b/tests/e2e/tests/build/styles/styles-array.ts @@ -46,14 +46,15 @@ export default function () { .then(() => expectToFail(() => expectFileToExist('dist/renamed-lazy-style.bundle.js'))) // index.html lists the right bundles .then(() => expectFileToMatch('dist/index.html', oneLineTrim` - - + + `)) .then(() => expectFileToMatch('dist/index.html', oneLineTrim` - + + `)) .then(() => ng('build', '--no-extract-css')) diff --git a/tests/e2e/tests/misc/minimal-config.ts b/tests/e2e/tests/misc/minimal-config.ts index b04fbf2cecf9..d8ededab39d6 100644 --- a/tests/e2e/tests/misc/minimal-config.ts +++ b/tests/e2e/tests/misc/minimal-config.ts @@ -7,7 +7,11 @@ export default function () { .then(() => writeFile('angular-cli.json', JSON.stringify({ apps: [{ root: 'src', - main: 'main.ts' + main: 'main.ts', + scripts: [ + '../node_modules/core-js/client/shim.min.js', + '../node_modules/zone.js/dist/zone.js' + ] }], e2e: { protractor: { config: './protractor.conf.js' } } }))) diff --git a/tests/e2e/tests/third-party/bootstrap.ts b/tests/e2e/tests/third-party/bootstrap.ts index 23f922440970..f99fc436b339 100644 --- a/tests/e2e/tests/third-party/bootstrap.ts +++ b/tests/e2e/tests/third-party/bootstrap.ts @@ -23,6 +23,7 @@ export default function() { .then(() => expectFileToMatch('dist/styles.bundle.css', '* Bootstrap')) .then(() => expectFileToMatch('dist/index.html', oneLineTrim` +