@angular/build 19.1.7 → 19.1.9

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular/build",
3
- "version": "19.1.7",
3
+ "version": "19.1.9",
4
4
  "description": "Official build system for Angular",
5
5
  "keywords": [
6
6
  "Angular CLI",
@@ -23,8 +23,8 @@
23
23
  "builders": "builders.json",
24
24
  "dependencies": {
25
25
  "@ampproject/remapping": "2.3.0",
26
- "@angular-devkit/core": "19.1.7",
27
- "@angular-devkit/architect": "0.1901.7",
26
+ "@angular-devkit/core": "19.1.9",
27
+ "@angular-devkit/architect": "0.1901.9",
28
28
  "@babel/core": "7.26.0",
29
29
  "@babel/helper-annotate-as-pure": "7.25.9",
30
30
  "@babel/helper-split-export-declaration": "7.24.7",
@@ -58,7 +58,7 @@
58
58
  "@angular/localize": "^19.0.0",
59
59
  "@angular/platform-server": "^19.0.0",
60
60
  "@angular/service-worker": "^19.0.0",
61
- "@angular/ssr": "^19.1.7",
61
+ "@angular/ssr": "^19.1.9",
62
62
  "less": "^4.2.0",
63
63
  "ng-packagr": "^19.0.0",
64
64
  "postcss": "^8.4.0",
@@ -190,10 +190,6 @@ async function executeBuild(options, context, rebuildState) {
190
190
  if (serverEntryPoint) {
191
191
  executionResult.addOutputFile(manifest_1.SERVER_APP_ENGINE_MANIFEST_FILENAME, (0, manifest_1.generateAngularServerAppEngineManifest)(i18nOptions, baseHref), bundler_context_1.BuildOutputFileType.ServerRoot);
192
192
  }
193
- // Override auto-CSP settings if we are serving through Vite middleware.
194
- if (context.builder.builderName === 'dev-server' && options.security) {
195
- options.security.autoCsp = false;
196
- }
197
193
  // Perform i18n translation inlining if enabled
198
194
  if (i18nOptions.shouldInline) {
199
195
  const result = await (0, i18n_1.inlineI18n)(metafile, options, executionResult, initialFiles);
@@ -196,7 +196,11 @@ export declare function normalizeOptions(context: BuilderContext, projectName: s
196
196
  partialSSRBuild: boolean;
197
197
  externalRuntimeStyles: boolean | undefined;
198
198
  instrumentForCoverage: ((filename: string) => boolean) | undefined;
199
- security: import("./schema").Security | undefined;
199
+ security: {
200
+ autoCsp: {
201
+ unsafeEval: boolean;
202
+ } | undefined;
203
+ };
200
204
  templateUpdates: boolean;
201
205
  incrementalResults: boolean;
202
206
  }>;
@@ -236,8 +236,16 @@ async function normalizeOptions(context, projectName, options, extensions) {
236
236
  throw new Error('The "index" option cannot be set to false when enabling "ssr", "prerender" or "app-shell".');
237
237
  }
238
238
  }
239
+ const autoCsp = options.security?.autoCsp;
240
+ const security = {
241
+ autoCsp: autoCsp
242
+ ? {
243
+ unsafeEval: autoCsp === true ? false : !!autoCsp.unsafeEval,
244
+ }
245
+ : undefined,
246
+ };
239
247
  // Initial options to keep
240
- const { allowedCommonJsDependencies, aot = true, baseHref, crossOrigin, externalDependencies, extractLicenses, inlineStyleLanguage = 'css', outExtension, serviceWorker, poll, polyfills, statsJson, outputMode, stylePreprocessorOptions, subresourceIntegrity, verbose, watch, progress = true, externalPackages, namedChunks, budgets, deployUrl, clearScreen, define, partialSSRBuild = false, externalRuntimeStyles, instrumentForCoverage, security, } = options;
248
+ const { allowedCommonJsDependencies, aot = true, baseHref, crossOrigin, externalDependencies, extractLicenses, inlineStyleLanguage = 'css', outExtension, serviceWorker, poll, polyfills, statsJson, outputMode, stylePreprocessorOptions, subresourceIntegrity, verbose, watch, progress = true, externalPackages, namedChunks, budgets, deployUrl, clearScreen, define, partialSSRBuild = false, externalRuntimeStyles, instrumentForCoverage, } = options;
241
249
  // Return all the normalized options
242
250
  return {
243
251
  advancedOptimizations: !!aot && optimizationOptions.scripts,
@@ -82,6 +82,17 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
82
82
  browserOptions.prerender = undefined;
83
83
  browserOptions.ssr ||= true;
84
84
  }
85
+ // Disable auto CSP.
86
+ browserOptions.security = {
87
+ autoCsp: false,
88
+ };
89
+ // Disable JSON build stats.
90
+ // These are not accessible with the dev server and can cause HMR fallbacks.
91
+ if (browserOptions.statsJson === true) {
92
+ context.logger.warn('Build JSON statistics output (`statsJson` option) has been disabled.' +
93
+ ' The development server does not support this option.');
94
+ }
95
+ browserOptions.statsJson = false;
85
96
  // Set all packages as external to support Vite's prebundle caching
86
97
  browserOptions.externalPackages = serverOptions.prebundle;
87
98
  // Disable generating a full manifest with routes.
@@ -402,7 +402,7 @@ function createCompilerPlugin(pluginOptions, compilationOrFactory, stylesheetBun
402
402
  const replacement = pluginOptions.fileReplacements?.[path.normalize(args.path)];
403
403
  if (replacement) {
404
404
  return {
405
- contents: await Promise.resolve().then(() => __importStar(require('fs/promises'))).then(({ readFile }) => readFile(path.normalize(replacement))),
405
+ contents: await Promise.resolve().then(() => __importStar(require('node:fs/promises'))).then(({ readFile }) => readFile(path.normalize(replacement))),
406
406
  loader: 'json',
407
407
  watchFiles: [replacement],
408
408
  };
@@ -59,13 +59,6 @@ async function generateIndexHtml(initialFiles, outputFiles, buildOptions, lang)
59
59
  }
60
60
  throw new Error(`Output file does not exist: ${relativefilePath}`);
61
61
  };
62
- // Read the Auto CSP options.
63
- const autoCsp = buildOptions.security?.autoCsp;
64
- const autoCspOptions = autoCsp === true
65
- ? { unsafeEval: false }
66
- : autoCsp
67
- ? { unsafeEval: !!autoCsp.unsafeEval }
68
- : undefined;
69
62
  // Create an index HTML generator that reads from the in-memory output files
70
63
  const indexHtmlGenerator = new index_html_generator_1.IndexHtmlGenerator({
71
64
  indexPath: indexHtmlOptions.input,
@@ -78,7 +71,7 @@ async function generateIndexHtml(initialFiles, outputFiles, buildOptions, lang)
78
71
  generateDedicatedSSRContent: !!(buildOptions.ssrOptions ||
79
72
  buildOptions.prerenderOptions ||
80
73
  buildOptions.appShellOptions),
81
- autoCsp: autoCspOptions,
74
+ autoCsp: buildOptions.security.autoCsp,
82
75
  });
83
76
  indexHtmlGenerator.readAsset = readAsset;
84
77
  return indexHtmlGenerator.process({
@@ -20,7 +20,8 @@ function angularHtmlFallbackMiddleware(req, _res, next) {
20
20
  }
21
21
  if (req.url) {
22
22
  const mimeType = (0, utils_1.lookupMimeTypeFromRequest)(req.url);
23
- if (mimeType === 'text/html' || mimeType === 'application/xhtml+xml') {
23
+ if ((mimeType === 'text/html' || mimeType === 'application/xhtml+xml') &&
24
+ !/^\/index\.(?:csr\.)?html/.test(req.url)) {
24
25
  // eslint-disable-next-line no-console
25
26
  console.warn(`Request for HTML file "${req.url}" was received but no asset found. Asset may be missing from build.`);
26
27
  }
@@ -11,10 +11,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.assertIsError = assertIsError;
14
- const assert_1 = __importDefault(require("assert"));
14
+ const node_assert_1 = __importDefault(require("node:assert"));
15
15
  function assertIsError(value) {
16
16
  const isError = value instanceof Error ||
17
17
  // The following is needing to identify errors coming from RxJs.
18
18
  (typeof value === 'object' && value && 'name' in value && 'message' in value);
19
- (0, assert_1.default)(isError, 'catch clause variable is not an Error instance');
19
+ (0, node_assert_1.default)(isError, 'catch clause variable is not an Error instance');
20
20
  }
@@ -112,7 +112,7 @@ async function autoCsp(html, unsafeEval = false) {
112
112
  rewriter.emitRaw(`<script>${loaderScript}</script>`);
113
113
  scriptContent = [];
114
114
  }
115
- rewriter.on('startTag', (tag, html) => {
115
+ rewriter.on('startTag', (tag) => {
116
116
  if (tag.tagName === 'script') {
117
117
  openedScriptTag = tag;
118
118
  const src = getScriptAttributeValue(tag, 'src');
@@ -32,7 +32,7 @@ class IndexHtmlGenerator {
32
32
  this.plugins = [augmentIndexHtmlPlugin(this), ...extraCommonPlugins, postTransformPlugin(this)];
33
33
  // CSR plugins
34
34
  if (options?.optimization?.styles?.inlineCritical) {
35
- this.csrPlugins.push(inlineCriticalCssPlugin(this));
35
+ this.csrPlugins.push(inlineCriticalCssPlugin(this, !!options.autoCsp));
36
36
  }
37
37
  this.csrPlugins.push(addNoncePlugin());
38
38
  // SSR plugins
@@ -127,11 +127,12 @@ function inlineFontsPlugin({ options }) {
127
127
  });
128
128
  return async (html) => inlineFontsProcessor.process(html);
129
129
  }
130
- function inlineCriticalCssPlugin(generator) {
130
+ function inlineCriticalCssPlugin(generator, autoCsp) {
131
131
  const inlineCriticalCssProcessor = new inline_critical_css_1.InlineCriticalCssProcessor({
132
132
  minify: generator.options.optimization?.styles.minify,
133
133
  deployUrl: generator.options.deployUrl,
134
134
  readAsset: (filePath) => generator.readAsset(filePath),
135
+ autoCsp,
135
136
  });
136
137
  return async (html, options) => inlineCriticalCssProcessor.process(html, { outputPath: options.outputPath });
137
138
  }
@@ -12,6 +12,7 @@ export interface InlineCriticalCssProcessorOptions {
12
12
  minify?: boolean;
13
13
  deployUrl?: string;
14
14
  readAsset?: (path: string) => Promise<string>;
15
+ autoCsp?: boolean;
15
16
  }
16
17
  export declare class InlineCriticalCssProcessor {
17
18
  protected readonly options: InlineCriticalCssProcessorOptions;
@@ -113,7 +113,7 @@ class BeastiesExtended extends BeastiesBase {
113
113
  }
114
114
  const returnValue = await super.embedLinkedStylesheet(link, document);
115
115
  const cspNonce = this.findCspNonce(document);
116
- if (cspNonce) {
116
+ if (cspNonce || this.optionsExtended.autoCsp) {
117
117
  const beastiesMedia = link.getAttribute('onload')?.match(MEDIA_SET_HANDLER_PATTERN);
118
118
  if (beastiesMedia) {
119
119
  // If there's a Beasties-generated `onload` handler and the file has an Angular CSP nonce,
@@ -128,11 +128,13 @@ class BeastiesExtended extends BeastiesBase {
128
128
  // a way of doing that at the moment so we fall back to doing it any time a `link` tag is
129
129
  // inserted. We mitigate it by only iterating the direct children of the `<head>` which
130
130
  // should be pretty shallow.
131
- document.head.children.forEach((child) => {
132
- if (child.tagName === 'style' && !child.hasAttribute('nonce')) {
133
- child.setAttribute('nonce', cspNonce);
134
- }
135
- });
131
+ if (cspNonce) {
132
+ document.head.children.forEach((child) => {
133
+ if (child.tagName === 'style' && !child.hasAttribute('nonce')) {
134
+ child.setAttribute('nonce', cspNonce);
135
+ }
136
+ });
137
+ }
136
138
  }
137
139
  return returnValue;
138
140
  }
@@ -159,8 +161,10 @@ class BeastiesExtended extends BeastiesBase {
159
161
  return;
160
162
  }
161
163
  const script = document.createElement('script');
162
- script.setAttribute('nonce', nonce);
163
164
  script.textContent = LINK_LOAD_SCRIPT_CONTENT;
165
+ if (nonce) {
166
+ script.setAttribute('nonce', nonce);
167
+ }
164
168
  // Prepend the script to the head since it needs to
165
169
  // run as early as possible, before the `link` tags.
166
170
  document.head.insertBefore(script, link);
@@ -41,8 +41,8 @@ var __importStar = (this && this.__importStar) || (function () {
41
41
  })();
42
42
  Object.defineProperty(exports, "__esModule", { value: true });
43
43
  exports.createTranslationLoader = createTranslationLoader;
44
- const crypto_1 = require("crypto");
45
- const fs = __importStar(require("fs"));
44
+ const node_crypto_1 = require("node:crypto");
45
+ const fs = __importStar(require("node:fs"));
46
46
  const load_esm_1 = require("./load-esm");
47
47
  async function createTranslationLoader() {
48
48
  const { parsers, diagnostics } = await importParsers();
@@ -55,7 +55,7 @@ async function createTranslationLoader() {
55
55
  // Types don't overlap here so we need to use any.
56
56
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
57
  const { locale, translations } = parser.parse(path, content, analysis.hint);
58
- const integrity = 'sha256-' + (0, crypto_1.createHash)('sha256').update(content).digest('base64');
58
+ const integrity = 'sha256-' + (0, node_crypto_1.createHash)('sha256').update(content).digest('base64');
59
59
  return { format, locale, translations, diagnostics, integrity };
60
60
  }
61
61
  else {
@@ -45,9 +45,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
45
45
  Object.defineProperty(exports, "__esModule", { value: true });
46
46
  exports.MissingAssetSourceRootException = void 0;
47
47
  exports.normalizeAssetPatterns = normalizeAssetPatterns;
48
- const fs_1 = require("fs");
49
48
  const node_assert_1 = __importDefault(require("node:assert"));
50
- const path = __importStar(require("path"));
49
+ const node_fs_1 = require("node:fs");
50
+ const path = __importStar(require("node:path"));
51
51
  class MissingAssetSourceRootException extends Error {
52
52
  constructor(path) {
53
53
  super(`The ${path} asset path must start with the project source root.`);
@@ -73,7 +73,7 @@ function normalizeAssetPatterns(assetPatterns, workspaceRoot, projectRoot, proje
73
73
  let glob, input;
74
74
  let isDirectory = false;
75
75
  try {
76
- isDirectory = (0, fs_1.statSync)(resolvedAssetPath).isDirectory();
76
+ isDirectory = (0, node_fs_1.statSync)(resolvedAssetPath).isDirectory();
77
77
  }
78
78
  catch {
79
79
  isDirectory = true;
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.normalizeCacheOptions = normalizeCacheOptions;
11
11
  const node_path_1 = require("node:path");
12
12
  /** Version placeholder is replaced during the build process with actual package version */
13
- const VERSION = '19.1.7';
13
+ const VERSION = '19.1.9';
14
14
  function hasCacheMetadata(value) {
15
15
  return (!!value &&
16
16
  typeof value === 'object' &&
@@ -17,7 +17,6 @@ const node_assert_1 = __importDefault(require("node:assert"));
17
17
  const node_crypto_1 = require("node:crypto");
18
18
  const node_path_1 = require("node:path");
19
19
  const node_url_1 = require("node:url");
20
- const url_1 = require("url");
21
20
  const javascript_transformer_1 = require("../../../tools/esbuild/javascript-transformer");
22
21
  /**
23
22
  * @note For some unknown reason, setting `globalThis.ngServerMode = true` does not work when using ESM loader hooks.
@@ -110,7 +109,7 @@ async function load(url, context, nextLoad) {
110
109
  // Only module files potentially require transformation. Angular libraries that would
111
110
  // need linking are ESM only.
112
111
  if (format === 'module' && isFileProtocol(url)) {
113
- const filePath = (0, url_1.fileURLToPath)(url);
112
+ const filePath = (0, node_url_1.fileURLToPath)(url);
114
113
  let source = await javascriptTransformer.transformFile(filePath);
115
114
  if (filePath.includes('@angular/')) {
116
115
  // Prepend 'var ngServerMode=true;' to the source.
@@ -7,14 +7,14 @@
7
7
  * found in the LICENSE file at https://angular.dev/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- const worker_threads_1 = require("worker_threads");
10
+ const node_worker_threads_1 = require("node:worker_threads");
11
11
  const fetch_patch_1 = require("./fetch-patch");
12
12
  const launch_server_1 = require("./launch-server");
13
13
  const load_esm_from_memory_1 = require("./load-esm-from-memory");
14
14
  /**
15
15
  * This is passed as workerData when setting up the worker via the `piscina` package.
16
16
  */
17
- const { outputMode, hasSsrEntry } = worker_threads_1.workerData;
17
+ const { outputMode, hasSsrEntry } = node_worker_threads_1.workerData;
18
18
  let serverURL = launch_server_1.DEFAULT_URL;
19
19
  /**
20
20
  * Renders each route in routes and writes them to <outputPath>/<route>/index.html.
@@ -7,7 +7,7 @@
7
7
  * found in the LICENSE file at https://angular.dev/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- const worker_threads_1 = require("worker_threads");
10
+ const node_worker_threads_1 = require("node:worker_threads");
11
11
  const schema_1 = require("../../builders/application/schema");
12
12
  const fetch_patch_1 = require("./fetch-patch");
13
13
  const launch_server_1 = require("./launch-server");
@@ -15,7 +15,7 @@ const load_esm_from_memory_1 = require("./load-esm-from-memory");
15
15
  /**
16
16
  * This is passed as workerData when setting up the worker via the `piscina` package.
17
17
  */
18
- const { outputMode, hasSsrEntry } = worker_threads_1.workerData;
18
+ const { outputMode, hasSsrEntry } = node_worker_threads_1.workerData;
19
19
  /** Renders an application based on a provided options. */
20
20
  async function extractRoutes() {
21
21
  const serverURL = outputMode !== undefined && hasSsrEntry ? await (0, launch_server_1.launchServer)() : launch_server_1.DEFAULT_URL;
@@ -43,9 +43,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
43
43
  exports.augmentAppWithServiceWorker = augmentAppWithServiceWorker;
44
44
  exports.augmentAppWithServiceWorkerEsbuild = augmentAppWithServiceWorkerEsbuild;
45
45
  exports.augmentAppWithServiceWorkerCore = augmentAppWithServiceWorkerCore;
46
- const crypto = __importStar(require("crypto"));
46
+ const crypto = __importStar(require("node:crypto"));
47
47
  const node_fs_1 = require("node:fs");
48
- const path = __importStar(require("path"));
48
+ const path = __importStar(require("node:path"));
49
49
  const bundler_context_1 = require("../tools/esbuild/bundler-context");
50
50
  const error_1 = require("./error");
51
51
  const load_esm_1 = require("./load-esm");