@angular-devkit/build-angular 15.0.0-next.2 → 15.0.0-next.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 (57) hide show
  1. package/package.json +16 -15
  2. package/src/builders/app-shell/index.js +16 -8
  3. package/src/builders/browser/schema.d.ts +6 -2
  4. package/src/builders/browser/schema.json +16 -2
  5. package/src/builders/browser-esbuild/compiler-plugin.d.ts +9 -2
  6. package/src/builders/browser-esbuild/compiler-plugin.js +114 -90
  7. package/src/builders/browser-esbuild/esbuild.d.ts +4 -3
  8. package/src/builders/browser-esbuild/esbuild.js +12 -6
  9. package/src/builders/browser-esbuild/experimental-warnings.js +0 -3
  10. package/src/builders/browser-esbuild/index.d.ts +3 -3
  11. package/src/builders/browser-esbuild/index.js +143 -86
  12. package/src/builders/browser-esbuild/options.d.ts +26 -4
  13. package/src/builders/browser-esbuild/options.js +62 -6
  14. package/src/builders/browser-esbuild/schema.d.ts +6 -2
  15. package/src/builders/browser-esbuild/schema.json +16 -2
  16. package/src/builders/browser-esbuild/watcher.d.ts +23 -0
  17. package/src/builders/browser-esbuild/watcher.js +93 -0
  18. package/src/builders/karma/find-tests-plugin.d.ts +19 -0
  19. package/src/builders/karma/{find-tests.js → find-tests-plugin.js} +49 -5
  20. package/src/builders/karma/index.d.ts +1 -1
  21. package/src/builders/karma/index.js +86 -43
  22. package/src/builders/karma/schema.d.ts +8 -4
  23. package/src/builders/karma/schema.json +18 -3
  24. package/src/builders/server/schema.d.ts +0 -5
  25. package/src/builders/server/schema.json +0 -5
  26. package/src/sass/sass-service-legacy.d.ts +51 -0
  27. package/src/sass/sass-service-legacy.js +175 -0
  28. package/src/sass/sass-service.d.ts +6 -9
  29. package/src/sass/sass-service.js +69 -52
  30. package/src/{builders/karma/find-tests.d.ts → sass/worker-legacy.d.ts} +1 -1
  31. package/src/sass/worker-legacy.js +44 -0
  32. package/src/sass/worker.js +64 -14
  33. package/src/utils/build-options.d.ts +1 -2
  34. package/src/utils/environment-options.d.ts +1 -0
  35. package/src/utils/environment-options.js +11 -1
  36. package/src/utils/normalize-builder-schema.d.ts +1 -0
  37. package/src/utils/normalize-builder-schema.js +3 -2
  38. package/src/utils/normalize-polyfills.d.ts +8 -0
  39. package/src/utils/normalize-polyfills.js +24 -0
  40. package/src/utils/process-bundle.js +1 -1
  41. package/src/utils/service-worker.d.ts +3 -0
  42. package/src/utils/service-worker.js +29 -2
  43. package/src/utils/webpack-diagnostics.d.ts +1 -1
  44. package/src/utils/webpack-diagnostics.js +2 -3
  45. package/src/webpack/configs/common.js +29 -14
  46. package/src/webpack/configs/styles.d.ts +1 -7
  47. package/src/webpack/configs/styles.js +102 -106
  48. package/src/webpack/plugins/javascript-optimizer-plugin.js +2 -2
  49. package/src/webpack/plugins/karma/karma.js +4 -5
  50. package/src/webpack/plugins/scripts-webpack-plugin.js +24 -5
  51. package/src/webpack/plugins/styles-webpack-plugin.d.ts +19 -0
  52. package/src/webpack/plugins/styles-webpack-plugin.js +71 -0
  53. package/src/webpack/plugins/transfer-size-plugin.js +2 -1
  54. package/src/webpack/utils/helpers.d.ts +5 -2
  55. package/src/webpack/utils/helpers.js +24 -33
  56. package/src/webpack/plugins/single-test-transform.d.ts +0 -27
  57. package/src/webpack/plugins/single-test-transform.js +0 -44
@@ -0,0 +1,24 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.normalizePolyfills = void 0;
11
+ const fs_1 = require("fs");
12
+ const path_1 = require("path");
13
+ function normalizePolyfills(polyfills, root) {
14
+ if (!polyfills) {
15
+ return [];
16
+ }
17
+ const polyfillsList = Array.isArray(polyfills) ? polyfills : [polyfills];
18
+ return polyfillsList.map((p) => {
19
+ const resolvedPath = (0, path_1.resolve)(root, p);
20
+ // If file doesn't exist, let the bundle resolve it using node module resolution.
21
+ return (0, fs_1.existsSync)(resolvedPath) ? resolvedPath : p;
22
+ });
23
+ }
24
+ exports.normalizePolyfills = normalizePolyfills;
@@ -115,7 +115,7 @@ async function inlineLocales(options) {
115
115
  ast = (0, core_1.parseSync)(options.code, {
116
116
  babelrc: false,
117
117
  configFile: false,
118
- sourceType: 'script',
118
+ sourceType: 'unambiguous',
119
119
  filename: options.filename,
120
120
  });
121
121
  }
@@ -6,5 +6,8 @@
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
8
  /// <reference types="node" />
9
+ import type { Config } from '@angular/service-worker/config';
9
10
  import { promises as fsPromises } from 'fs';
10
11
  export declare function augmentAppWithServiceWorker(appRoot: string, workspaceRoot: string, outputPath: string, baseHref: string, ngswConfigPath?: string, inputputFileSystem?: typeof fsPromises, outputFileSystem?: typeof fsPromises): Promise<void>;
12
+ export declare function augmentAppWithServiceWorkerEsbuild(workspaceRoot: string, configPath: string, outputPath: string, baseHref: string): Promise<void>;
13
+ export declare function augmentAppWithServiceWorkerCore(config: Config, outputPath: string, baseHref: string, inputputFileSystem?: typeof fsPromises, outputFileSystem?: typeof fsPromises): Promise<void>;
@@ -30,7 +30,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
30
30
  return result;
31
31
  };
32
32
  Object.defineProperty(exports, "__esModule", { value: true });
33
- exports.augmentAppWithServiceWorker = void 0;
33
+ exports.augmentAppWithServiceWorkerCore = exports.augmentAppWithServiceWorkerEsbuild = exports.augmentAppWithServiceWorker = void 0;
34
34
  const crypto = __importStar(require("crypto"));
35
35
  const fs_1 = require("fs");
36
36
  const path = __importStar(require("path"));
@@ -100,6 +100,33 @@ async function augmentAppWithServiceWorker(appRoot, workspaceRoot, outputPath, b
100
100
  throw error;
101
101
  }
102
102
  }
103
+ return augmentAppWithServiceWorkerCore(config, outputPath, baseHref, inputputFileSystem, outputFileSystem);
104
+ }
105
+ exports.augmentAppWithServiceWorker = augmentAppWithServiceWorker;
106
+ // This is currently used by the esbuild-based builder
107
+ async function augmentAppWithServiceWorkerEsbuild(workspaceRoot, configPath, outputPath, baseHref) {
108
+ // Read the configuration file
109
+ let config;
110
+ try {
111
+ const configurationData = await fs_1.promises.readFile(configPath, 'utf-8');
112
+ config = JSON.parse(configurationData);
113
+ }
114
+ catch (error) {
115
+ (0, error_1.assertIsError)(error);
116
+ if (error.code === 'ENOENT') {
117
+ // TODO: Generate an error object that can be consumed by the esbuild-based builder
118
+ const message = `Service worker configuration file "${path.relative(workspaceRoot, configPath)}" could not be found.`;
119
+ throw new Error(message);
120
+ }
121
+ else {
122
+ throw error;
123
+ }
124
+ }
125
+ // TODO: Return the output files and any errors/warnings
126
+ return augmentAppWithServiceWorkerCore(config, outputPath, baseHref);
127
+ }
128
+ exports.augmentAppWithServiceWorkerEsbuild = augmentAppWithServiceWorkerEsbuild;
129
+ async function augmentAppWithServiceWorkerCore(config, outputPath, baseHref, inputputFileSystem = fs_1.promises, outputFileSystem = fs_1.promises) {
103
130
  // Load ESM `@angular/service-worker/config` using the TypeScript dynamic import workaround.
104
131
  // Once TypeScript provides support for keeping the dynamic import this workaround can be
105
132
  // changed to a direct dynamic import.
@@ -135,4 +162,4 @@ async function augmentAppWithServiceWorker(appRoot, workspaceRoot, outputPath, b
135
162
  }
136
163
  }
137
164
  }
138
- exports.augmentAppWithServiceWorker = augmentAppWithServiceWorker;
165
+ exports.augmentAppWithServiceWorkerCore = augmentAppWithServiceWorkerCore;
@@ -5,6 +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
- import { Compilation } from 'webpack';
8
+ import type { Compilation } from 'webpack';
9
9
  export declare function addWarning(compilation: Compilation, message: string): void;
10
10
  export declare function addError(compilation: Compilation, message: string): void;
@@ -8,12 +8,11 @@
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.addError = exports.addWarning = void 0;
11
- const webpack_1 = require("webpack");
12
11
  function addWarning(compilation, message) {
13
- compilation.warnings.push(new webpack_1.WebpackError(message));
12
+ compilation.warnings.push(new compilation.compiler.webpack.WebpackError(message));
14
13
  }
15
14
  exports.addWarning = addWarning;
16
15
  function addError(compilation, message) {
17
- compilation.errors.push(new webpack_1.WebpackError(message));
16
+ compilation.errors.push(new compilation.compiler.webpack.WebpackError(message));
18
17
  }
19
18
  exports.addError = addError;
@@ -54,7 +54,7 @@ const VENDORS_TEST = /[\\/]node_modules[\\/]/;
54
54
  async function getCommonConfig(wco) {
55
55
  var _a, _b;
56
56
  const { root, projectRoot, buildOptions, tsConfig, projectName, sourceRoot, tsConfigPath } = wco;
57
- 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;
57
+ 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, } = buildOptions;
58
58
  const isPlatformServer = buildOptions.platform === 'server';
59
59
  const extraPlugins = [];
60
60
  const extraRules = [];
@@ -76,14 +76,32 @@ async function getCommonConfig(wco) {
76
76
  // Fixes Critical dependency: the request of a dependency is an expression
77
77
  extraPlugins.push(new webpack_2.ContextReplacementPlugin(/@?hapi|express[\\/]/));
78
78
  }
79
- if (!isPlatformServer) {
80
- if (buildOptions.polyfills) {
81
- const projectPolyfills = path.resolve(root, buildOptions.polyfills);
82
- if (entryPoints['polyfills']) {
83
- entryPoints['polyfills'].push(projectPolyfills);
79
+ if (polyfills === null || polyfills === void 0 ? void 0 : polyfills.length) {
80
+ // `zone.js/testing` is a **special** polyfill because when not imported in the main it fails with the below errors:
81
+ // `Error: Expected to be running in 'ProxyZone', but it was not found.`
82
+ // This was also the reason why previously it was imported in `test.ts` as the first module.
83
+ // From Jia li:
84
+ // This is because the jasmine functions such as beforeEach/it will not be patched by zone.js since
85
+ // jasmine will not be loaded yet, so the ProxyZone will not be there. We have to load zone-testing.js after
86
+ // jasmine is ready.
87
+ // We could force loading 'zone.js/testing' prior to jasmine by changing the order of scripts in 'karma-context.html'.
88
+ // But this has it's own problems as zone.js needs to be loaded prior to jasmine due to patching of timing functions
89
+ // See: https://github.com/jasmine/jasmine/issues/1944
90
+ // Thus the correct order is zone.js -> jasmine -> zone.js/testing.
91
+ const zoneTestingEntryPoint = 'zone.js/testing';
92
+ const polyfillsExludingZoneTesting = polyfills.filter((p) => p !== zoneTestingEntryPoint);
93
+ if (Array.isArray(entryPoints['polyfills'])) {
94
+ entryPoints['polyfills'].push(...polyfillsExludingZoneTesting);
95
+ }
96
+ else {
97
+ entryPoints['polyfills'] = polyfillsExludingZoneTesting;
98
+ }
99
+ if (polyfillsExludingZoneTesting.length !== polyfills.length) {
100
+ if (Array.isArray(entryPoints['main'])) {
101
+ entryPoints['main'].unshift(zoneTestingEntryPoint);
84
102
  }
85
103
  else {
86
- entryPoints['polyfills'] = [projectPolyfills];
104
+ entryPoints['main'] = [zoneTestingEntryPoint];
87
105
  }
88
106
  }
89
107
  }
@@ -96,7 +114,7 @@ async function getCommonConfig(wco) {
96
114
  }
97
115
  // process global scripts
98
116
  // Add a new asset for each entry.
99
- for (const { bundleName, inject, paths } of (0, helpers_1.globalScriptsByBundleName)(root, buildOptions.scripts)) {
117
+ for (const { bundleName, inject, paths } of (0, helpers_1.globalScriptsByBundleName)(buildOptions.scripts)) {
100
118
  // Lazy scripts don't get a hash, otherwise they can't be loaded by name.
101
119
  const hash = inject ? hashFormat.script : '';
102
120
  extraPlugins.push(new plugins_1.ScriptsWebpackPlugin({
@@ -104,7 +122,7 @@ async function getCommonConfig(wco) {
104
122
  sourceMap: scriptsSourceMap,
105
123
  scripts: paths,
106
124
  filename: `${path.basename(bundleName)}${hash}.js`,
107
- basePath: projectRoot,
125
+ basePath: root,
108
126
  }));
109
127
  }
110
128
  // process asset entries
@@ -204,10 +222,6 @@ async function getCommonConfig(wco) {
204
222
  if (platform === 'browser' && (scriptsOptimization || stylesOptimization.minify)) {
205
223
  extraMinimizers.push(new transfer_size_plugin_1.TransferSizePlugin());
206
224
  }
207
- const externals = [...externalDependencies];
208
- if (isPlatformServer && !bundleDependencies) {
209
- externals.push(({ context, request }, callback) => (0, helpers_1.externalizePackages)(context !== null && context !== void 0 ? context : wco.projectRoot, request, callback));
210
- }
211
225
  let crossOriginLoading = false;
212
226
  if (subresourceIntegrity && crossOrigin === 'none') {
213
227
  crossOriginLoading = 'anonymous';
@@ -235,7 +249,7 @@ async function getCommonConfig(wco) {
235
249
  },
236
250
  context: root,
237
251
  entry: entryPoints,
238
- externals,
252
+ externals: externalDependencies,
239
253
  output: {
240
254
  uniqueName: projectName,
241
255
  hashFunction: 'xxhash64',
@@ -280,6 +294,7 @@ async function getCommonConfig(wco) {
280
294
  strictExportPresence: true,
281
295
  parser: {
282
296
  javascript: {
297
+ requireContext: false,
283
298
  // Disable auto URL asset module creation. This doesn't effect `new Worker(new URL(...))`
284
299
  // https://webpack.js.org/guides/asset-modules/#url-assets
285
300
  url: false,
@@ -5,12 +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
- import { Configuration } from 'webpack';
9
- import { StyleElement } from '../../builders/browser/schema';
8
+ import type { Configuration } from 'webpack';
10
9
  import { WebpackConfigOptions } from '../../utils/build-options';
11
- export declare function resolveGlobalStyles(styleEntrypoints: StyleElement[], root: string, preserveSymlinks: boolean, skipResolution?: boolean): {
12
- entryPoints: Record<string, string[]>;
13
- noInjectNames: string[];
14
- paths: string[];
15
- };
16
10
  export declare function getStylesConfig(wco: WebpackConfigOptions): Configuration;
@@ -33,57 +33,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
33
33
  return (mod && mod.__esModule) ? mod : { "default": mod };
34
34
  };
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.getStylesConfig = exports.resolveGlobalStyles = void 0;
36
+ exports.getStylesConfig = void 0;
37
37
  const fs = __importStar(require("fs"));
38
38
  const mini_css_extract_plugin_1 = __importDefault(require("mini-css-extract-plugin"));
39
39
  const path = __importStar(require("path"));
40
- const webpack_1 = require("webpack");
40
+ const url_1 = require("url");
41
41
  const sass_service_1 = require("../../sass/sass-service");
42
+ const sass_service_legacy_1 = require("../../sass/sass-service-legacy");
43
+ const environment_options_1 = require("../../utils/environment-options");
42
44
  const plugins_1 = require("../plugins");
43
45
  const css_optimizer_plugin_1 = require("../plugins/css-optimizer-plugin");
46
+ const styles_webpack_plugin_1 = require("../plugins/styles-webpack-plugin");
44
47
  const helpers_1 = require("../utils/helpers");
45
- function resolveGlobalStyles(styleEntrypoints, root, preserveSymlinks, skipResolution = false) {
46
- const entryPoints = {};
47
- const noInjectNames = [];
48
- const paths = [];
49
- if (styleEntrypoints.length === 0) {
50
- return { entryPoints, noInjectNames, paths };
51
- }
52
- for (const style of (0, helpers_1.normalizeExtraEntryPoints)(styleEntrypoints, 'styles')) {
53
- let stylesheetPath = style.input;
54
- if (!skipResolution) {
55
- stylesheetPath = path.resolve(root, stylesheetPath);
56
- if (!fs.existsSync(stylesheetPath)) {
57
- try {
58
- stylesheetPath = require.resolve(style.input, { paths: [root] });
59
- }
60
- catch { }
61
- }
62
- }
63
- if (!preserveSymlinks) {
64
- stylesheetPath = fs.realpathSync(stylesheetPath);
65
- }
66
- // Add style entry points.
67
- if (entryPoints[style.bundleName]) {
68
- entryPoints[style.bundleName].push(stylesheetPath);
69
- }
70
- else {
71
- entryPoints[style.bundleName] = [stylesheetPath];
72
- }
73
- // Add non injected styles to the list.
74
- if (!style.inject) {
75
- noInjectNames.push(style.bundleName);
76
- }
77
- // Add global css paths.
78
- paths.push(stylesheetPath);
79
- }
80
- return { entryPoints, noInjectNames, paths };
81
- }
82
- exports.resolveGlobalStyles = resolveGlobalStyles;
83
48
  // eslint-disable-next-line max-lines-per-function
84
49
  function getStylesConfig(wco) {
85
50
  var _a, _b, _c;
86
- const { root, buildOptions } = wco;
51
+ const { root, projectRoot, buildOptions } = wco;
87
52
  const extraPlugins = [];
88
53
  extraPlugins.push(new plugins_1.AnyComponentStyleBudgetChecker(buildOptions.budgets));
89
54
  const cssSourceMap = buildOptions.sourceMap.styles;
@@ -92,24 +57,26 @@ function getStylesConfig(wco) {
92
57
  // use includePaths from appConfig
93
58
  const includePaths = (_c = (_b = (_a = buildOptions.stylePreprocessorOptions) === null || _a === void 0 ? void 0 : _a.includePaths) === null || _b === void 0 ? void 0 : _b.map((p) => path.resolve(root, p))) !== null && _c !== void 0 ? _c : [];
94
59
  // Process global styles.
95
- const { entryPoints, noInjectNames, paths: globalStylePaths, } = resolveGlobalStyles(buildOptions.styles, root, !!buildOptions.preserveSymlinks);
96
- if (noInjectNames.length > 0) {
97
- // Add plugin to remove hashes from lazy styles.
98
- extraPlugins.push(new plugins_1.RemoveHashPlugin({ chunkNames: noInjectNames, hashFormat }));
60
+ if (buildOptions.styles.length > 0) {
61
+ const { entryPoints, noInjectNames } = (0, helpers_1.normalizeGlobalStyles)(buildOptions.styles);
62
+ extraPlugins.push(new styles_webpack_plugin_1.StylesWebpackPlugin({
63
+ root,
64
+ entryPoints,
65
+ preserveSymlinks: buildOptions.preserveSymlinks,
66
+ }));
67
+ if (noInjectNames.length > 0) {
68
+ // Add plugin to remove hashes from lazy styles.
69
+ extraPlugins.push(new plugins_1.RemoveHashPlugin({ chunkNames: noInjectNames, hashFormat }));
70
+ }
99
71
  }
100
- const sassImplementation = new sass_service_1.SassWorkerImplementation();
101
- const sassTildeUsageMessage = new Set();
72
+ const sassImplementation = environment_options_1.useLegacySass
73
+ ? new sass_service_legacy_1.SassLegacyWorkerImplementation()
74
+ : new sass_service_1.SassWorkerImplementation();
102
75
  extraPlugins.push({
103
76
  apply(compiler) {
104
77
  compiler.hooks.shutdown.tap('sass-worker', () => {
105
78
  sassImplementation.close();
106
79
  });
107
- compiler.hooks.afterCompile.tap('sass-worker', (compilation) => {
108
- for (const message of sassTildeUsageMessage) {
109
- compilation.warnings.push(new webpack_1.WebpackError(message));
110
- }
111
- sassTildeUsageMessage.clear();
112
- });
113
80
  },
114
81
  });
115
82
  const assetNameTemplate = (0, helpers_1.assetNameTemplateFactory)(hashFormat);
@@ -147,7 +114,6 @@ function getStylesConfig(wco) {
147
114
  : undefined,
148
115
  plugins: [
149
116
  postcssImports({
150
- resolve: (url) => (url.startsWith('~') ? url.slice(1) : url),
151
117
  load: (filename) => {
152
118
  return new Promise((resolve, reject) => {
153
119
  loader.fs.readFile(filename, (err, data) => {
@@ -243,30 +209,7 @@ function getStylesConfig(wco) {
243
209
  },
244
210
  {
245
211
  loader: require.resolve('sass-loader'),
246
- options: {
247
- implementation: sassImplementation,
248
- sourceMap: true,
249
- sassOptions: {
250
- importer: (url, from) => {
251
- if (url.charAt(0) === '~') {
252
- sassTildeUsageMessage.add(`'${from}' imports '${url}' with a tilde. Usage of '~' in imports is deprecated.`);
253
- }
254
- return null;
255
- },
256
- // Prevent use of `fibers` package as it no longer works in newer Node.js versions
257
- fiber: false,
258
- // bootstrap-sass requires a minimum precision of 8
259
- precision: 8,
260
- includePaths,
261
- // Use expanded as otherwise sass will remove comments that are needed for autoprefixer
262
- // Ex: /* autoprefixer grid: autoplace */
263
- // See: https://github.com/webpack-contrib/sass-loader/blob/45ad0be17264ceada5f0b4fb87e9357abe85c4ff/src/getSassOptions.js#L68-L70
264
- outputStyle: 'expanded',
265
- // Silences compiler warnings from 3rd party stylesheets
266
- quietDeps: !buildOptions.verbose,
267
- verbose: buildOptions.verbose,
268
- },
269
- },
212
+ options: getSassLoaderOptions(root, sassImplementation, includePaths, false, !buildOptions.verbose, !!buildOptions.preserveSymlinks),
270
213
  },
271
214
  ],
272
215
  },
@@ -281,31 +224,7 @@ function getStylesConfig(wco) {
281
224
  },
282
225
  {
283
226
  loader: require.resolve('sass-loader'),
284
- options: {
285
- implementation: sassImplementation,
286
- sourceMap: true,
287
- sassOptions: {
288
- importer: (url, from) => {
289
- if (url.charAt(0) === '~') {
290
- sassTildeUsageMessage.add(`'${from}' imports '${url}' with a tilde. Usage of '~' in imports is deprecated.`);
291
- }
292
- return null;
293
- },
294
- // Prevent use of `fibers` package as it no longer works in newer Node.js versions
295
- fiber: false,
296
- indentedSyntax: true,
297
- // bootstrap-sass requires a minimum precision of 8
298
- precision: 8,
299
- includePaths,
300
- // Use expanded as otherwise sass will remove comments that are needed for autoprefixer
301
- // Ex: /* autoprefixer grid: autoplace */
302
- // See: https://github.com/webpack-contrib/sass-loader/blob/45ad0be17264ceada5f0b4fb87e9357abe85c4ff/src/getSassOptions.js#L68-L70
303
- outputStyle: 'expanded',
304
- // Silences compiler warnings from 3rd party stylesheets
305
- quietDeps: !buildOptions.verbose,
306
- verbose: buildOptions.verbose,
307
- },
308
- },
227
+ options: getSassLoaderOptions(root, sassImplementation, includePaths, true, !buildOptions.verbose, !!buildOptions.preserveSymlinks),
309
228
  },
310
229
  ],
311
230
  },
@@ -327,7 +246,6 @@ function getStylesConfig(wco) {
327
246
  },
328
247
  ];
329
248
  return {
330
- entry: entryPoints,
331
249
  module: {
332
250
  rules: styleLanguages.map(({ extensions, use }) => ({
333
251
  test: new RegExp(`\\.(?:${extensions.join('|')})$`, 'i'),
@@ -338,8 +256,7 @@ function getStylesConfig(wco) {
338
256
  // Global styles are only defined global styles
339
257
  {
340
258
  use: globalStyleLoaders,
341
- include: globalStylePaths,
342
- resourceQuery: { not: [/\?ngResource/] },
259
+ resourceQuery: /\?ngGlobalStyle/,
343
260
  },
344
261
  // Component styles are all styles except defined global styles
345
262
  {
@@ -382,3 +299,82 @@ function getTailwindConfigPath({ projectRoot, root }) {
382
299
  }
383
300
  return undefined;
384
301
  }
302
+ function getSassLoaderOptions(root, implementation, includePaths, indentedSyntax, verbose, preserveSymlinks) {
303
+ return implementation instanceof sass_service_1.SassWorkerImplementation
304
+ ? {
305
+ sourceMap: true,
306
+ api: 'modern',
307
+ implementation,
308
+ // Webpack importer is only implemented in the legacy API and we have our own custom Webpack importer.
309
+ // See: https://github.com/webpack-contrib/sass-loader/blob/997f3eb41d86dd00d5fa49c395a1aeb41573108c/src/utils.js#L642-L651
310
+ webpackImporter: false,
311
+ sassOptions: (loaderContext) => ({
312
+ importers: [getSassResolutionImporter(loaderContext, root, preserveSymlinks)],
313
+ loadPaths: includePaths,
314
+ // Use expanded as otherwise sass will remove comments that are needed for autoprefixer
315
+ // Ex: /* autoprefixer grid: autoplace */
316
+ // See: https://github.com/webpack-contrib/sass-loader/blob/45ad0be17264ceada5f0b4fb87e9357abe85c4ff/src/getSassOptions.js#L68-L70
317
+ style: 'expanded',
318
+ // Silences compiler warnings from 3rd party stylesheets
319
+ quietDeps: !verbose,
320
+ verbose,
321
+ syntax: indentedSyntax ? 'indented' : 'scss',
322
+ }),
323
+ }
324
+ : {
325
+ sourceMap: true,
326
+ api: 'legacy',
327
+ implementation,
328
+ sassOptions: {
329
+ importer: (url, from) => {
330
+ if (url.charAt(0) === '~') {
331
+ throw new Error(`'${from}' imports '${url}' with a tilde. Usage of '~' in imports is no longer supported.`);
332
+ }
333
+ return null;
334
+ },
335
+ // Prevent use of `fibers` package as it no longer works in newer Node.js versions
336
+ fiber: false,
337
+ indentedSyntax,
338
+ // bootstrap-sass requires a minimum precision of 8
339
+ precision: 8,
340
+ includePaths,
341
+ // Use expanded as otherwise sass will remove comments that are needed for autoprefixer
342
+ // Ex: /* autoprefixer grid: autoplace */
343
+ // See: https://github.com/webpack-contrib/sass-loader/blob/45ad0be17264ceada5f0b4fb87e9357abe85c4ff/src/getSassOptions.js#L68-L70
344
+ outputStyle: 'expanded',
345
+ // Silences compiler warnings from 3rd party stylesheets
346
+ quietDeps: !verbose,
347
+ verbose,
348
+ },
349
+ };
350
+ }
351
+ function getSassResolutionImporter(loaderContext, root, preserveSymlinks) {
352
+ const commonResolverOptions = {
353
+ conditionNames: ['sass', 'style'],
354
+ mainFields: ['sass', 'style', 'main', '...'],
355
+ extensions: ['.scss', '.sass', '.css'],
356
+ restrictions: [/\.((sa|sc|c)ss)$/i],
357
+ preferRelative: true,
358
+ symlinks: !preserveSymlinks,
359
+ };
360
+ // Sass also supports import-only files. If you name a file <name>.import.scss, it will only be loaded for imports, not for @uses.
361
+ // See: https://sass-lang.com/documentation/at-rules/import#import-only-files
362
+ const resolveImport = loaderContext.getResolve({
363
+ ...commonResolverOptions,
364
+ dependencyType: 'sass-import',
365
+ mainFiles: ['_index.import', '_index', 'index.import', 'index', '...'],
366
+ });
367
+ const resolveModule = loaderContext.getResolve({
368
+ ...commonResolverOptions,
369
+ dependencyType: 'sass-module',
370
+ mainFiles: ['_index', 'index', '...'],
371
+ });
372
+ return {
373
+ findFileUrl: (url, { fromImport }) => {
374
+ const resolve = fromImport ? resolveImport : resolveModule;
375
+ return resolve(root, url)
376
+ .then((file) => (0, url_1.pathToFileURL)(file))
377
+ .catch(() => null);
378
+ },
379
+ };
380
+ }
@@ -14,6 +14,7 @@ exports.JavaScriptOptimizerPlugin = void 0;
14
14
  const piscina_1 = __importDefault(require("piscina"));
15
15
  const environment_options_1 = require("../../utils/environment-options");
16
16
  const esbuild_targets_1 = require("../../utils/esbuild-targets");
17
+ const webpack_diagnostics_1 = require("../../utils/webpack-diagnostics");
17
18
  const esbuild_executor_1 = require("./esbuild-executor");
18
19
  /**
19
20
  * The maximum number of Workers that will be created to execute optimize tasks.
@@ -142,8 +143,7 @@ class JavaScriptOptimizerPlugin {
142
143
  source: optimizedAsset,
143
144
  });
144
145
  }, (error) => {
145
- const optimizationError = new compiler.webpack.WebpackError(`Optimization error [${name}]: ${error.stack || error.message}`);
146
- compilation.errors.push(optimizationError);
146
+ (0, webpack_diagnostics_1.addError)(compilation, `Optimization error [${name}]: ${error.stack || error.message}`);
147
147
  }));
148
148
  }
149
149
  await Promise.all(tasks);
@@ -109,7 +109,6 @@ const init = (config, emitter) => {
109
109
  webpackConfig.output.path = `/${KARMA_APPLICATION_PATH}/`;
110
110
  webpackConfig.output.publicPath = `/${KARMA_APPLICATION_PATH}/`;
111
111
  const compiler = (0, webpack_1.default)(webpackConfig, (error, stats) => {
112
- var _a;
113
112
  if (error) {
114
113
  throw error;
115
114
  }
@@ -122,10 +121,10 @@ const init = (config, emitter) => {
122
121
  warnings: true,
123
122
  });
124
123
  logger.error((0, stats_1.statsErrorsToString)(statsJson, { colors: true }));
125
- // Notify potential listeners of the compile error.
126
- emitter.emit('compile_error', {
127
- errors: (_a = statsJson.errors) === null || _a === void 0 ? void 0 : _a.map((e) => e.message),
128
- });
124
+ if (config.singleRun) {
125
+ // Notify potential listeners of the compile error.
126
+ emitter.emit('load_error');
127
+ }
129
128
  // Finish Karma run early in case of compilation error.
130
129
  emitter.emit('run_complete', [], { exitCode: 1 });
131
130
  // Emit a failure build event if there are compilation errors.
@@ -34,6 +34,8 @@ exports.ScriptsWebpackPlugin = void 0;
34
34
  const loader_utils_1 = require("loader-utils");
35
35
  const path = __importStar(require("path"));
36
36
  const webpack_1 = require("webpack");
37
+ const error_1 = require("../../utils/error");
38
+ const webpack_diagnostics_1 = require("../../utils/webpack-diagnostics");
37
39
  const Entrypoint = require('webpack/lib/Entrypoint');
38
40
  /**
39
41
  * The name of the plugin provided to Webpack when tapping Webpack compiler hooks.
@@ -81,18 +83,35 @@ class ScriptsWebpackPlugin {
81
83
  chunk.addGroup(entrypoint);
82
84
  compilation.entrypoints.set(this.options.name, entrypoint);
83
85
  compilation.chunks.add(chunk);
84
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
85
86
  compilation.assets[filename] = source;
86
87
  compilation.hooks.chunkAsset.call(chunk, filename);
87
88
  }
88
89
  apply(compiler) {
89
- if (!this.options.scripts || this.options.scripts.length === 0) {
90
+ if (this.options.scripts.length === 0) {
90
91
  return;
91
92
  }
92
- const scripts = this.options.scripts
93
- .filter((script) => !!script)
94
- .map((script) => path.resolve(this.options.basePath || '', script));
93
+ const resolver = compiler.resolverFactory.get('normal', {
94
+ preferRelative: true,
95
+ useSyncFileSystemCalls: true,
96
+ fileSystem: compiler.inputFileSystem,
97
+ });
95
98
  compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
99
+ const scripts = [];
100
+ for (const script of this.options.scripts) {
101
+ try {
102
+ const resolvedPath = resolver.resolveSync({}, this.options.basePath, script);
103
+ if (resolvedPath) {
104
+ scripts.push(resolvedPath);
105
+ }
106
+ else {
107
+ (0, webpack_diagnostics_1.addError)(compilation, `Cannot resolve '${script}'.`);
108
+ }
109
+ }
110
+ catch (error) {
111
+ (0, error_1.assertIsError)(error);
112
+ (0, webpack_diagnostics_1.addError)(compilation, error.message);
113
+ }
114
+ }
96
115
  compilation.hooks.additionalAssets.tapPromise(PLUGIN_NAME, async () => {
97
116
  if (await this.shouldSkip(compilation, scripts)) {
98
117
  if (this._cachedOutput) {
@@ -0,0 +1,19 @@
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
+ import type { Compiler } from 'webpack';
9
+ export interface StylesWebpackPluginOptions {
10
+ preserveSymlinks?: boolean;
11
+ root: string;
12
+ entryPoints: Record<string, string[]>;
13
+ }
14
+ export declare class StylesWebpackPlugin {
15
+ private readonly options;
16
+ private compilation;
17
+ constructor(options: StylesWebpackPluginOptions);
18
+ apply(compiler: Compiler): void;
19
+ }