@angular-devkit/build-angular 14.0.0-rc.1 → 14.0.0-rc.2

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.
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@angular-devkit/build-angular",
3
- "version": "14.0.0-rc.1",
3
+ "version": "14.0.0-rc.2",
4
4
  "description": "Angular Webpack Build Facade",
5
5
  "main": "src/index.js",
6
6
  "typings": "src/index.d.ts",
7
7
  "builders": "builders.json",
8
8
  "dependencies": {
9
9
  "@ampproject/remapping": "2.2.0",
10
- "@angular-devkit/architect": "0.1400.0-rc.1",
11
- "@angular-devkit/build-webpack": "0.1400.0-rc.1",
12
- "@angular-devkit/core": "14.0.0-rc.1",
10
+ "@angular-devkit/architect": "0.1400.0-rc.2",
11
+ "@angular-devkit/build-webpack": "0.1400.0-rc.2",
12
+ "@angular-devkit/core": "14.0.0-rc.2",
13
13
  "@babel/core": "7.17.10",
14
14
  "@babel/generator": "7.17.10",
15
15
  "@babel/helper-annotate-as-pure": "7.16.7",
@@ -20,7 +20,7 @@
20
20
  "@babel/runtime": "7.17.9",
21
21
  "@babel/template": "7.16.7",
22
22
  "@discoveryjs/json-ext": "0.5.7",
23
- "@ngtools/webpack": "14.0.0-rc.1",
23
+ "@ngtools/webpack": "14.0.0-rc.2",
24
24
  "ansi-colors": "4.1.1",
25
25
  "babel-loader": "8.2.5",
26
26
  "babel-plugin-istanbul": "6.1.1",
@@ -32,7 +32,7 @@ export interface ApplicationPresetOptions {
32
32
  jitMode: boolean;
33
33
  linkerPluginCreator: typeof import('@angular/compiler-cli/linker/babel').createEs2015LinkerPlugin;
34
34
  };
35
- forceES5?: boolean;
35
+ forcePresetEnv?: boolean;
36
36
  forceAsyncTransformation?: boolean;
37
37
  instrumentCode?: {
38
38
  includedBasePath: string;
@@ -43,6 +43,7 @@ export interface ApplicationPresetOptions {
43
43
  pureTopLevel: boolean;
44
44
  wrapDecorators: boolean;
45
45
  };
46
+ supportedBrowsers?: string[];
46
47
  diagnosticReporter?: DiagnosticReporter;
47
48
  }
48
49
  export default function (api: unknown, options: ApplicationPresetOptions): {
@@ -116,14 +116,13 @@ function default_1(api, options) {
116
116
  },
117
117
  }));
118
118
  }
119
- if (options.forceES5) {
119
+ if (options.forcePresetEnv) {
120
120
  presets.push([
121
121
  require('@babel/preset-env').default,
122
122
  {
123
123
  bugfixes: true,
124
124
  modules: false,
125
- // Comparable behavior to tsconfig target of ES5
126
- targets: { ie: 9 },
125
+ targets: options.supportedBrowsers,
127
126
  exclude: ['transform-typeof-symbol'],
128
127
  },
129
128
  ]);
@@ -53,15 +53,16 @@ exports.default = (0, babel_loader_1.custom)(() => {
53
53
  return {
54
54
  async customOptions(options, { source, map }) {
55
55
  var _a, _b;
56
- const { i18n, scriptTarget, aot, optimize, instrumentCode, ...rawOptions } = options;
56
+ const { i18n, scriptTarget, aot, optimize, instrumentCode, supportedBrowsers, ...rawOptions } = options;
57
57
  // Must process file if plugins are added
58
58
  let shouldProcess = Array.isArray(rawOptions.plugins) && rawOptions.plugins.length > 0;
59
59
  const customOptions = {
60
60
  forceAsyncTransformation: false,
61
- forceES5: false,
61
+ forcePresetEnv: false,
62
62
  angularLinker: undefined,
63
63
  i18n: undefined,
64
64
  instrumentCode: undefined,
65
+ supportedBrowsers,
65
66
  };
66
67
  // Analyze file for linking
67
68
  if (await requiresLinking(this.resourcePath, source)) {
@@ -78,20 +79,31 @@ exports.default = (0, babel_loader_1.custom)(() => {
78
79
  }
79
80
  // Analyze for ES target processing
80
81
  const esTarget = scriptTarget;
81
- if (esTarget !== undefined) {
82
- if (esTarget < typescript_1.ScriptTarget.ES2015) {
83
- customOptions.forceES5 = true;
84
- }
85
- else if (esTarget >= typescript_1.ScriptTarget.ES2017 || /\.[cm]?js$/.test(this.resourcePath)) {
86
- // Application code (TS files) will only contain native async if target is ES2017+.
87
- // However, third-party libraries can regardless of the target option.
88
- // APF packages with code in [f]esm2015 directories is downlevelled to ES2015 and
89
- // will not have native async.
90
- customOptions.forceAsyncTransformation =
91
- !/[\\/][_f]?esm2015[\\/]/.test(this.resourcePath) && source.includes('async');
92
- }
93
- shouldProcess || (shouldProcess = customOptions.forceAsyncTransformation || customOptions.forceES5 || false);
82
+ const isJsFile = /\.[cm]?js$/.test(this.resourcePath);
83
+ // The below should be dropped when we no longer support ES5 TypeScript output.
84
+ if (esTarget === typescript_1.ScriptTarget.ES5) {
85
+ // This is needed because when target is ES5 we change the TypeScript target to ES2015
86
+ // because it simplifies build-optimization passes.
87
+ // @see https://github.com/angular/angular-cli/blob/22af6520834171d01413d4c7e4a9f13fb752252e/packages/angular_devkit/build_angular/src/webpack/plugins/typescript.ts#L51-L56
88
+ customOptions.forcePresetEnv = true;
89
+ // Comparable behavior to tsconfig target of ES5
90
+ customOptions.supportedBrowsers = ['IE 9'];
91
+ }
92
+ else if (isJsFile) {
93
+ // Applications code ES version can be controlled using TypeScript's `target` option.
94
+ // However, this doesn't effect libraries and hence we use preset-env to downlevel ES fetaures
95
+ // based on the supported browsers in browserlist.
96
+ customOptions.forcePresetEnv = true;
97
+ }
98
+ if ((esTarget !== undefined && esTarget >= typescript_1.ScriptTarget.ES2017) || isJsFile) {
99
+ // Application code (TS files) will only contain native async if target is ES2017+.
100
+ // However, third-party libraries can regardless of the target option.
101
+ // APF packages with code in [f]esm2015 directories is downlevelled to ES2015 and
102
+ // will not have native async.
103
+ customOptions.forceAsyncTransformation =
104
+ !/[\\/][_f]?esm2015[\\/]/.test(this.resourcePath) && source.includes('async');
94
105
  }
106
+ shouldProcess || (shouldProcess = customOptions.forceAsyncTransformation || customOptions.forcePresetEnv || false);
95
107
  // Analyze for i18n inlining
96
108
  if (i18n &&
97
109
  !/[\\/]@angular[\\/](?:compiler|localize)/.test(this.resourcePath) &&
@@ -7,6 +7,8 @@
7
7
  */
8
8
  import { BuilderContext } from '@angular-devkit/architect';
9
9
  import { BuildFailure, BuildOptions, BuildResult, Message, OutputFile } from 'esbuild';
10
+ /** Default outdir setting for esbuild. */
11
+ export declare const DEFAULT_OUTDIR: string;
10
12
  /**
11
13
  * Determines if an unknown value is an esbuild BuildFailure error object thrown by esbuild.
12
14
  * @param value A potential esbuild BuildFailure error object.
@@ -7,8 +7,11 @@
7
7
  * found in the LICENSE file at https://angular.io/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.logMessages = exports.bundle = exports.isEsBuildFailure = void 0;
10
+ exports.logMessages = exports.bundle = exports.isEsBuildFailure = exports.DEFAULT_OUTDIR = void 0;
11
11
  const esbuild_1 = require("esbuild");
12
+ const path_1 = require("path");
13
+ /** Default outdir setting for esbuild. */
14
+ exports.DEFAULT_OUTDIR = (0, path_1.resolve)('/virtual-output');
12
15
  /**
13
16
  * Determines if an unknown value is an esbuild BuildFailure error object thrown by esbuild.
14
17
  * @param value A potential esbuild BuildFailure error object.
@@ -99,11 +99,11 @@ async function execute(options, context) {
99
99
  // Entries in the metafile are relative to the `absWorkingDir` option which is set to the workspaceRoot
100
100
  const relativeFilePath = path.relative(workspaceRoot, outputFile.path);
101
101
  const entryPoint = (_c = (_b = result.metafile) === null || _b === void 0 ? void 0 : _b.outputs[relativeFilePath]) === null || _c === void 0 ? void 0 : _c.entryPoint;
102
+ outputFile.path = path.relative(esbuild_1.DEFAULT_OUTDIR, outputFile.path);
102
103
  if (entryPoint) {
103
104
  // An entryPoint value indicates an initial file
104
105
  initialFiles.push({
105
- // Remove leading directory separator
106
- file: outputFile.path.slice(1),
106
+ file: outputFile.path,
107
107
  name: (_d = entryPointNameLookup.get(entryPoint)) !== null && _d !== void 0 ? _d : '',
108
108
  extension: path.extname(outputFile.path),
109
109
  });
@@ -124,7 +124,9 @@ async function execute(options, context) {
124
124
  // resolveGlobalStyles is temporarily reused from the Webpack builder code
125
125
  const { entryPoints: stylesheetEntrypoints, noInjectNames } = (0, configs_1.resolveGlobalStyles)(options.styles, workspaceRoot, !!options.preserveSymlinks);
126
126
  for (const [name, files] of Object.entries(stylesheetEntrypoints)) {
127
- const virtualEntryData = files.map((file) => `@import '${file}';`).join('\n');
127
+ const virtualEntryData = files
128
+ .map((file) => `@import '${file.replace(/\\/g, '/')}';`)
129
+ .join('\n');
128
130
  const sheetResult = await (0, stylesheets_1.bundleStylesheetText)(virtualEntryData, { virtualName: `angular:style/global;${name}`, resolvePath: workspaceRoot }, {
129
131
  optimization: !!optimizationOptions.styles.minify,
130
132
  sourcemap: !!sourcemapOptions.styles,
@@ -139,7 +141,7 @@ async function execute(options, context) {
139
141
  // The virtual stylesheets will be named `stdin` by esbuild. This must be replaced
140
142
  // with the actual name of the global style and the leading directory separator must
141
143
  // also be removed to make the path relative.
142
- const sheetPath = sheetResult.path.replace('stdin', name).slice(1);
144
+ const sheetPath = sheetResult.path.replace('stdin', name);
143
145
  outputFiles.push(createOutputFileFromText(sheetPath, sheetResult.contents));
144
146
  if (sheetResult.map) {
145
147
  outputFiles.push(createOutputFileFromText(sheetPath + '.map', sheetResult.map));
@@ -168,10 +170,12 @@ async function execute(options, context) {
168
170
  optimization: optimizationOptions,
169
171
  crossOrigin: options.crossOrigin,
170
172
  });
171
- indexHtmlGenerator.readAsset = async function (path) {
173
+ /** Virtual output path to support reading in-memory files. */
174
+ const virtualOutputPath = '/';
175
+ indexHtmlGenerator.readAsset = async function (filePath) {
172
176
  // Remove leading directory separator
173
- path = path.slice(1);
174
- const file = outputFiles.find((file) => file.path === path);
177
+ const relativefilePath = path.relative(virtualOutputPath, filePath);
178
+ const file = outputFiles.find((file) => file.path === relativefilePath);
175
179
  if (file) {
176
180
  return file.text;
177
181
  }
@@ -180,7 +184,7 @@ async function execute(options, context) {
180
184
  const { content, warnings, errors } = await indexHtmlGenerator.process({
181
185
  baseHref: options.baseHref,
182
186
  lang: undefined,
183
- outputPath: '/',
187
+ outputPath: virtualOutputPath,
184
188
  files: initialFiles,
185
189
  });
186
190
  for (const error of errors) {
@@ -226,7 +230,7 @@ async function bundleCode(workspaceRoot, entryPoints, outputNames, options, opti
226
230
  metafile: true,
227
231
  minify: optimizationOptions.scripts,
228
232
  pure: ['forwardRef'],
229
- outdir: '/',
233
+ outdir: esbuild_1.DEFAULT_OUTDIR,
230
234
  sourcemap: sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true),
231
235
  splitting: true,
232
236
  tsconfig,
@@ -45,7 +45,7 @@ async function bundleStylesheet(entry, options) {
45
45
  logLevel: 'silent',
46
46
  minify: options.optimization,
47
47
  sourcemap: options.sourcemap,
48
- outdir: '/',
48
+ outdir: esbuild_1.DEFAULT_OUTDIR,
49
49
  write: false,
50
50
  platform: 'browser',
51
51
  preserveSymlinks: options.preserveSymlinks,
@@ -62,6 +62,7 @@ async function bundleStylesheet(entry, options) {
62
62
  const resourceFiles = [];
63
63
  if (result.outputFiles) {
64
64
  for (const outputFile of result.outputFiles) {
65
+ outputFile.path = path.relative(esbuild_1.DEFAULT_OUTDIR, outputFile.path);
65
66
  const filename = path.basename(outputFile.path);
66
67
  if (filename.endsWith('.css')) {
67
68
  outputPath = outputFile.path;
@@ -100,67 +100,65 @@ async function execute(options, context) {
100
100
  }
101
101
  let baseUrl = options.baseUrl;
102
102
  let server;
103
- if (options.devServerTarget) {
104
- const target = (0, architect_1.targetFromTargetString)(options.devServerTarget);
105
- const serverOptions = await context.getTargetOptions(target);
106
- const overrides = {
107
- watch: false,
108
- liveReload: false,
109
- };
110
- if (options.host !== undefined) {
111
- overrides.host = options.host;
112
- }
113
- else if (typeof serverOptions.host === 'string') {
114
- options.host = serverOptions.host;
115
- }
116
- else {
117
- options.host = overrides.host = 'localhost';
118
- }
119
- if (options.port !== undefined) {
120
- overrides.port = options.port;
121
- }
122
- else if (typeof serverOptions.port === 'number') {
123
- options.port = serverOptions.port;
124
- }
125
- server = await context.scheduleTarget(target, overrides);
126
- const result = await server.result;
127
- if (!result.success) {
128
- return { success: false };
129
- }
130
- if (typeof serverOptions.publicHost === 'string') {
131
- let publicHost = serverOptions.publicHost;
132
- if (!/^\w+:\/\//.test(publicHost)) {
133
- publicHost = `${serverOptions.ssl ? 'https' : 'http'}://${publicHost}`;
103
+ try {
104
+ if (options.devServerTarget) {
105
+ const target = (0, architect_1.targetFromTargetString)(options.devServerTarget);
106
+ const serverOptions = await context.getTargetOptions(target);
107
+ const overrides = {
108
+ watch: false,
109
+ liveReload: false,
110
+ };
111
+ if (options.host !== undefined) {
112
+ overrides.host = options.host;
113
+ }
114
+ else if (typeof serverOptions.host === 'string') {
115
+ options.host = serverOptions.host;
116
+ }
117
+ else {
118
+ options.host = overrides.host = 'localhost';
119
+ }
120
+ if (options.port !== undefined) {
121
+ overrides.port = options.port;
122
+ }
123
+ else if (typeof serverOptions.port === 'number') {
124
+ options.port = serverOptions.port;
125
+ }
126
+ server = await context.scheduleTarget(target, overrides);
127
+ const result = await server.result;
128
+ if (!result.success) {
129
+ return { success: false };
130
+ }
131
+ if (typeof serverOptions.publicHost === 'string') {
132
+ let publicHost = serverOptions.publicHost;
133
+ if (!/^\w+:\/\//.test(publicHost)) {
134
+ publicHost = `${serverOptions.ssl ? 'https' : 'http'}://${publicHost}`;
135
+ }
136
+ const clientUrl = url.parse(publicHost);
137
+ baseUrl = url.format(clientUrl);
138
+ }
139
+ else if (typeof result.baseUrl === 'string') {
140
+ baseUrl = result.baseUrl;
141
+ }
142
+ else if (typeof result.port === 'number') {
143
+ baseUrl = url.format({
144
+ protocol: serverOptions.ssl ? 'https' : 'http',
145
+ hostname: options.host,
146
+ port: result.port.toString(),
147
+ });
134
148
  }
135
- const clientUrl = url.parse(publicHost);
136
- baseUrl = url.format(clientUrl);
137
- }
138
- else if (typeof result.baseUrl === 'string') {
139
- baseUrl = result.baseUrl;
140
149
  }
141
- else if (typeof result.port === 'number') {
142
- baseUrl = url.format({
143
- protocol: serverOptions.ssl ? 'https' : 'http',
144
- hostname: options.host,
145
- port: result.port.toString(),
146
- });
150
+ // Like the baseUrl in protractor config file when using the API we need to add
151
+ // a trailing slash when provide to the baseUrl.
152
+ if (baseUrl && !baseUrl.endsWith('/')) {
153
+ baseUrl += '/';
147
154
  }
148
- }
149
- // Like the baseUrl in protractor config file when using the API we need to add
150
- // a trailing slash when provide to the baseUrl.
151
- if (baseUrl && !baseUrl.endsWith('/')) {
152
- baseUrl += '/';
153
- }
154
- try {
155
155
  return await runProtractor(context.workspaceRoot, { ...options, baseUrl });
156
156
  }
157
157
  catch {
158
158
  return { success: false };
159
159
  }
160
160
  finally {
161
- if (server) {
162
- await server.stop();
163
- }
161
+ await (server === null || server === void 0 ? void 0 : server.stop());
164
162
  }
165
163
  }
166
164
  exports.execute = execute;
@@ -300,6 +300,7 @@ async function getCommonConfig(wco) {
300
300
  scriptTarget,
301
301
  aot: buildOptions.aot,
302
302
  optimize: buildOptions.buildOptimizer,
303
+ supportedBrowsers: buildOptions.supportedBrowsers,
303
304
  instrumentCode: codeCoverage
304
305
  ? {
305
306
  includedBasePath: sourceRoot,
@@ -30,11 +30,13 @@ class CssOptimizerPlugin {
30
30
  apply(compiler) {
31
31
  const { OriginalSource, SourceMapSource } = compiler.webpack.sources;
32
32
  compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
33
+ const logger = compilation.getLogger('build-angular.CssOptimizerPlugin');
33
34
  compilation.hooks.processAssets.tapPromise({
34
35
  name: PLUGIN_NAME,
35
36
  stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,
36
37
  }, async (compilationAssets) => {
37
38
  const cache = compilation.options.cache && compilation.getCache(PLUGIN_NAME);
39
+ logger.time('optimize css assets');
38
40
  for (const assetName of Object.keys(compilationAssets)) {
39
41
  if (!/\.(?:css|scss|sass|less|styl)$/.test(assetName)) {
40
42
  continue;
@@ -51,6 +53,7 @@ class CssOptimizerPlugin {
51
53
  cacheItem = cache.getItemCache(name, eTag);
52
54
  const cachedOutput = await cacheItem.getPromise();
53
55
  if (cachedOutput) {
56
+ logger.debug(`${name} restored from cache`);
54
57
  await this.addWarnings(compilation, cachedOutput.warnings);
55
58
  compilation.updateAsset(name, cachedOutput.source, (assetInfo) => ({
56
59
  ...assetInfo,
@@ -61,7 +64,10 @@ class CssOptimizerPlugin {
61
64
  }
62
65
  const { source, map: inputMap } = styleAssetSource.sourceAndMap();
63
66
  const input = typeof source === 'string' ? source : source.toString();
67
+ const optimizeAssetLabel = `optimize asset: ${asset.name}`;
68
+ logger.time(optimizeAssetLabel);
64
69
  const { code, warnings, map } = await this.optimize(input, asset.name, inputMap, this.targets);
70
+ logger.timeEnd(optimizeAssetLabel);
65
71
  await this.addWarnings(compilation, warnings);
66
72
  const optimizedAsset = map
67
73
  ? new SourceMapSource(code, name, map)
@@ -75,6 +81,7 @@ class CssOptimizerPlugin {
75
81
  warnings,
76
82
  }));
77
83
  }
84
+ logger.timeEnd('optimize css assets');
78
85
  });
79
86
  });
80
87
  }
@@ -38,10 +38,12 @@ class JavaScriptOptimizerPlugin {
38
38
  apply(compiler) {
39
39
  const { OriginalSource, SourceMapSource } = compiler.webpack.sources;
40
40
  compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
41
+ const logger = compilation.getLogger('build-angular.JavaScriptOptimizerPlugin');
41
42
  compilation.hooks.processAssets.tapPromise({
42
43
  name: PLUGIN_NAME,
43
44
  stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,
44
45
  }, async (compilationAssets) => {
46
+ logger.time('optimize js assets');
45
47
  const scriptsToOptimize = [];
46
48
  const cache = compilation.options.cache && compilation.getCache('JavaScriptOptimizerPlugin');
47
49
  // Analyze the compilation assets for scripts that require optimization
@@ -61,6 +63,7 @@ class JavaScriptOptimizerPlugin {
61
63
  cacheItem = cache.getItemCache(name, eTag);
62
64
  const cachedOutput = await cacheItem.getPromise();
63
65
  if (cachedOutput) {
66
+ logger.debug(`${name} restored from cache`);
64
67
  compilation.updateAsset(name, cachedOutput.source, (assetInfo) => ({
65
68
  ...assetInfo,
66
69
  minimized: true,
@@ -125,6 +128,7 @@ class JavaScriptOptimizerPlugin {
125
128
  try {
126
129
  const tasks = [];
127
130
  for (const { name, code, map, cacheItem } of scriptsToOptimize) {
131
+ logger.time(`optimize asset: ${name}`);
128
132
  tasks.push(workerPool
129
133
  .run({
130
134
  asset: {
@@ -142,6 +146,7 @@ class JavaScriptOptimizerPlugin {
142
146
  ...assetInfo,
143
147
  minimized: true,
144
148
  }));
149
+ logger.timeEnd(`optimize asset: ${name}`);
145
150
  return cacheItem === null || cacheItem === void 0 ? void 0 : cacheItem.storePromise({
146
151
  source: optimizedAsset,
147
152
  });
@@ -155,6 +160,7 @@ class JavaScriptOptimizerPlugin {
155
160
  finally {
156
161
  void workerPool.destroy();
157
162
  }
163
+ logger.timeEnd('optimize js assets');
158
164
  });
159
165
  });
160
166
  }
@@ -20,6 +20,7 @@ function ensureIvy(wco) {
20
20
  '\nFor additional information or if the build fails, please see https://angular.io/guide/ivy');
21
21
  wco.tsConfig.options.enableIvy = true;
22
22
  }
23
+ let es5TargetWarningsShown = false;
23
24
  function createIvyPlugin(wco, aot, tsconfig) {
24
25
  if (aot) {
25
26
  ensureIvy(wco);
@@ -39,6 +40,10 @@ function createIvyPlugin(wco, aot, tsconfig) {
39
40
  // as for third-party libraries. This greatly reduces the complexity of static analysis.
40
41
  if (wco.scriptTarget < typescript_1.ScriptTarget.ES2015) {
41
42
  compilerOptions.target = typescript_1.ScriptTarget.ES2015;
43
+ if (!es5TargetWarningsShown) {
44
+ wco.logger.warn('DEPRECATED: ES5 output is deprecated. Please update TypeScript `target` compiler option to ES2015 or later.');
45
+ es5TargetWarningsShown = true;
46
+ }
42
47
  }
43
48
  const fileReplacements = {};
44
49
  if (buildOptions.fileReplacements) {