@angular-devkit/build-angular 0.800.0 → 0.800.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/package.json +8 -7
  2. package/src/angular-cli-files/models/build-options.d.ts +3 -2
  3. package/src/angular-cli-files/models/safari-nomodule.js +3 -17
  4. package/src/angular-cli-files/models/webpack-configs/common.js +40 -34
  5. package/src/angular-cli-files/models/webpack-configs/typescript.d.ts +1 -1
  6. package/src/angular-cli-files/models/webpack-configs/typescript.js +5 -5
  7. package/src/angular-cli-files/models/webpack-configs/utils.d.ts +0 -1
  8. package/src/angular-cli-files/models/webpack-configs/utils.js +0 -4
  9. package/src/angular-cli-files/plugins/karma-context.html +1 -1
  10. package/src/angular-cli-files/plugins/karma-debug.html +1 -1
  11. package/src/angular-cli-files/plugins/karma.js +3 -3
  12. package/src/angular-cli-files/utilities/bundle-calculator.js +1 -0
  13. package/src/angular-cli-files/utilities/index-file/write-index-html.js +1 -1
  14. package/src/angular-cli-files/utilities/package-chunk-sort.js +1 -0
  15. package/src/angular-cli-files/utilities/read-tsconfig.d.ts +9 -2
  16. package/src/angular-cli-files/utilities/read-tsconfig.js +25 -8
  17. package/src/angular-cli-files/utilities/service-worker/index.js +1 -1
  18. package/src/browser/index.js +15 -7
  19. package/src/dev-server/schema.d.ts +3 -1
  20. package/src/dev-server/schema.json +1 -1
  21. package/src/extract-i18n/index.js +9 -0
  22. package/src/karma/index.js +1 -1
  23. package/src/utils/build-browser-features.d.ts +35 -0
  24. package/src/utils/build-browser-features.js +74 -0
  25. package/src/utils/index.d.ts +1 -1
  26. package/src/utils/index.js +5 -5
  27. package/src/utils/webpack-browser-config.js +16 -6
  28. package/src/utils/differential-loading.d.ts +0 -10
  29. package/src/utils/differential-loading.js +0 -24
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "@angular-devkit/build-angular",
3
- "version": "0.800.0",
3
+ "version": "0.800.4",
4
4
  "description": "Angular Webpack Build Facade",
5
5
  "experimental": true,
6
6
  "main": "src/index.js",
7
7
  "typings": "src/index.d.ts",
8
8
  "builders": "builders.json",
9
9
  "dependencies": {
10
- "@angular-devkit/architect": "0.800.0",
11
- "@angular-devkit/build-optimizer": "0.800.0",
12
- "@angular-devkit/build-webpack": "0.800.0",
13
- "@angular-devkit/core": "8.0.0",
14
- "@ngtools/webpack": "8.0.0",
10
+ "@angular-devkit/architect": "0.800.4",
11
+ "@angular-devkit/build-optimizer": "0.800.4",
12
+ "@angular-devkit/build-webpack": "0.800.4",
13
+ "@angular-devkit/core": "8.0.4",
14
+ "@ngtools/webpack": "8.0.4",
15
15
  "ajv": "6.10.0",
16
16
  "autoprefixer": "9.5.1",
17
17
  "browserslist": "4.5.5",
18
- "caniuse-api": "3.0.0",
18
+ "caniuse-lite": "1.0.30000974",
19
19
  "circular-dependency-plugin": "5.0.2",
20
20
  "clean-css": "4.2.1",
21
21
  "copy-webpack-plugin": "5.0.2",
@@ -58,6 +58,7 @@
58
58
  "worker-plugin": "3.1.0"
59
59
  },
60
60
  "peerDependencies": {
61
+ "@angular/compiler-cli": ">=8.0.0-beta.0 < 9.0.0",
61
62
  "typescript": ">=3.1 < 3.5"
62
63
  },
63
64
  "keywords": [
@@ -6,7 +6,8 @@
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
8
  import { logging } from '@angular-devkit/core';
9
- import { ParsedCommandLine, ScriptTarget } from 'typescript';
9
+ import { ParsedConfiguration } from '@angular/compiler-cli';
10
+ import { ScriptTarget } from 'typescript';
10
11
  import { AssetPatternClass, Budget, ExtraEntryPoint, OptimizationClass, SourceMapClass } from '../../browser/schema';
11
12
  import { NormalizedFileReplacement } from '../../utils/normalize-file-replacements';
12
13
  export interface BuildOptions {
@@ -78,7 +79,7 @@ export interface WebpackConfigOptions<T = BuildOptions> {
78
79
  projectRoot: string;
79
80
  sourceRoot?: string;
80
81
  buildOptions: T;
81
- tsConfig: ParsedCommandLine;
82
+ tsConfig: ParsedConfiguration;
82
83
  tsConfigPath: string;
83
84
  supportES2015: boolean;
84
85
  }
@@ -1,22 +1,8 @@
1
- /**
2
- * Safari 10.1 supports modules, but does not support the `nomodule` attribute - it will
3
- * load <script nomodule> anyway. This snippet solve this problem, but only for script
4
- * tags that load external code, e.g.: <script nomodule src="nomodule.js"></script>
5
- *
6
- * Again: this will **not** prevent inline script, e.g.:
7
- * <script nomodule>alert('no modules');</script>.
8
- *
9
- * This workaround is possible because Safari supports the non-standard 'beforeload' event.
10
- * This allows us to trap the module and nomodule load.
11
- *
12
- * Note also that `nomodule` is supported in later versions of Safari - it's just 10.1 that
13
- * omits this attribute.
14
- */
15
- (function() {
1
+ (function () {
16
2
  var check = document.createElement('script');
17
3
  if (!('noModule' in check) && 'onbeforeload' in check) {
18
4
  var support = false;
19
- document.addEventListener('beforeload', function(e) {
5
+ document.addEventListener('beforeload', function (e) {
20
6
  if (e.target === check) {
21
7
  support = true;
22
8
  } else if (!e.target.hasAttribute('nomodule') || !support) {
@@ -30,4 +16,4 @@
30
16
  document.head.appendChild(check);
31
17
  check.remove();
32
18
  }
33
- }());
19
+ }());
@@ -12,7 +12,7 @@ const CopyWebpackPlugin = require("copy-webpack-plugin");
12
12
  const path = require("path");
13
13
  const typescript_1 = require("typescript");
14
14
  const webpack_1 = require("webpack");
15
- const differential_loading_1 = require("../../../utils/differential-loading");
15
+ const build_browser_features_1 = require("../../../utils/build-browser-features");
16
16
  const bundle_budget_1 = require("../../plugins/bundle-budget");
17
17
  const cleancss_webpack_plugin_1 = require("../../plugins/cleancss-webpack-plugin");
18
18
  const named_chunks_plugin_1 = require("../../plugins/named-chunks-plugin");
@@ -31,7 +31,7 @@ exports.buildOptimizerLoader = g['_DevKitIsLocal']
31
31
  : '@angular-devkit/build-optimizer/webpack-loader';
32
32
  // tslint:disable-next-line:no-big-function
33
33
  function getCommonConfig(wco) {
34
- const { root, projectRoot, buildOptions } = wco;
34
+ const { root, projectRoot, buildOptions, tsConfig } = wco;
35
35
  const { styles: stylesOptimization, scripts: scriptsOptimization } = buildOptions.optimization;
36
36
  const { styles: stylesSourceMap, scripts: scriptsSourceMap, vendor: vendorSourceMap, } = buildOptions.sourceMap;
37
37
  const nodeModules = find_up_1.findUp('node_modules', projectRoot);
@@ -45,41 +45,47 @@ function getCommonConfig(wco) {
45
45
  if (buildOptions.main) {
46
46
  entryPoints['main'] = [path.resolve(root, buildOptions.main)];
47
47
  }
48
- const es5Polyfills = path.join(__dirname, '..', 'es5-polyfills.js');
49
- const es5JitPolyfills = path.join(__dirname, '..', 'es5-jit-polyfills.js');
50
- if (targetInFileName) {
51
- // For differential loading we don't need to have 2 polyfill bundles
52
- if (buildOptions.scriptTargetOverride === typescript_1.ScriptTarget.ES2015) {
53
- entryPoints['polyfills'] = [path.join(__dirname, '..', 'safari-nomodule.js')];
54
- }
55
- else {
56
- entryPoints['polyfills'] = [es5Polyfills];
57
- if (!buildOptions.aot) {
58
- entryPoints['polyfills'].push(es5JitPolyfills);
48
+ if (wco.buildOptions.platform !== 'server') {
49
+ const buildBrowserFeatures = new build_browser_features_1.BuildBrowserFeatures(projectRoot, tsConfig.options.target || typescript_1.ScriptTarget.ES5);
50
+ if ((buildOptions.scriptTargetOverride || tsConfig.options.target) === typescript_1.ScriptTarget.ES5) {
51
+ if (buildOptions.es5BrowserSupport ||
52
+ (buildOptions.es5BrowserSupport === undefined &&
53
+ buildBrowserFeatures.isEs5SupportNeeded())) {
54
+ // The nomodule polyfill needs to be inject prior to any script and be
55
+ // outside of webpack compilation because otherwise webpack will cause the
56
+ // script to be wrapped in window["webpackJsonp"] which causes this to fail.
57
+ if (buildBrowserFeatures.isNoModulePolyfillNeeded()) {
58
+ const noModuleScript = {
59
+ bundleName: 'polyfills-nomodule-es5',
60
+ input: path.join(__dirname, '..', 'safari-nomodule.js'),
61
+ };
62
+ buildOptions.scripts = buildOptions.scripts
63
+ ? [...buildOptions.scripts, noModuleScript]
64
+ : [noModuleScript];
65
+ }
66
+ // For differential loading we don't need to generate a seperate polyfill file
67
+ // because they will be loaded exclusivly based on module and nomodule
68
+ const polyfillsChunkName = buildBrowserFeatures.isDifferentialLoadingNeeded()
69
+ ? 'polyfills'
70
+ : 'polyfills-es5';
71
+ entryPoints[polyfillsChunkName] = [path.join(__dirname, '..', 'es5-polyfills.js')];
72
+ if (!buildOptions.aot) {
73
+ entryPoints[polyfillsChunkName].push(path.join(__dirname, '..', 'es5-jit-polyfills.js'));
74
+ }
59
75
  }
60
76
  }
61
- }
62
- else {
63
- // For NON differential loading we want to have 2 polyfill bundles
64
- if (buildOptions.es5BrowserSupport
65
- || (buildOptions.es5BrowserSupport === undefined && differential_loading_1.isEs5SupportNeeded(projectRoot))) {
66
- entryPoints['polyfills-es5'] = [es5Polyfills];
67
- if (!buildOptions.aot) {
68
- entryPoints['polyfills-es5'].push(es5JitPolyfills);
69
- }
77
+ if (buildOptions.polyfills) {
78
+ entryPoints['polyfills'] = [
79
+ ...(entryPoints['polyfills'] || []),
80
+ path.resolve(root, buildOptions.polyfills),
81
+ ];
82
+ }
83
+ if (!buildOptions.aot) {
84
+ entryPoints['polyfills'] = [
85
+ ...(entryPoints['polyfills'] || []),
86
+ path.join(__dirname, '..', 'jit-polyfills.js'),
87
+ ];
70
88
  }
71
- }
72
- if (buildOptions.polyfills) {
73
- entryPoints['polyfills'] = [
74
- ...(entryPoints['polyfills'] || []),
75
- path.resolve(root, buildOptions.polyfills),
76
- ];
77
- }
78
- if (!buildOptions.aot) {
79
- entryPoints['polyfills'] = [
80
- ...(entryPoints['polyfills'] || []),
81
- path.join(__dirname, '..', 'jit-polyfills.js'),
82
- ];
83
89
  }
84
90
  if (buildOptions.profile || process.env['NG_BUILD_PROFILING']) {
85
91
  extraPlugins.push(new webpack_1.debug.ProfilingPlugin({
@@ -9,7 +9,7 @@ export declare function getNonAotConfig(wco: WebpackConfigOptions): {
9
9
  };
10
10
  plugins: AngularCompilerPlugin[];
11
11
  };
12
- export declare function getAotConfig(wco: WebpackConfigOptions, extract?: boolean): {
12
+ export declare function getAotConfig(wco: WebpackConfigOptions, i18nExtract?: boolean): {
13
13
  module: {
14
14
  rules: {
15
15
  test: RegExp;
@@ -34,12 +34,12 @@ function _pluginOptionsOverrides(buildOptions, pluginOptions) {
34
34
  compilerOptions
35
35
  };
36
36
  }
37
- function _createAotPlugin(wco, options, useMain = true, extract = false) {
37
+ function _createAotPlugin(wco, options, i18nExtract = false) {
38
38
  const { root, buildOptions } = wco;
39
39
  const i18nInFile = buildOptions.i18nFile
40
40
  ? path.resolve(root, buildOptions.i18nFile)
41
41
  : undefined;
42
- const i18nFileAndFormat = extract
42
+ const i18nFileAndFormat = i18nExtract
43
43
  ? {
44
44
  i18nOutFile: buildOptions.i18nFile,
45
45
  i18nOutFormat: buildOptions.i18nFormat,
@@ -54,7 +54,7 @@ function _createAotPlugin(wco, options, useMain = true, extract = false) {
54
54
  }
55
55
  }
56
56
  let pluginOptions = {
57
- mainPath: useMain ? path.join(root, buildOptions.main) : undefined,
57
+ mainPath: path.join(root, buildOptions.main),
58
58
  ...i18nFileAndFormat,
59
59
  locale: buildOptions.i18nLocale,
60
60
  platform: buildOptions.platform === 'server' ? webpack_1.PLATFORM.Server : webpack_1.PLATFORM.Browser,
@@ -79,7 +79,7 @@ function getNonAotConfig(wco) {
79
79
  };
80
80
  }
81
81
  exports.getNonAotConfig = getNonAotConfig;
82
- function getAotConfig(wco, extract = false) {
82
+ function getAotConfig(wco, i18nExtract = false) {
83
83
  const { tsConfigPath, buildOptions } = wco;
84
84
  const loaders = [webpack_1.NgToolsLoader];
85
85
  if (buildOptions.buildOptimizer) {
@@ -91,7 +91,7 @@ function getAotConfig(wco, extract = false) {
91
91
  const test = /(?:\.ngfactory\.js|\.ngstyle\.js|\.tsx?)$/;
92
92
  return {
93
93
  module: { rules: [{ test, use: loaders }] },
94
- plugins: [_createAotPlugin(wco, { tsConfigPath }, true, extract)]
94
+ plugins: [_createAotPlugin(wco, { tsConfigPath }, i18nExtract)]
95
95
  };
96
96
  }
97
97
  exports.getAotConfig = getAotConfig;
@@ -8,7 +8,6 @@
8
8
  import { ExtraEntryPoint, ExtraEntryPointClass } from '../../../browser/schema';
9
9
  import { SourceMapDevToolPlugin } from 'webpack';
10
10
  import { ScriptTarget } from 'typescript';
11
- export declare const ngAppResolve: (resolvePath: string) => string;
12
11
  export interface HashFormat {
13
12
  chunk: string;
14
13
  extract: string;
@@ -9,13 +9,9 @@
9
9
  // tslint:disable
10
10
  // TODO: cleanup this file, it's copied as is from Angular CLI.
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- const path = require("path");
13
12
  const core_1 = require("@angular-devkit/core");
14
13
  const webpack_1 = require("webpack");
15
14
  const typescript_1 = require("typescript");
16
- exports.ngAppResolve = (resolvePath) => {
17
- return path.resolve(process.cwd(), resolvePath);
18
- };
19
15
  function getOutputHashFormat(option, length = 20) {
20
16
  /* tslint:disable:max-line-length */
21
17
  const hashFormats = {
@@ -28,8 +28,8 @@ Reloaded before every execution run.
28
28
  %MAPPINGS%
29
29
  </script>
30
30
  <script src="_karma_webpack_/runtime.js" crossorigin="anonymous"></script>
31
- <script src="_karma_webpack_/polyfills.js" crossorigin="anonymous"></script>
32
31
  <script src="_karma_webpack_/polyfills-es5.js" crossorigin="anonymous" nomodule></script>
32
+ <script src="_karma_webpack_/polyfills.js" crossorigin="anonymous"></script>
33
33
  <!-- Dynamically replaced with <script> tags -->
34
34
  %SCRIPTS%
35
35
  <script src="_karma_webpack_/styles.js" crossorigin="anonymous"></script>
@@ -29,8 +29,8 @@ just for immediate execution, without reporting to Karma server.
29
29
  %MAPPINGS%
30
30
  </script>
31
31
  <script src="_karma_webpack_/runtime.js" crossorigin="anonymous"></script>
32
- <script src="_karma_webpack_/polyfills.js" crossorigin="anonymous"></script>
33
32
  <script src="_karma_webpack_/polyfills-es5.js" crossorigin="anonymous" nomodule></script>
33
+ <script src="_karma_webpack_/polyfills.js" crossorigin="anonymous"></script>
34
34
  <!-- Dynamically replaced with <script> tags -->
35
35
  %SCRIPTS%
36
36
  <script src="_karma_webpack_/styles.js" crossorigin="anonymous"></script>
@@ -60,15 +60,14 @@ const init = (config, emitter, customFileHandlers) => {
60
60
  const logger = config.buildWebpack.logger || node_1.createConsoleLogger();
61
61
  successCb = config.buildWebpack.successCb;
62
62
  failureCb = config.buildWebpack.failureCb;
63
- config.reporters.unshift('@angular-devkit/build-angular--event-reporter');
64
63
  // When using code-coverage, auto-add coverage-istanbul.
65
64
  config.reporters = config.reporters || [];
66
65
  if (options.codeCoverage && config.reporters.indexOf('coverage-istanbul') === -1) {
67
- config.reporters.unshift('coverage-istanbul');
66
+ config.reporters.push('coverage-istanbul');
68
67
  }
69
68
  // Add a reporter that fixes sourcemap urls.
70
69
  if (index_1.normalizeSourceMaps(options.sourceMap).scripts) {
71
- config.reporters.unshift('@angular-devkit/build-angular--sourcemap-reporter');
70
+ config.reporters.push('@angular-devkit/build-angular--sourcemap-reporter');
72
71
  // Code taken from https://github.com/tschaub/karma-source-map-support.
73
72
  // We can't use it directly because we need to add it conditionally in this file, and karma
74
73
  // frameworks cannot be added dynamically.
@@ -79,6 +78,7 @@ const init = (config, emitter, customFileHandlers) => {
79
78
  { pattern: path.join(ksmsPath, 'client.js'), watched: false }
80
79
  ], true);
81
80
  }
81
+ config.reporters.push('@angular-devkit/build-angular--event-reporter');
82
82
  // Add webpack config.
83
83
  const webpackConfig = config.buildWebpack.webpackConfig;
84
84
  const webpackMiddlewareConfig = {
@@ -29,6 +29,7 @@ class BundleCalculator extends Calculator {
29
29
  const size = this.compilation.chunks
30
30
  .filter(chunk => chunk.name === this.budget.name)
31
31
  .reduce((files, chunk) => [...files, ...chunk.files], [])
32
+ .filter((file) => !file.endsWith('.map'))
32
33
  .map((file) => this.compilation.assets[file].size())
33
34
  .reduce((total, size) => total + size, 0);
34
35
  return [{ size, label: this.budget.name }];
@@ -21,7 +21,7 @@ function writeIndexHtml({ host, outputPath, indexPath, ES5BuildFiles, ES2015Buil
21
21
  deployUrl,
22
22
  sri,
23
23
  entrypoints: package_chunk_sort_1.generateEntryPoints({ scripts, styles }),
24
- files: filterAndMapBuildFiles(ES5BuildFiles, '.css'),
24
+ files: filterAndMapBuildFiles(ES2015BuildFiles, '.css'),
25
25
  noModuleFiles: filterAndMapBuildFiles(ES5BuildFiles, '.js'),
26
26
  moduleFiles: filterAndMapBuildFiles(ES2015BuildFiles, '.js'),
27
27
  loadOutputFile: async (filePath) => {
@@ -11,6 +11,7 @@ function generateEntryPoints(appConfig) {
11
11
  return [...new Set(entryPoints)];
12
12
  };
13
13
  const entryPoints = [
14
+ 'polyfills-nomodule-es5',
14
15
  'polyfills-es5',
15
16
  'polyfills',
16
17
  'sw-register',
@@ -5,5 +5,12 @@
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
- import * as ts from 'typescript';
9
- export declare function readTsconfig(tsconfigPath: string): ts.ParsedCommandLine;
8
+ import { ParsedConfiguration } from '@angular/compiler-cli';
9
+ /**
10
+ * Reads and parses a given TsConfig file.
11
+ *
12
+ * @param tsconfigPath - An absolute or relative path from 'workspaceRoot' of the tsconfig file.
13
+ * @param workspaceRoot - workspaceRoot root location when provided
14
+ * it will resolve 'tsconfigPath' from this path.
15
+ */
16
+ export declare function readTsconfig(tsconfigPath: string, workspaceRoot?: string): ParsedConfiguration;
@@ -1,14 +1,31 @@
1
1
  "use strict";
2
+ /**
3
+ * @license
4
+ * Copyright Google Inc. All Rights Reserved.
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://angular.io/license
8
+ */
2
9
  Object.defineProperty(exports, "__esModule", { value: true });
3
10
  const path = require("path");
4
- const require_project_module_1 = require("../utilities/require-project-module");
5
- function readTsconfig(tsconfigPath) {
6
- const projectTs = require_project_module_1.requireProjectModule(path.dirname(tsconfigPath), 'typescript');
7
- const configResult = projectTs.readConfigFile(tsconfigPath, projectTs.sys.readFile);
8
- const tsConfig = projectTs.parseJsonConfigFileContent(configResult.config, projectTs.sys, path.dirname(tsconfigPath), undefined, tsconfigPath);
9
- if (tsConfig.errors.length > 0) {
10
- throw new Error(`Errors found while reading ${tsconfigPath}:\n ${tsConfig.errors.map(e => e.messageText).join('\n ')}`);
11
+ /**
12
+ * Reads and parses a given TsConfig file.
13
+ *
14
+ * @param tsconfigPath - An absolute or relative path from 'workspaceRoot' of the tsconfig file.
15
+ * @param workspaceRoot - workspaceRoot root location when provided
16
+ * it will resolve 'tsconfigPath' from this path.
17
+ */
18
+ function readTsconfig(tsconfigPath, workspaceRoot) {
19
+ const tsConfigFullPath = workspaceRoot
20
+ ? path.resolve(workspaceRoot, tsconfigPath)
21
+ : tsconfigPath;
22
+ // We use 'ng' instead of 'ts' here because 'ts' is not aware of 'angularCompilerOptions'
23
+ // and will not merged them if they are at un upper level tsconfig file when using `extends`.
24
+ const ng = require('@angular/compiler-cli');
25
+ const configResult = ng.readConfiguration(tsConfigFullPath);
26
+ if (configResult.errors && configResult.errors.length) {
27
+ throw new Error(ng.formatDiagnostics(configResult.errors));
11
28
  }
12
- return tsConfig;
29
+ return configResult;
13
30
  }
14
31
  exports.readTsconfig = readTsconfig;
@@ -68,7 +68,7 @@ async function augmentAppWithServiceWorker(host, projectRoot, appRoot, outputPat
68
68
  if (!configExists) {
69
69
  throw new Error(core_1.tags.oneLine `
70
70
  Error: Expected to find an ngsw-config.json configuration
71
- file in the ${appRoot} folder. Either provide one or disable Service Worker
71
+ file in the ${core_1.getSystemPath(appRoot)} folder. Either provide one or disable Service Worker
72
72
  in your angular.json configuration file.
73
73
  `);
74
74
  }
@@ -106,11 +106,10 @@ function buildWebpackBrowser(options, context, transforms = {}) {
106
106
  throw new Error('Must either have a target from the context or a default project.');
107
107
  }
108
108
  const projectRoot = core_1.resolve(workspace.root, core_1.normalize(workspace.getProject(projectName).root));
109
- const tsConfigPath = path.resolve(core_1.getSystemPath(workspace.root), options.tsConfig);
110
- const tsConfig = read_tsconfig_1.readTsconfig(tsConfigPath);
111
- if (utils_1.isEs5SupportNeeded(projectRoot) &&
112
- tsConfig.options.target !== typescript_1.ScriptTarget.ES5 &&
113
- tsConfig.options.target !== typescript_1.ScriptTarget.ES2015) {
109
+ const tsConfig = read_tsconfig_1.readTsconfig(options.tsConfig, context.workspaceRoot);
110
+ const target = tsConfig.options.target || typescript_1.ScriptTarget.ES5;
111
+ const buildBrowserFeatures = new utils_1.BuildBrowserFeatures(core_1.getSystemPath(projectRoot), target);
112
+ if (target > typescript_1.ScriptTarget.ES2015 && buildBrowserFeatures.isDifferentialLoadingNeeded()) {
114
113
  context.logger.warn(core_1.tags.stripIndent `
115
114
  WARNING: Using differential loading with targets ES5 and ES2016 or higher may
116
115
  cause problems. Browsers with support for ES2015 will load the ES2016+ scripts
@@ -145,14 +144,14 @@ function buildWebpackBrowser(options, context, transforms = {}) {
145
144
  scripts: options.scripts,
146
145
  styles: options.styles,
147
146
  })
148
- .pipe(operators_1.map(() => ({ success: true })), operators_1.catchError(() => rxjs_1.of({ success: false })));
147
+ .pipe(operators_1.map(() => ({ success: true })), operators_1.catchError(error => rxjs_1.of({ success: false, error: mapErrorToMessage(error) })));
149
148
  }
150
149
  else {
151
150
  return rxjs_1.of({ success });
152
151
  }
153
152
  }), operators_1.concatMap(buildEvent => {
154
153
  if (buildEvent.success && !options.watch && options.serviceWorker) {
155
- return rxjs_1.from(service_worker_1.augmentAppWithServiceWorker(host, root, projectRoot, core_1.resolve(root, core_1.normalize(options.outputPath)), options.baseHref || '/', options.ngswConfigPath).then(() => ({ success: true }), () => ({ success: false })));
154
+ return rxjs_1.from(service_worker_1.augmentAppWithServiceWorker(host, root, projectRoot, core_1.resolve(root, core_1.normalize(options.outputPath)), options.baseHref || '/', options.ngswConfigPath).then(() => ({ success: true }), error => ({ success: false, error: mapErrorToMessage(error) })));
156
155
  }
157
156
  else {
158
157
  return rxjs_1.of(buildEvent);
@@ -165,4 +164,13 @@ function buildWebpackBrowser(options, context, transforms = {}) {
165
164
  }));
166
165
  }
167
166
  exports.buildWebpackBrowser = buildWebpackBrowser;
167
+ function mapErrorToMessage(error) {
168
+ if (error instanceof Error) {
169
+ return error.message;
170
+ }
171
+ if (typeof error === 'string') {
172
+ return error;
173
+ }
174
+ return undefined;
175
+ }
168
176
  exports.default = architect_1.createBuilder(buildWebpackBrowser);
@@ -72,7 +72,9 @@ export interface Schema {
72
72
  */
73
73
  proxyConfig?: string;
74
74
  /**
75
- * Specify the URL that the browser client will use.
75
+ * The URL that the browser client (or live-reload client, if enabled) should use to connect
76
+ * to the development server. Use for a complex dev server setup, such as one with reverse
77
+ * proxies.
76
78
  */
77
79
  publicHost?: string;
78
80
  /**
@@ -54,7 +54,7 @@
54
54
  },
55
55
  "publicHost": {
56
56
  "type": "string",
57
- "description": "Specify the URL that the browser client will use."
57
+ "description": "The URL that the browser client (or live-reload client, if enabled) should use to connect to the development server. Use for a complex dev server setup, such as one with reverse proxies."
58
58
  },
59
59
  "servePath": {
60
60
  "type": "string",
@@ -12,6 +12,7 @@ const build_webpack_1 = require("@angular-devkit/build-webpack");
12
12
  const path = require("path");
13
13
  const webpack = require("webpack");
14
14
  const webpack_configs_1 = require("../angular-cli-files/models/webpack-configs");
15
+ const read_tsconfig_1 = require("../angular-cli-files/utilities/read-tsconfig");
15
16
  const stats_1 = require("../angular-cli-files/utilities/stats");
16
17
  const version_1 = require("../utils/version");
17
18
  const webpack_browser_config_1 = require("../utils/webpack-browser-config");
@@ -40,6 +41,13 @@ async function execute(options, context) {
40
41
  version_1.Version.assertCompatibleAngularVersion(context.workspaceRoot);
41
42
  const browserTarget = architect_1.targetFromTargetString(options.browserTarget);
42
43
  const browserOptions = await context.validateOptions(await context.getTargetOptions(browserTarget), await context.getBuilderNameForTarget(browserTarget));
44
+ // FIXME: i18n is not yet implemented in Ivy
45
+ // We should display a warning and exit gracefully.
46
+ const { options: compilerOptions } = read_tsconfig_1.readTsconfig(browserOptions.tsConfig, context.workspaceRoot);
47
+ if (compilerOptions.enableIvy) {
48
+ context.logger.warn('We are sorry but i18n is not yet implemented in Ivy.');
49
+ return { success: true };
50
+ }
43
51
  // We need to determine the outFile name so that AngularCompiler can retrieve it.
44
52
  let outFile = options.outFile || getI18nOutfile(options.i18nFormat);
45
53
  if (options.outputPath) {
@@ -52,6 +60,7 @@ async function execute(options, context) {
52
60
  scripts: false,
53
61
  styles: false,
54
62
  },
63
+ buildOptimizer: false,
55
64
  i18nLocale: options.i18nLocale,
56
65
  i18nFormat: options.i18nFormat,
57
66
  i18nFile: outFile,
@@ -81,7 +81,7 @@ function execute(options, context, transforms = {}) {
81
81
  return karmaStart.then(() => karmaServerWithStop.stop());
82
82
  }
83
83
  };
84
- })));
84
+ })), operators_1.defaultIfEmpty({ success: false }));
85
85
  }
86
86
  exports.execute = execute;
87
87
  exports.default = architect_1.createBuilder(execute);
@@ -0,0 +1,35 @@
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 * as ts from 'typescript';
9
+ export declare class BuildBrowserFeatures {
10
+ private projectRoot;
11
+ private scriptTarget;
12
+ private readonly _supportedBrowsers;
13
+ private readonly _es6TargetOrLater;
14
+ constructor(projectRoot: string, scriptTarget: ts.ScriptTarget);
15
+ /**
16
+ * True, when one or more browsers requires ES5
17
+ * support and the scirpt target is ES2015 or greater.
18
+ */
19
+ isDifferentialLoadingNeeded(): boolean;
20
+ /**
21
+ * True, when one or more browsers requires ES5 support
22
+ */
23
+ isEs5SupportNeeded(): boolean;
24
+ /**
25
+ * Safari 10.1 and iOS Safari 10.3 supports modules,
26
+ * but does not support the `nomodule` attribute.
27
+ * While return `true`, when support for Safari 10.1 and iOS Safari 10.3
28
+ * is required and in differential loading is enabled.
29
+ */
30
+ isNoModulePolyfillNeeded(): boolean;
31
+ /**
32
+ * True, when a browser feature is supported partially or fully.
33
+ */
34
+ isFeatureSupported(featureId: string): boolean;
35
+ }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ /**
3
+ * @license
4
+ * Copyright Google Inc. All Rights Reserved.
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://angular.io/license
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ const browserslist = require("browserslist");
11
+ const caniuse_lite_1 = require("caniuse-lite");
12
+ const ts = require("typescript");
13
+ class BuildBrowserFeatures {
14
+ constructor(projectRoot, scriptTarget) {
15
+ this.projectRoot = projectRoot;
16
+ this.scriptTarget = scriptTarget;
17
+ this._supportedBrowsers = browserslist(undefined, { path: this.projectRoot });
18
+ this._es6TargetOrLater = this.scriptTarget > ts.ScriptTarget.ES5;
19
+ }
20
+ /**
21
+ * True, when one or more browsers requires ES5
22
+ * support and the scirpt target is ES2015 or greater.
23
+ */
24
+ isDifferentialLoadingNeeded() {
25
+ return this._es6TargetOrLater && this.isEs5SupportNeeded();
26
+ }
27
+ /**
28
+ * True, when one or more browsers requires ES5 support
29
+ */
30
+ isEs5SupportNeeded() {
31
+ return !this.isFeatureSupported('es6-module');
32
+ }
33
+ /**
34
+ * Safari 10.1 and iOS Safari 10.3 supports modules,
35
+ * but does not support the `nomodule` attribute.
36
+ * While return `true`, when support for Safari 10.1 and iOS Safari 10.3
37
+ * is required and in differential loading is enabled.
38
+ */
39
+ isNoModulePolyfillNeeded() {
40
+ if (!this.isDifferentialLoadingNeeded()) {
41
+ return false;
42
+ }
43
+ const safariBrowsers = [
44
+ 'safari 10.1',
45
+ 'ios_saf 10.3',
46
+ ];
47
+ return this._supportedBrowsers.some(browser => safariBrowsers.includes(browser));
48
+ }
49
+ /**
50
+ * True, when a browser feature is supported partially or fully.
51
+ */
52
+ isFeatureSupported(featureId) {
53
+ // y: feature is fully available
54
+ // n: feature is unavailable
55
+ // a: feature is partially supported
56
+ // x: feature is prefixed
57
+ const criteria = [
58
+ 'y',
59
+ 'a',
60
+ ];
61
+ const data = caniuse_lite_1.feature(caniuse_lite_1.features[featureId]);
62
+ return !this._supportedBrowsers
63
+ .some(browser => {
64
+ const [agentId, version] = browser.split(' ');
65
+ const browserData = data.stats[agentId];
66
+ const featureStatus = (browserData && browserData[version]);
67
+ // We are only interested in the first character
68
+ // Ex: when 'a #4 #5', we only need to check for 'a'
69
+ // as for such cases we should polyfill these features as needed
70
+ return !featureStatus || !criteria.includes(featureStatus.charAt(0));
71
+ });
72
+ }
73
+ }
74
+ exports.BuildBrowserFeatures = BuildBrowserFeatures;
@@ -5,9 +5,9 @@
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
+ export * from './build-browser-features';
8
9
  export * from './default-progress';
9
10
  export * from './delete-output-dir';
10
- export * from './differential-loading';
11
11
  export * from './run-module-as-observable-fork';
12
12
  export * from './normalize-file-replacements';
13
13
  export * from './normalize-asset-patterns';
@@ -1,8 +1,4 @@
1
1
  "use strict";
2
- function __export(m) {
3
- for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
4
- }
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
2
  /**
7
3
  * @license
8
4
  * Copyright Google Inc. All Rights Reserved.
@@ -10,9 +6,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
6
  * Use of this source code is governed by an MIT-style license that can be
11
7
  * found in the LICENSE file at https://angular.io/license
12
8
  */
9
+ function __export(m) {
10
+ for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
11
+ }
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ __export(require("./build-browser-features"));
13
14
  __export(require("./default-progress"));
14
15
  __export(require("./delete-output-dir"));
15
- __export(require("./differential-loading"));
16
16
  __export(require("./run-module-as-observable-fork"));
17
17
  __export(require("./normalize-file-replacements"));
18
18
  __export(require("./normalize-asset-patterns"));
@@ -6,7 +6,7 @@ const path = require("path");
6
6
  const webpack_configs_1 = require("../angular-cli-files/models/webpack-configs");
7
7
  const read_tsconfig_1 = require("../angular-cli-files/utilities/read-tsconfig");
8
8
  const utils_1 = require("../utils");
9
- const differential_loading_1 = require("./differential-loading");
9
+ const build_browser_features_1 = require("./build-browser-features");
10
10
  const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
11
11
  const webpackMerge = require('webpack-merge');
12
12
  async function generateWebpackConfig(context, workspaceRoot, projectRoot, sourceRoot, options, webpackPartialGenerator, logger) {
@@ -20,9 +20,11 @@ async function generateWebpackConfig(context, workspaceRoot, projectRoot, source
20
20
  const ts = await Promise.resolve().then(() => require('typescript'));
21
21
  // At the moment, only the browser builder supports differential loading
22
22
  // However this config generation is used by multiple builders such as dev-server
23
- const scriptTarget = tsConfig.options.target;
23
+ const scriptTarget = tsConfig.options.target || ts.ScriptTarget.ES5;
24
+ const buildBrowserFeatures = new build_browser_features_1.BuildBrowserFeatures(projectRoot, scriptTarget);
24
25
  const differentialLoading = context.builder.builderName === 'browser'
25
- && differential_loading_1.isDifferentialLoadingNeeded(projectRoot, scriptTarget) && !options.watch;
26
+ && !options.watch
27
+ && buildBrowserFeatures.isDifferentialLoadingNeeded();
26
28
  const scriptTargets = [scriptTarget];
27
29
  if (differentialLoading) {
28
30
  scriptTargets.unshift(ts.ScriptTarget.ES5);
@@ -30,18 +32,26 @@ async function generateWebpackConfig(context, workspaceRoot, projectRoot, source
30
32
  // For differential loading, we can have several targets
31
33
  return scriptTargets.map(scriptTarget => {
32
34
  let buildOptions = { ...options };
35
+ const supportES2015 = scriptTarget !== ts.ScriptTarget.ES3 && scriptTarget !== ts.ScriptTarget.ES5;
33
36
  if (differentialLoading) {
34
- // For differential loading, the builder needs to created the index.html by itself
35
- // without using a webpack plugin.
36
37
  buildOptions = {
37
38
  ...options,
39
+ ...(
40
+ // FIXME: we do create better webpack config composition to achieve the below
41
+ // When DL is enabled and supportES2015 is true it means that we are on the second build
42
+ // This also means that we don't need to include styles and assets multiple times
43
+ supportES2015
44
+ ? {}
45
+ : {
46
+ styles: options.extractCss ? [] : options.styles,
47
+ assets: [],
48
+ }),
38
49
  es5BrowserSupport: undefined,
39
50
  index: '',
40
51
  esVersionInFileName: true,
41
52
  scriptTargetOverride: scriptTarget,
42
53
  };
43
54
  }
44
- const supportES2015 = scriptTarget !== ts.ScriptTarget.ES3 && scriptTarget !== ts.ScriptTarget.ES5;
45
55
  const wco = {
46
56
  root: workspaceRoot,
47
57
  logger: logger.createChild('webpackConfigOptions'),
@@ -1,10 +0,0 @@
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 { ScriptTarget } from 'typescript';
9
- export declare function isDifferentialLoadingNeeded(projectRoot: string, target?: ScriptTarget): boolean;
10
- export declare function isEs5SupportNeeded(projectRoot: string): boolean;
@@ -1,24 +0,0 @@
1
- "use strict";
2
- /**
3
- * @license
4
- * Copyright Google Inc. All Rights Reserved.
5
- *
6
- * Use of this source code is governed by an MIT-style license that can be
7
- * found in the LICENSE file at https://angular.io/license
8
- */
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- const browserslist = require("browserslist");
11
- const caniuse = require("caniuse-api");
12
- const typescript_1 = require("typescript");
13
- function isDifferentialLoadingNeeded(projectRoot, target = typescript_1.ScriptTarget.ES5) {
14
- const supportES2015 = target !== typescript_1.ScriptTarget.ES3 && target !== typescript_1.ScriptTarget.ES5;
15
- return supportES2015 && isEs5SupportNeeded(projectRoot);
16
- }
17
- exports.isDifferentialLoadingNeeded = isDifferentialLoadingNeeded;
18
- function isEs5SupportNeeded(projectRoot) {
19
- const browsersList = browserslist(undefined, {
20
- path: projectRoot,
21
- });
22
- return !caniuse.isSupported('es6-module', browsersList.join(', '));
23
- }
24
- exports.isEs5SupportNeeded = isEs5SupportNeeded;