@angular-devkit/build-angular 13.1.0-next.0 → 13.1.0-rc.0

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 (36) hide show
  1. package/package.json +35 -35
  2. package/src/babel/presets/application.d.ts +5 -2
  3. package/src/babel/presets/application.js +7 -14
  4. package/src/babel/webpack-loader.js +23 -14
  5. package/src/builders/browser/index.js +7 -5
  6. package/src/builders/dev-server/index.js +31 -2
  7. package/src/builders/extract-i18n/ivy-extract-loader.js +4 -1
  8. package/src/utils/build-options.d.ts +1 -0
  9. package/src/utils/bundle-calculator.d.ts +6 -7
  10. package/src/utils/bundle-calculator.js +3 -1
  11. package/src/utils/environment-options.d.ts +0 -1
  12. package/src/utils/environment-options.js +1 -4
  13. package/src/utils/i18n-options.d.ts +16 -10
  14. package/src/utils/i18n-options.js +46 -37
  15. package/src/utils/index-file/augment-index-html.d.ts +5 -1
  16. package/src/utils/index-file/augment-index-html.js +38 -5
  17. package/src/utils/index.d.ts +0 -1
  18. package/src/utils/index.js +0 -1
  19. package/src/utils/normalize-builder-schema.js +2 -0
  20. package/src/utils/read-tsconfig.js +1 -4
  21. package/src/utils/supported-browsers.d.ts +8 -0
  22. package/src/utils/supported-browsers.js +26 -0
  23. package/src/webpack/configs/common.js +27 -23
  24. package/src/webpack/configs/dev-server.js +78 -25
  25. package/src/webpack/configs/styles.js +23 -14
  26. package/src/webpack/plugins/hmr/hmr-accept.js +4 -1
  27. package/src/webpack/plugins/named-chunks-plugin.d.ts +17 -0
  28. package/src/webpack/plugins/named-chunks-plugin.js +49 -0
  29. package/src/webpack/plugins/transfer-size-plugin.d.ts +12 -0
  30. package/src/webpack/plugins/transfer-size-plugin.js +47 -0
  31. package/src/webpack/utils/helpers.d.ts +3 -1
  32. package/src/webpack/utils/helpers.js +18 -3
  33. package/src/webpack/utils/stats.d.ts +10 -3
  34. package/src/webpack/utils/stats.js +111 -33
  35. package/src/utils/build-browser-features.d.ts +0 -16
  36. package/src/utils/build-browser-features.js +0 -54
@@ -10,7 +10,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
10
10
  return (mod && mod.__esModule) ? mod : { "default": mod };
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.configureI18nBuild = exports.createI18nOptions = void 0;
13
+ exports.loadTranslations = exports.configureI18nBuild = exports.createI18nOptions = void 0;
14
14
  const core_1 = require("@angular-devkit/core");
15
15
  const fs_1 = __importDefault(require("fs"));
16
16
  const module_1 = __importDefault(require("module"));
@@ -158,42 +158,18 @@ async function configureI18nBuild(context, options) {
158
158
  if (!desc.files.length) {
159
159
  continue;
160
160
  }
161
- if (!loader) {
162
- loader = await (0, load_translations_1.createTranslationLoader)();
163
- }
164
- for (const file of desc.files) {
165
- const loadResult = loader(path_1.default.join(context.workspaceRoot, file.path));
166
- for (const diagnostics of loadResult.diagnostics.messages) {
167
- if (diagnostics.type === 'error') {
168
- throw new Error(`Error parsing translation file '${file.path}': ${diagnostics.message}`);
169
- }
170
- else {
171
- context.logger.warn(`WARNING [${file.path}]: ${diagnostics.message}`);
172
- }
173
- }
174
- if (loadResult.locale !== undefined && loadResult.locale !== locale) {
175
- context.logger.warn(`WARNING [${file.path}]: File target locale ('${loadResult.locale}') does not match configured locale ('${locale}')`);
176
- }
177
- usedFormats.add(loadResult.format);
178
- if (usedFormats.size > 1 && tsConfig.options.enableI18nLegacyMessageIdFormat !== false) {
179
- // This limitation is only for legacy message id support (defaults to true as of 9.0)
180
- throw new Error('Localization currently only supports using one type of translation file format for the entire application.');
181
- }
182
- file.format = loadResult.format;
183
- file.integrity = loadResult.integrity;
184
- if (desc.translation) {
185
- // Merge translations
186
- for (const [id, message] of Object.entries(loadResult.translations)) {
187
- if (desc.translation[id] !== undefined) {
188
- context.logger.warn(`WARNING [${file.path}]: Duplicate translations for message '${id}' when merging`);
189
- }
190
- desc.translation[id] = message;
191
- }
192
- }
193
- else {
194
- // First or only translation file
195
- desc.translation = loadResult.translations;
196
- }
161
+ loader !== null && loader !== void 0 ? loader : (loader = await (0, load_translations_1.createTranslationLoader)());
162
+ loadTranslations(locale, desc, context.workspaceRoot, loader, {
163
+ warn(message) {
164
+ context.logger.warn(message);
165
+ },
166
+ error(message) {
167
+ throw new Error(message);
168
+ },
169
+ }, usedFormats);
170
+ if (usedFormats.size > 1 && tsConfig.options.enableI18nLegacyMessageIdFormat !== false) {
171
+ // This limitation is only for legacy message id support (defaults to true as of 9.0)
172
+ throw new Error('Localization currently only supports using one type of translation file format for the entire application.');
197
173
  }
198
174
  }
199
175
  // If inlining store the output in a temporary location to facilitate post-processing
@@ -225,3 +201,36 @@ function findLocaleDataPath(locale, resolver) {
225
201
  return null;
226
202
  }
227
203
  }
204
+ function loadTranslations(locale, desc, workspaceRoot, loader, logger, usedFormats) {
205
+ for (const file of desc.files) {
206
+ const loadResult = loader(path_1.default.join(workspaceRoot, file.path));
207
+ for (const diagnostics of loadResult.diagnostics.messages) {
208
+ if (diagnostics.type === 'error') {
209
+ logger.error(`Error parsing translation file '${file.path}': ${diagnostics.message}`);
210
+ }
211
+ else {
212
+ logger.warn(`WARNING [${file.path}]: ${diagnostics.message}`);
213
+ }
214
+ }
215
+ if (loadResult.locale !== undefined && loadResult.locale !== locale) {
216
+ logger.warn(`WARNING [${file.path}]: File target locale ('${loadResult.locale}') does not match configured locale ('${locale}')`);
217
+ }
218
+ usedFormats === null || usedFormats === void 0 ? void 0 : usedFormats.add(loadResult.format);
219
+ file.format = loadResult.format;
220
+ file.integrity = loadResult.integrity;
221
+ if (desc.translation) {
222
+ // Merge translations
223
+ for (const [id, message] of Object.entries(loadResult.translations)) {
224
+ if (desc.translation[id] !== undefined) {
225
+ logger.warn(`WARNING [${file.path}]: Duplicate translations for message '${id}' when merging`);
226
+ }
227
+ desc.translation[id] = message;
228
+ }
229
+ }
230
+ else {
231
+ // First or only translation file
232
+ desc.translation = loadResult.translations;
233
+ }
234
+ }
235
+ }
236
+ exports.loadTranslations = loadTranslations;
@@ -27,4 +27,8 @@ export interface FileInfo {
27
27
  name: string;
28
28
  extension: string;
29
29
  }
30
- export declare function augmentIndexHtml(params: AugmentIndexHtmlOptions): Promise<string>;
30
+ export declare function augmentIndexHtml(params: AugmentIndexHtmlOptions): Promise<{
31
+ content: string;
32
+ warnings: string[];
33
+ errors: string[];
34
+ }>;
@@ -9,6 +9,7 @@
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.augmentIndexHtml = void 0;
11
11
  const crypto_1 = require("crypto");
12
+ const load_esm_1 = require("../load-esm");
12
13
  const html_rewriting_stream_1 = require("./html-rewriting-stream");
13
14
  /*
14
15
  * Helper function used by the IndexHtmlWebpackPlugin.
@@ -18,6 +19,8 @@ const html_rewriting_stream_1 = require("./html-rewriting-stream");
18
19
  */
19
20
  async function augmentIndexHtml(params) {
20
21
  const { loadOutputFile, files, entrypoints, sri, deployUrl = '', lang, baseHref, html } = params;
22
+ const warnings = [];
23
+ const errors = [];
21
24
  let { crossOrigin = 'none' } = params;
22
25
  if (sri && crossOrigin === 'none') {
23
26
  crossOrigin = 'anonymous';
@@ -72,6 +75,7 @@ async function augmentIndexHtml(params) {
72
75
  }
73
76
  linkTags.push(`<link ${attrs.join(' ')}>`);
74
77
  }
78
+ const dir = lang ? await getLanguageDirection(lang, warnings) : undefined;
75
79
  const { rewriter, transformedContent } = await (0, html_rewriting_stream_1.htmlRewritingStream)(html);
76
80
  const baseTagExists = html.includes('<base');
77
81
  rewriter
@@ -82,6 +86,9 @@ async function augmentIndexHtml(params) {
82
86
  if (isString(lang)) {
83
87
  updateAttribute(tag, 'lang', lang);
84
88
  }
89
+ if (dir) {
90
+ updateAttribute(tag, 'dir', dir);
91
+ }
85
92
  break;
86
93
  case 'head':
87
94
  // Base href should be added before any link, meta tags
@@ -119,11 +126,14 @@ async function augmentIndexHtml(params) {
119
126
  rewriter.emitEndTag(tag);
120
127
  });
121
128
  const content = await transformedContent;
122
- if (linkTags.length || scriptTags.length) {
123
- // In case no body/head tags are not present (dotnet partial templates)
124
- return linkTags.join('') + scriptTags.join('') + content;
125
- }
126
- return content;
129
+ return {
130
+ content: linkTags.length || scriptTags.length
131
+ ? // In case no body/head tags are not present (dotnet partial templates)
132
+ linkTags.join('') + scriptTags.join('') + content
133
+ : content,
134
+ warnings,
135
+ errors,
136
+ };
127
137
  }
128
138
  exports.augmentIndexHtml = augmentIndexHtml;
129
139
  function generateSriAttributes(content) {
@@ -144,3 +154,26 @@ function updateAttribute(tag, name, value) {
144
154
  function isString(value) {
145
155
  return typeof value === 'string';
146
156
  }
157
+ async function getLanguageDirection(locale, warnings) {
158
+ const dir = await getLanguageDirectionFromLocales(locale);
159
+ if (!dir) {
160
+ warnings.push(`Locale data for '${locale}' cannot be found. 'dir' attribute will not be set for this locale.`);
161
+ }
162
+ return dir;
163
+ }
164
+ async function getLanguageDirectionFromLocales(locale) {
165
+ try {
166
+ const localeData = (await (0, load_esm_1.loadEsmModule)(`@angular/common/locales/${locale}`)).default;
167
+ const dir = localeData[localeData.length - 2];
168
+ return isString(dir) ? dir : undefined;
169
+ }
170
+ catch {
171
+ // In some cases certain locales might map to files which are named only with language id.
172
+ // Example: `en-US` -> `en`.
173
+ const [languageId] = locale.split('-', 1);
174
+ if (languageId !== locale) {
175
+ return getLanguageDirectionFromLocales(languageId);
176
+ }
177
+ }
178
+ return undefined;
179
+ }
@@ -5,7 +5,6 @@
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';
9
8
  export * from './default-progress';
10
9
  export * from './delete-output-dir';
11
10
  export * from './run-module-as-observable-fork';
@@ -17,7 +17,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
17
17
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- __exportStar(require("./build-browser-features"), exports);
21
20
  __exportStar(require("./default-progress"), exports);
22
21
  __exportStar(require("./delete-output-dir"), exports);
23
22
  __exportStar(require("./run-module-as-observable-fork"), exports);
@@ -14,6 +14,7 @@ const normalize_cache_1 = require("./normalize-cache");
14
14
  const normalize_file_replacements_1 = require("./normalize-file-replacements");
15
15
  const normalize_optimization_1 = require("./normalize-optimization");
16
16
  const normalize_source_maps_1 = require("./normalize-source-maps");
17
+ const supported_browsers_1 = require("./supported-browsers");
17
18
  function normalizeBrowserSchema(root, projectRoot, sourceRoot, options, metadata) {
18
19
  const normalizedSourceMapOptions = (0, normalize_source_maps_1.normalizeSourceMaps)(options.sourceMap || false);
19
20
  return {
@@ -37,6 +38,7 @@ function normalizeBrowserSchema(root, projectRoot, sourceRoot, options, metadata
37
38
  // A value of 0 is falsy and will disable polling rather then enable
38
39
  // 500 ms is a sensible default in this case
39
40
  poll: options.poll === 0 ? 500 : options.poll,
41
+ supportedBrowsers: (0, supported_browsers_1.getSupportedBrowsers)((0, core_1.getSystemPath)(projectRoot)),
40
42
  };
41
43
  }
42
44
  exports.normalizeBrowserSchema = normalizeBrowserSchema;
@@ -41,10 +41,7 @@ async function readTsconfig(tsconfigPath, workspaceRoot) {
41
41
  // Load ESM `@angular/compiler-cli` using the TypeScript dynamic import workaround.
42
42
  // Once TypeScript provides support for keeping the dynamic import this workaround can be
43
43
  // changed to a direct dynamic import.
44
- const compilerCliModule = await (0, load_esm_1.loadEsmModule)('@angular/compiler-cli');
45
- // If it is not ESM then the functions needed will be stored in the `default` property.
46
- // TODO_ESM: This can be removed once `@angular/compiler-cli` is ESM only.
47
- const { formatDiagnostics, readConfiguration } = (compilerCliModule.readConfiguration ? compilerCliModule : compilerCliModule.default);
44
+ const { formatDiagnostics, readConfiguration } = await (0, load_esm_1.loadEsmModule)('@angular/compiler-cli');
48
45
  const configResult = readConfiguration(tsConfigFullPath);
49
46
  if (configResult.errors && configResult.errors.length) {
50
47
  throw new Error(formatDiagnostics(configResult.errors));
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google LLC 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
+ export declare function getSupportedBrowsers(projectRoot: string): string[];
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ /**
3
+ * @license
4
+ * Copyright Google LLC 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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
10
+ return (mod && mod.__esModule) ? mod : { "default": mod };
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.getSupportedBrowsers = void 0;
14
+ const browserslist_1 = __importDefault(require("browserslist"));
15
+ function getSupportedBrowsers(projectRoot) {
16
+ browserslist_1.default.defaults = [
17
+ 'last 1 Chrome version',
18
+ 'last 1 Firefox version',
19
+ 'last 2 Edge major versions',
20
+ 'last 2 Safari major versions',
21
+ 'last 2 iOS major versions',
22
+ 'Firefox ESR',
23
+ ];
24
+ return (0, browserslist_1.default)(undefined, { path: projectRoot });
25
+ }
26
+ exports.getSupportedBrowsers = getSupportedBrowsers;
@@ -36,17 +36,18 @@ const path = __importStar(require("path"));
36
36
  const typescript_1 = require("typescript");
37
37
  const webpack_2 = require("webpack");
38
38
  const webpack_subresource_integrity_1 = require("webpack-subresource-integrity");
39
- const utils_1 = require("../../utils");
40
39
  const environment_options_1 = require("../../utils/environment-options");
41
40
  const load_esm_1 = require("../../utils/load-esm");
42
41
  const plugins_1 = require("../plugins");
42
+ const named_chunks_plugin_1 = require("../plugins/named-chunks-plugin");
43
43
  const progress_plugin_1 = require("../plugins/progress-plugin");
44
+ const transfer_size_plugin_1 = require("../plugins/transfer-size-plugin");
44
45
  const typescript_2 = require("../plugins/typescript");
45
46
  const helpers_1 = require("../utils/helpers");
46
47
  // eslint-disable-next-line max-lines-per-function
47
48
  async function getCommonConfig(wco) {
48
49
  var _a, _b;
49
- const { root, projectRoot, buildOptions, tsConfig, projectName, sourceRoot, tsConfigPath } = wco;
50
+ const { root, projectRoot, buildOptions, tsConfig, projectName, sourceRoot, tsConfigPath, scriptTarget, } = wco;
50
51
  const { cache, codeCoverage, crossOrigin = 'none', platform = 'browser', aot = true, codeCoverageExclude = [], main, polyfills, sourceMap: { styles: stylesSourceMap, scripts: scriptsSourceMap, vendor: vendorSourceMap, hidden: hiddenSourceMap, }, optimization: { styles: stylesOptimization, scripts: scriptsOptimization }, commonChunk, vendorChunk, subresourceIntegrity, verbose, poll, webWorkerTsConfig, externalDependencies = [], allowedCommonJsDependencies, bundleDependencies, } = buildOptions;
51
52
  const isPlatformServer = buildOptions.platform === 'server';
52
53
  const extraPlugins = [];
@@ -55,13 +56,9 @@ async function getCommonConfig(wco) {
55
56
  // Load ESM `@angular/compiler-cli` using the TypeScript dynamic import workaround.
56
57
  // Once TypeScript provides support for keeping the dynamic import this workaround can be
57
58
  // changed to a direct dynamic import.
58
- const compilerCliModule = await (0, load_esm_1.loadEsmModule)('@angular/compiler-cli');
59
- // If it is not ESM then the values needed will be stored in the `default` property.
60
- // TODO_ESM: This can be removed once `@angular/compiler-cli` is ESM only.
61
- const { GLOBAL_DEFS_FOR_TERSER, GLOBAL_DEFS_FOR_TERSER_WITH_AOT, VERSION: NG_VERSION, } = (compilerCliModule.GLOBAL_DEFS_FOR_TERSER ? compilerCliModule : compilerCliModule.default);
59
+ const { GLOBAL_DEFS_FOR_TERSER, GLOBAL_DEFS_FOR_TERSER_WITH_AOT, VERSION: NG_VERSION, } = await (0, load_esm_1.loadEsmModule)('@angular/compiler-cli');
62
60
  // determine hashing format
63
61
  const hashFormat = (0, helpers_1.getOutputHashFormat)(buildOptions.outputHashing || 'none');
64
- const buildBrowserFeatures = new utils_1.BuildBrowserFeatures(projectRoot);
65
62
  if (buildOptions.progress) {
66
63
  extraPlugins.push(new progress_plugin_1.ProgressPlugin(platform));
67
64
  }
@@ -93,11 +90,6 @@ async function getCommonConfig(wco) {
93
90
  }
94
91
  }
95
92
  }
96
- if (environment_options_1.profilingEnabled) {
97
- extraPlugins.push(new webpack_2.debug.ProfilingPlugin({
98
- outputPath: path.resolve(root, 'chrome-profiler-events.json'),
99
- }));
100
- }
101
93
  if (allowedCommonJsDependencies) {
102
94
  // When this is not defined it means the builder doesn't support showing common js usages.
103
95
  // When it does it will be an array.
@@ -190,8 +182,10 @@ async function getCommonConfig(wco) {
190
182
  }
191
183
  if (main || polyfills) {
192
184
  extraRules.push({
193
- test: /\.[cm]?[tj]sx?$/,
185
+ test: tsConfig.options.allowJs ? /\.[cm]?[tj]sx?$/ : /\.[cm]?tsx?$/,
194
186
  loader: webpack_1.AngularWebpackLoaderPath,
187
+ // The below are known paths that are not part of the TypeScript compilation even when allowJs is enabled.
188
+ exclude: [/[/\\](?:css-loader|mini-css-extract-plugin|webpack-dev-server|webpack)[/\\]/],
195
189
  });
196
190
  extraPlugins.push((0, typescript_2.createIvyPlugin)(wco, aot, tsConfigPath));
197
191
  }
@@ -203,12 +197,15 @@ async function getCommonConfig(wco) {
203
197
  extraMinimizers.push(new plugins_1.JavaScriptOptimizerPlugin({
204
198
  define: buildOptions.aot ? GLOBAL_DEFS_FOR_TERSER_WITH_AOT : GLOBAL_DEFS_FOR_TERSER,
205
199
  sourcemap: scriptsSourceMap,
206
- target: wco.scriptTarget,
200
+ target: scriptTarget,
207
201
  keepNames: !environment_options_1.allowMangle || isPlatformServer,
208
202
  removeLicenses: buildOptions.extractLicenses,
209
203
  advanced: buildOptions.buildOptimizer,
210
204
  }));
211
205
  }
206
+ if (platform === 'browser' && (scriptsOptimization || stylesOptimization.minify)) {
207
+ extraMinimizers.push(new transfer_size_plugin_1.TransferSizePlugin());
208
+ }
212
209
  const externals = [...externalDependencies];
213
210
  if (isPlatformServer && !bundleDependencies) {
214
211
  externals.push(({ context, request }, callback) => (0, helpers_1.externalizePackages)(context !== null && context !== void 0 ? context : wco.projectRoot, request, callback));
@@ -225,7 +222,7 @@ async function getCommonConfig(wco) {
225
222
  devtool: false,
226
223
  target: [
227
224
  isPlatformServer ? 'node' : 'web',
228
- tsConfig.options.target === typescript_1.ScriptTarget.ES5 ? 'es5' : 'es2015',
225
+ scriptTarget === typescript_1.ScriptTarget.ES5 ? 'es5' : 'es2015',
229
226
  ],
230
227
  profile: buildOptions.statsJson,
231
228
  resolve: {
@@ -233,10 +230,7 @@ async function getCommonConfig(wco) {
233
230
  extensions: ['.ts', '.tsx', '.mjs', '.js'],
234
231
  symlinks: !buildOptions.preserveSymlinks,
235
232
  modules: [tsConfig.options.baseUrl || projectRoot, 'node_modules'],
236
- mainFields: isPlatformServer
237
- ? ['es2015', 'module', 'main']
238
- : ['es2020', 'es2015', 'browser', 'module', 'main'],
239
- conditionNames: isPlatformServer ? ['es2015', '...'] : ['es2020', 'es2015', '...'],
233
+ ...(0, helpers_1.getMainFieldsAndConditionNames)(scriptTarget, isPlatformServer),
240
234
  },
241
235
  resolveLoader: {
242
236
  symlinks: !buildOptions.preserveSymlinks,
@@ -260,7 +254,7 @@ async function getCommonConfig(wco) {
260
254
  watch: buildOptions.watch,
261
255
  watchOptions: {
262
256
  poll,
263
- ignored: poll === undefined ? undefined : 'node_modules/**',
257
+ ignored: poll === undefined ? undefined : '**/node_modules/**',
264
258
  },
265
259
  performance: {
266
260
  hints: false,
@@ -270,6 +264,9 @@ async function getCommonConfig(wco) {
270
264
  /Failed to parse source map from/,
271
265
  // https://github.com/webpack-contrib/postcss-loader/blob/bd261875fdf9c596af4ffb3a1a73fe3c549befda/src/index.js#L153-L158
272
266
  /Add postcss as project dependency/,
267
+ // esbuild will issue a warning, while still hoists the @charset at the very top.
268
+ // This is caused by a bug in css-loader https://github.com/webpack-contrib/css-loader/issues/1212
269
+ /"@charset" must be the first rule in the file/,
273
270
  ],
274
271
  module: {
275
272
  // Show an error for missing exports instead of a warning.
@@ -283,6 +280,12 @@ async function getCommonConfig(wco) {
283
280
  }
284
281
  : undefined,
285
282
  rules: [
283
+ {
284
+ test: /\.?(svg|html)$/,
285
+ // Only process HTML and SVG which are known Angular component resources.
286
+ resourceQuery: /\?ngResource/,
287
+ type: 'asset/source',
288
+ },
286
289
  {
287
290
  // Mark files inside `rxjs/add` as containing side effects.
288
291
  // If this is fixed upstream and the fixed version becomes the minimum
@@ -300,7 +303,7 @@ async function getCommonConfig(wco) {
300
303
  loader: require.resolve('../../babel/webpack-loader'),
301
304
  options: {
302
305
  cacheDirectory: (cache.enabled && path.join(cache.path, 'babel-webpack')) || false,
303
- scriptTarget: wco.scriptTarget,
306
+ scriptTarget,
304
307
  aot: buildOptions.aot,
305
308
  optimize: buildOptions.buildOptimizer,
306
309
  instrumentCode: codeCoverage
@@ -317,6 +320,7 @@ async function getCommonConfig(wco) {
317
320
  ],
318
321
  },
319
322
  experiments: {
323
+ backCompat: false,
320
324
  syncWebAssembly: true,
321
325
  asyncWebAssembly: true,
322
326
  },
@@ -324,7 +328,7 @@ async function getCommonConfig(wco) {
324
328
  level: verbose ? 'verbose' : 'error',
325
329
  },
326
330
  stats: (0, helpers_1.getStatsOptions)(verbose),
327
- cache: (0, helpers_1.getCacheSettings)(wco, buildBrowserFeatures.supportedBrowsers, NG_VERSION.full),
331
+ cache: (0, helpers_1.getCacheSettings)(wco, NG_VERSION.full),
328
332
  optimization: {
329
333
  minimizer: extraMinimizers,
330
334
  moduleIds: 'deterministic',
@@ -356,7 +360,7 @@ async function getCommonConfig(wco) {
356
360
  },
357
361
  },
358
362
  },
359
- plugins: [new plugins_1.DedupeModuleResolvePlugin({ verbose }), ...extraPlugins],
363
+ plugins: [new named_chunks_plugin_1.NamedChunksPlugin(), new plugins_1.DedupeModuleResolvePlugin({ verbose }), ...extraPlugins],
360
364
  node: false,
361
365
  };
362
366
  }
@@ -30,7 +30,7 @@ exports.buildServePath = exports.getDevServerConfig = void 0;
30
30
  const core_1 = require("@angular-devkit/core");
31
31
  const fs_1 = require("fs");
32
32
  const path_1 = require("path");
33
- const url = __importStar(require("url"));
33
+ const url_1 = require("url");
34
34
  const load_esm_1 = require("../../utils/load-esm");
35
35
  const webpack_browser_config_1 = require("../../utils/webpack-browser-config");
36
36
  const hmr_loader_1 = require("../plugins/hmr/hmr-loader");
@@ -78,7 +78,7 @@ async function getDevServerConfig(wco) {
78
78
  rewrites: [
79
79
  {
80
80
  from: new RegExp(`^(?!${servePath})/.*`),
81
- to: (context) => url.format(context.parsedUrl),
81
+ to: (context) => context.parsedUrl.href,
82
82
  },
83
83
  ],
84
84
  },
@@ -89,7 +89,7 @@ async function getDevServerConfig(wco) {
89
89
  },
90
90
  compress: false,
91
91
  static: false,
92
- https: getSslConfig(root, wco.buildOptions),
92
+ server: getServerConfig(root, wco.buildOptions),
93
93
  allowedHosts: getAllowedHostsConfig(wco.buildOptions),
94
94
  devMiddleware: {
95
95
  publicPath: servePath,
@@ -139,15 +139,20 @@ exports.buildServePath = buildServePath;
139
139
  * Private method to enhance a webpack config with SSL configuration.
140
140
  * @private
141
141
  */
142
- function getSslConfig(root, options) {
142
+ function getServerConfig(root, options) {
143
143
  const { ssl, sslCert, sslKey } = options;
144
- if (ssl && sslCert && sslKey) {
145
- return {
146
- key: (0, path_1.resolve)(root, sslKey),
147
- cert: (0, path_1.resolve)(root, sslCert),
148
- };
144
+ if (!ssl) {
145
+ return 'http';
149
146
  }
150
- return ssl;
147
+ return {
148
+ type: 'https',
149
+ options: sslCert && sslKey
150
+ ? {
151
+ key: (0, path_1.resolve)(root, sslKey),
152
+ cert: (0, path_1.resolve)(root, sslCert),
153
+ }
154
+ : undefined,
155
+ };
151
156
  }
152
157
  /**
153
158
  * Private method to enhance a webpack config with Proxy configuration.
@@ -158,21 +163,71 @@ async function addProxyConfig(root, proxyConfig) {
158
163
  return undefined;
159
164
  }
160
165
  const proxyPath = (0, path_1.resolve)(root, proxyConfig);
161
- if ((0, fs_1.existsSync)(proxyPath)) {
162
- try {
163
- return require(proxyPath);
166
+ if (!(0, fs_1.existsSync)(proxyPath)) {
167
+ throw new Error(`Proxy configuration file ${proxyPath} does not exist.`);
168
+ }
169
+ switch ((0, path_1.extname)(proxyPath)) {
170
+ case '.json': {
171
+ const content = await fs_1.promises.readFile(proxyPath, 'utf-8');
172
+ const { parse, printParseErrorCode } = await Promise.resolve().then(() => __importStar(require('jsonc-parser')));
173
+ const parseErrors = [];
174
+ const proxyConfiguration = parse(content, parseErrors, { allowTrailingComma: true });
175
+ if (parseErrors.length > 0) {
176
+ let errorMessage = `Proxy configuration file ${proxyPath} contains parse errors:`;
177
+ for (const parseError of parseErrors) {
178
+ const { line, column } = getJsonErrorLineColumn(parseError.offset, content);
179
+ errorMessage += `\n[${line}, ${column}] ${printParseErrorCode(parseError.error)}`;
180
+ }
181
+ throw new Error(errorMessage);
182
+ }
183
+ return proxyConfiguration;
164
184
  }
165
- catch (e) {
166
- if (e.code === 'ERR_REQUIRE_ESM') {
167
- // Load the ESM configuration file using the TypeScript dynamic import workaround.
168
- // Once TypeScript provides support for keeping the dynamic import this workaround can be
169
- // changed to a direct dynamic import.
170
- return (await (0, load_esm_1.loadEsmModule)(url.pathToFileURL(proxyPath))).default;
185
+ case '.mjs':
186
+ // Load the ESM configuration file using the TypeScript dynamic import workaround.
187
+ // Once TypeScript provides support for keeping the dynamic import this workaround can be
188
+ // changed to a direct dynamic import.
189
+ return (await (0, load_esm_1.loadEsmModule)((0, url_1.pathToFileURL)(proxyPath))).default;
190
+ case '.cjs':
191
+ return require(proxyPath);
192
+ default:
193
+ // The file could be either CommonJS or ESM.
194
+ // CommonJS is tried first then ESM if loading fails.
195
+ try {
196
+ return require(proxyPath);
171
197
  }
172
- throw e;
198
+ catch (e) {
199
+ if (e.code === 'ERR_REQUIRE_ESM') {
200
+ // Load the ESM configuration file using the TypeScript dynamic import workaround.
201
+ // Once TypeScript provides support for keeping the dynamic import this workaround can be
202
+ // changed to a direct dynamic import.
203
+ return (await (0, load_esm_1.loadEsmModule)((0, url_1.pathToFileURL)(proxyPath))).default;
204
+ }
205
+ throw e;
206
+ }
207
+ }
208
+ }
209
+ /**
210
+ * Calculates the line and column for an error offset in the content of a JSON file.
211
+ * @param location The offset error location from the beginning of the content.
212
+ * @param content The full content of the file containing the error.
213
+ * @returns An object containing the line and column
214
+ */
215
+ function getJsonErrorLineColumn(offset, content) {
216
+ if (offset === 0) {
217
+ return { line: 1, column: 1 };
218
+ }
219
+ let line = 0;
220
+ let position = 0;
221
+ // eslint-disable-next-line no-constant-condition
222
+ while (true) {
223
+ ++line;
224
+ const nextNewline = content.indexOf('\n', position);
225
+ if (nextNewline === -1 || nextNewline > offset) {
226
+ break;
173
227
  }
228
+ position = nextNewline + 1;
174
229
  }
175
- throw new Error('Proxy config file ' + proxyPath + ' does not exist.');
230
+ return { line, column: offset - position + 1 };
176
231
  }
177
232
  /**
178
233
  * Find the default server path. We don't want to expose baseHref and deployUrl as arguments, only
@@ -219,10 +274,8 @@ function getAllowedHostsConfig(options) {
219
274
  function getPublicHostOptions(options, webSocketPath) {
220
275
  let publicHost = options.publicHost;
221
276
  if (publicHost) {
222
- if (!/^\w+:\/\//.test(publicHost)) {
223
- publicHost = `https://${publicHost}`;
224
- }
225
- publicHost = url.parse(publicHost).host;
277
+ const hostWithProtocol = !/^\w+:\/\//.test(publicHost) ? `https://${publicHost}` : publicHost;
278
+ publicHost = new url_1.URL(hostWithProtocol).host;
226
279
  }
227
280
  return `auto://${publicHost || '0.0.0.0:0'}${webSocketPath}`;
228
281
  }