@angular-devkit/build-angular 17.1.1 → 17.2.0-next.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.
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@angular-devkit/build-angular",
3
- "version": "17.1.1",
3
+ "version": "17.2.0-next.0",
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.1",
10
- "@angular-devkit/architect": "0.1701.1",
11
- "@angular-devkit/build-webpack": "0.1701.1",
12
- "@angular-devkit/core": "17.1.1",
10
+ "@angular-devkit/architect": "0.1702.0-next.0",
11
+ "@angular-devkit/build-webpack": "0.1702.0-next.0",
12
+ "@angular-devkit/core": "17.2.0-next.0",
13
13
  "@babel/core": "7.23.7",
14
14
  "@babel/generator": "7.23.6",
15
15
  "@babel/helper-annotate-as-pure": "7.22.5",
@@ -17,52 +17,52 @@
17
17
  "@babel/plugin-transform-async-generator-functions": "7.23.7",
18
18
  "@babel/plugin-transform-async-to-generator": "7.23.3",
19
19
  "@babel/plugin-transform-runtime": "7.23.7",
20
- "@babel/preset-env": "7.23.7",
21
- "@babel/runtime": "7.23.7",
20
+ "@babel/preset-env": "7.23.8",
21
+ "@babel/runtime": "7.23.8",
22
22
  "@discoveryjs/json-ext": "0.5.7",
23
- "@ngtools/webpack": "17.1.1",
24
- "@vitejs/plugin-basic-ssl": "1.0.2",
23
+ "@ngtools/webpack": "17.2.0-next.0",
24
+ "@vitejs/plugin-basic-ssl": "1.1.0",
25
25
  "ansi-colors": "4.1.3",
26
- "autoprefixer": "10.4.16",
26
+ "autoprefixer": "10.4.17",
27
27
  "babel-loader": "9.1.3",
28
28
  "babel-plugin-istanbul": "6.1.1",
29
29
  "browserslist": "^4.21.5",
30
- "copy-webpack-plugin": "11.0.0",
30
+ "copy-webpack-plugin": "12.0.2",
31
31
  "critters": "0.0.20",
32
- "css-loader": "6.8.1",
33
- "esbuild-wasm": "0.19.11",
32
+ "css-loader": "6.9.1",
33
+ "esbuild-wasm": "0.19.12",
34
34
  "fast-glob": "3.3.2",
35
35
  "https-proxy-agent": "7.0.2",
36
36
  "http-proxy-middleware": "2.0.6",
37
37
  "inquirer": "9.2.12",
38
- "jsonc-parser": "3.2.0",
38
+ "jsonc-parser": "3.2.1",
39
39
  "karma-source-map-support": "1.4.0",
40
40
  "less": "4.2.0",
41
41
  "less-loader": "11.1.0",
42
42
  "license-webpack-plugin": "4.0.2",
43
43
  "loader-utils": "3.2.1",
44
44
  "magic-string": "0.30.5",
45
- "mini-css-extract-plugin": "2.7.6",
45
+ "mini-css-extract-plugin": "2.7.7",
46
46
  "mrmime": "2.0.0",
47
47
  "open": "8.4.2",
48
48
  "ora": "5.4.1",
49
49
  "parse5-html-rewriting-stream": "7.0.0",
50
50
  "picomatch": "3.0.1",
51
- "piscina": "4.2.1",
51
+ "piscina": "4.3.0",
52
52
  "postcss": "8.4.33",
53
- "postcss-loader": "7.3.4",
53
+ "postcss-loader": "8.0.0",
54
54
  "resolve-url-loader": "5.0.0",
55
55
  "rxjs": "7.8.1",
56
- "sass": "1.69.7",
57
- "sass-loader": "13.3.3",
56
+ "sass": "1.70.0",
57
+ "sass-loader": "14.0.0",
58
58
  "semver": "7.5.4",
59
59
  "source-map-loader": "5.0.0",
60
60
  "source-map-support": "0.5.21",
61
- "terser": "5.26.0",
61
+ "terser": "5.27.0",
62
62
  "text-table": "0.2.0",
63
63
  "tree-kill": "1.2.2",
64
64
  "tslib": "2.6.2",
65
- "undici": "6.2.1",
65
+ "undici": "6.4.0",
66
66
  "vite": "5.0.12",
67
67
  "watchpack": "2.4.0",
68
68
  "webpack": "5.89.0",
@@ -72,19 +72,19 @@
72
72
  "webpack-subresource-integrity": "5.1.0"
73
73
  },
74
74
  "optionalDependencies": {
75
- "esbuild": "0.19.11"
75
+ "esbuild": "0.19.12"
76
76
  },
77
77
  "peerDependencies": {
78
- "@angular/compiler-cli": "^17.0.0",
79
- "@angular/localize": "^17.0.0",
80
- "@angular/platform-server": "^17.0.0",
81
- "@angular/service-worker": "^17.0.0",
78
+ "@angular/compiler-cli": "^17.0.0 || ^17.2.0-next.0",
79
+ "@angular/localize": "^17.0.0 || ^17.2.0-next.0",
80
+ "@angular/platform-server": "^17.0.0 || ^17.2.0-next.0",
81
+ "@angular/service-worker": "^17.0.0 || ^17.2.0-next.0",
82
82
  "@web/test-runner": "^0.18.0",
83
83
  "browser-sync": "^3.0.2",
84
84
  "jest": "^29.5.0",
85
85
  "jest-environment-jsdom": "^29.5.0",
86
86
  "karma": "^6.3.0",
87
- "ng-packagr": "^17.0.0",
87
+ "ng-packagr": "^17.0.0 || ^17.2.0-next.0",
88
88
  "protractor": "^7.0.0",
89
89
  "tailwindcss": "^2.0.0 || ^3.0.0",
90
90
  "typescript": ">=5.2 <5.4"
@@ -29,8 +29,9 @@ async function normalizeOptions(context, projectName, options) {
29
29
  const projectMetadata = await context.getProjectMetadata(projectName);
30
30
  const projectRoot = node_path_1.default.join(workspaceRoot, projectMetadata.root ?? '');
31
31
  const cacheOptions = (0, normalize_cache_1.normalizeCacheOptions)(projectMetadata, workspaceRoot);
32
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
33
- const buildTarget = (0, architect_1.targetFromTargetString)(options.buildTarget ?? options.browserTarget);
32
+ // Target specifier defaults to the current project's build target using a development configuration
33
+ const buildTargetSpecifier = options.buildTarget ?? options.browserTarget ?? `::development`;
34
+ const buildTarget = (0, architect_1.targetFromTargetString)(buildTargetSpecifier, projectName, 'build');
34
35
  // Initial options to keep
35
36
  const { host, port, poll, open, verbose, watch, allowedHosts, disableHostCheck, liveReload, hmr, headers, proxyConfig, servePath, publicHost, ssl, sslCert, sslKey, forceEsbuild, } = options;
36
37
  // Return all the normalized options
@@ -13,7 +13,7 @@
13
13
  "buildTarget": {
14
14
  "type": "string",
15
15
  "description": "A build builder target to serve in the format of `project:target[:configuration]`. You can also pass in more than one configuration name as a comma-separated list. Example: `project:target:production,staging`.",
16
- "pattern": "^[^:\\s]+:[^:\\s]+(:[^\\s]+)?$"
16
+ "pattern": "^[^:\\s]*:[^:\\s]*(:[^\\s]+)?$"
17
17
  },
18
18
  "port": {
19
19
  "type": "number",
@@ -341,7 +341,7 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
341
341
  publicDir: false,
342
342
  esbuild: false,
343
343
  mode: 'development',
344
- appType: 'spa',
344
+ appType: 'mpa',
345
345
  css: {
346
346
  devSourcemap: true,
347
347
  },
@@ -30,8 +30,9 @@ async function normalizeOptions(context, projectName, options) {
30
30
  const workspaceRoot = context.workspaceRoot;
31
31
  const projectMetadata = await context.getProjectMetadata(projectName);
32
32
  const projectRoot = node_path_1.default.join(workspaceRoot, projectMetadata.root ?? '');
33
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
34
- const buildTarget = (0, architect_1.targetFromTargetString)(options.buildTarget ?? options.browserTarget);
33
+ // Target specifier defaults to the current project's build target with no specified configuration
34
+ const buildTargetSpecifier = options.buildTarget ?? options.browserTarget ?? ':';
35
+ const buildTarget = (0, architect_1.targetFromTargetString)(buildTargetSpecifier, projectName, 'build');
35
36
  const i18nOptions = (0, i18n_options_1.createI18nOptions)(projectMetadata);
36
37
  // Normalize xliff format extensions
37
38
  let format = options.format;
@@ -13,7 +13,7 @@
13
13
  "buildTarget": {
14
14
  "type": "string",
15
15
  "description": "A builder target to extract i18n messages in the format of `project:target[:configuration]`. You can also pass in more than one configuration name as a comma-separated list. Example: `project:target:production,staging`.",
16
- "pattern": "^[^:\\s]+:[^:\\s]+(:[^\\s]+)?$"
16
+ "pattern": "^[^:\\s]*:[^:\\s]*(:[^\\s]+)?$"
17
17
  },
18
18
  "format": {
19
19
  "type": "string",
@@ -31,15 +31,16 @@ var __importStar = (this && this.__importStar) || function (mod) {
31
31
  };
32
32
  Object.defineProperty(exports, "__esModule", { value: true });
33
33
  const architect_1 = require("@angular-devkit/architect");
34
- const child_process_1 = require("child_process");
35
- const path = __importStar(require("path"));
36
- const util_1 = require("util");
34
+ const node_child_process_1 = require("node:child_process");
35
+ const fs = __importStar(require("node:fs/promises"));
36
+ const path = __importStar(require("node:path"));
37
+ const node_util_1 = require("node:util");
37
38
  const color_1 = require("../../utils/color");
38
39
  const test_files_1 = require("../../utils/test-files");
39
40
  const application_1 = require("../application");
40
41
  const schema_1 = require("../browser-esbuild/schema");
41
42
  const options_1 = require("./options");
42
- const execFile = (0, util_1.promisify)(child_process_1.execFile);
43
+ const execFile = (0, node_util_1.promisify)(node_child_process_1.execFile);
43
44
  /** Main execution function for the Jest builder. */
44
45
  exports.default = (0, architect_1.createBuilder)(async (schema, context) => {
45
46
  context.logger.warn('NOTE: The Jest builder is currently EXPERIMENTAL and not ready for production use.');
@@ -65,8 +66,21 @@ exports.default = (0, architect_1.createBuilder)(async (schema, context) => {
65
66
  error: '`jest-environment-jsdom` is not installed. Install it with `npm install jest-environment-jsdom --save-dev`.',
66
67
  };
67
68
  }
69
+ const [testFiles, customConfig] = await Promise.all([
70
+ (0, test_files_1.findTestFiles)(options.include, options.exclude, context.workspaceRoot),
71
+ findCustomJestConfig(context.workspaceRoot),
72
+ ]);
73
+ // Warn if a custom Jest configuration is found. We won't use it, so if a developer is trying to use a custom config, this hopefully
74
+ // makes a better experience than silently ignoring the configuration.
75
+ // Ideally, this would be a hard error. However a Jest config could exist for testing other files in the workspace outside of Angular
76
+ // CLI, so we likely can't produce a hard error in this situation without an opt-out.
77
+ if (customConfig) {
78
+ context.logger.warn('A custom Jest config was found, but this is not supported by `@angular-devkit/build-angular:jest` and will be' +
79
+ ` ignored: ${customConfig}. This is an experiment to see if completely abstracting away Jest's configuration is viable. Please` +
80
+ ` consider if your use case can be met without directly modifying the Jest config. If this is a major obstacle for your use` +
81
+ ` case, please post it in this issue so we can collect feedback and evaluate: https://github.com/angular/angular-cli/issues/25434.`);
82
+ }
68
83
  // Build all the test files.
69
- const testFiles = await (0, test_files_1.findTestFiles)(options.include, options.exclude, context.workspaceRoot);
70
84
  const jestGlobal = path.join(__dirname, 'jest-global.mjs');
71
85
  const initTestBed = path.join(__dirname, 'init-test-bed.mjs');
72
86
  const buildResult = await build(context, {
@@ -94,6 +108,7 @@ exports.default = (0, architect_1.createBuilder)(async (schema, context) => {
94
108
  '--experimental-vm-modules',
95
109
  jest,
96
110
  `--rootDir="${path.join(testOut, 'browser')}"`,
111
+ `--config=${path.join(__dirname, 'jest.config.mjs')}`,
97
112
  '--testEnvironment=jsdom',
98
113
  // TODO(dgp1130): Enable cache once we have a mechanism for properly clearing / disabling it.
99
114
  '--no-cache',
@@ -158,3 +173,27 @@ function resolveModule(module) {
158
173
  return undefined;
159
174
  }
160
175
  }
176
+ /** Returns whether or not the provided directory includes a Jest configuration file. */
177
+ async function findCustomJestConfig(dir) {
178
+ const entries = await fs.readdir(dir, { withFileTypes: true });
179
+ // Jest supports many file extensions (`js`, `ts`, `cjs`, `cts`, `json`, etc.) Just look
180
+ // for anything with that prefix.
181
+ const config = entries.find((entry) => entry.isFile() && entry.name.startsWith('jest.config.'));
182
+ if (config) {
183
+ return path.join(dir, config.name);
184
+ }
185
+ // Jest also supports a `jest` key in `package.json`, look for a config there.
186
+ const packageJsonPath = path.join(dir, 'package.json');
187
+ let packageJson;
188
+ try {
189
+ packageJson = await fs.readFile(packageJsonPath, 'utf8');
190
+ }
191
+ catch {
192
+ return undefined; // No package.json, therefore no Jest configuration in it.
193
+ }
194
+ const json = JSON.parse(packageJson);
195
+ if ('jest' in json) {
196
+ return packageJsonPath;
197
+ }
198
+ return undefined;
199
+ }
@@ -0,0 +1,11 @@
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
+
9
+ // Empty config file, everything is specified via CLI options right now.
10
+ // This file is used just so Jest doesn't accidentally inherit a custom user-specified Jest config.
11
+ export default {};
@@ -14,6 +14,13 @@ export interface EmitFileResult {
14
14
  contents: string;
15
15
  dependencies?: readonly string[];
16
16
  }
17
+ export declare enum DiagnosticModes {
18
+ None = 0,
19
+ Option = 1,
20
+ Syntactic = 2,
21
+ Semantic = 4,
22
+ All = 7
23
+ }
17
24
  export declare abstract class AngularCompilation {
18
25
  #private;
19
26
  static loadCompilerCli(): Promise<typeof ng>;
@@ -25,8 +32,8 @@ export declare abstract class AngularCompilation {
25
32
  referencedFiles: readonly string[];
26
33
  }>;
27
34
  abstract emitAffectedFiles(): Iterable<EmitFileResult> | Promise<Iterable<EmitFileResult>>;
28
- protected abstract collectDiagnostics(): Iterable<ts.Diagnostic> | Promise<Iterable<ts.Diagnostic>>;
29
- diagnoseFiles(): Promise<{
35
+ protected abstract collectDiagnostics(modes: DiagnosticModes): Iterable<ts.Diagnostic> | Promise<Iterable<ts.Diagnostic>>;
36
+ diagnoseFiles(modes?: DiagnosticModes): Promise<{
30
37
  errors?: PartialMessage[];
31
38
  warnings?: PartialMessage[];
32
39
  }>;
@@ -30,10 +30,18 @@ var __importStar = (this && this.__importStar) || function (mod) {
30
30
  return result;
31
31
  };
32
32
  Object.defineProperty(exports, "__esModule", { value: true });
33
- exports.AngularCompilation = void 0;
33
+ exports.AngularCompilation = exports.DiagnosticModes = void 0;
34
34
  const load_esm_1 = require("../../../../utils/load-esm");
35
35
  const profiling_1 = require("../../profiling");
36
36
  const diagnostics_1 = require("../diagnostics");
37
+ var DiagnosticModes;
38
+ (function (DiagnosticModes) {
39
+ DiagnosticModes[DiagnosticModes["None"] = 0] = "None";
40
+ DiagnosticModes[DiagnosticModes["Option"] = 1] = "Option";
41
+ DiagnosticModes[DiagnosticModes["Syntactic"] = 2] = "Syntactic";
42
+ DiagnosticModes[DiagnosticModes["Semantic"] = 4] = "Semantic";
43
+ DiagnosticModes[DiagnosticModes["All"] = 7] = "All";
44
+ })(DiagnosticModes || (exports.DiagnosticModes = DiagnosticModes = {}));
37
45
  class AngularCompilation {
38
46
  static #angularCompilerCliModule;
39
47
  static #typescriptModule;
@@ -64,13 +72,13 @@ class AngularCompilation {
64
72
  supportJitMode: false,
65
73
  }));
66
74
  }
67
- async diagnoseFiles() {
75
+ async diagnoseFiles(modes = DiagnosticModes.All) {
68
76
  const result = {};
69
77
  // Avoid loading typescript until actually needed.
70
78
  // This allows for avoiding the load of typescript in the main thread when using the parallel compilation.
71
79
  const typescript = await AngularCompilation.loadTypescript();
72
80
  await (0, profiling_1.profileAsync)('NG_DIAGNOSTICS_TOTAL', async () => {
73
- for (const diagnostic of await this.collectDiagnostics()) {
81
+ for (const diagnostic of await this.collectDiagnostics(modes)) {
74
82
  const message = (0, diagnostics_1.convertTypeScriptDiagnostic)(typescript, diagnostic);
75
83
  if (diagnostic.category === typescript.DiagnosticCategory.Error) {
76
84
  (result.errors ??= []).push(message);
@@ -8,7 +8,7 @@
8
8
  import type ng from '@angular/compiler-cli';
9
9
  import ts from 'typescript';
10
10
  import { AngularHostOptions } from '../angular-host';
11
- import { AngularCompilation, EmitFileResult } from './angular-compilation';
11
+ import { AngularCompilation, DiagnosticModes, EmitFileResult } from './angular-compilation';
12
12
  export declare class AotCompilation extends AngularCompilation {
13
13
  #private;
14
14
  initialize(tsconfig: string, hostOptions: AngularHostOptions, compilerOptionsTransformer?: (compilerOptions: ng.CompilerOptions) => ng.CompilerOptions): Promise<{
@@ -16,6 +16,6 @@ export declare class AotCompilation extends AngularCompilation {
16
16
  compilerOptions: ng.CompilerOptions;
17
17
  referencedFiles: readonly string[];
18
18
  }>;
19
- collectDiagnostics(): Iterable<ts.Diagnostic>;
19
+ collectDiagnostics(modes: DiagnosticModes): Iterable<ts.Diagnostic>;
20
20
  emitAffectedFiles(): Iterable<EmitFileResult>;
21
21
  }
@@ -86,22 +86,33 @@ class AotCompilation extends angular_compilation_1.AngularCompilation {
86
86
  this.#state = new AngularCompilationState(angularProgram, host, typeScriptProgram, affectedFiles, affectedFiles.size === 1 ? OptimizeFor.SingleFile : OptimizeFor.WholeProgram, (0, web_worker_transformer_1.createWorkerTransformer)(hostOptions.processWebWorker.bind(hostOptions)), this.#state?.diagnosticCache);
87
87
  return { affectedFiles, compilerOptions, referencedFiles };
88
88
  }
89
- *collectDiagnostics() {
89
+ *collectDiagnostics(modes) {
90
90
  (0, node_assert_1.default)(this.#state, 'Angular compilation must be initialized prior to collecting diagnostics.');
91
91
  const { affectedFiles, angularCompiler, diagnosticCache, templateDiagnosticsOptimization, typeScriptProgram, } = this.#state;
92
+ const syntactic = modes & angular_compilation_1.DiagnosticModes.Syntactic;
93
+ const semantic = modes & angular_compilation_1.DiagnosticModes.Semantic;
92
94
  // Collect program level diagnostics
93
- yield* typeScriptProgram.getConfigFileParsingDiagnostics();
94
- yield* angularCompiler.getOptionDiagnostics();
95
- yield* typeScriptProgram.getOptionsDiagnostics();
96
- yield* typeScriptProgram.getGlobalDiagnostics();
95
+ if (modes & angular_compilation_1.DiagnosticModes.Option) {
96
+ yield* typeScriptProgram.getConfigFileParsingDiagnostics();
97
+ yield* angularCompiler.getOptionDiagnostics();
98
+ yield* typeScriptProgram.getOptionsDiagnostics();
99
+ }
100
+ if (syntactic) {
101
+ yield* typeScriptProgram.getGlobalDiagnostics();
102
+ }
97
103
  // Collect source file specific diagnostics
98
104
  for (const sourceFile of typeScriptProgram.getSourceFiles()) {
99
105
  if (angularCompiler.ignoreForDiagnostics.has(sourceFile)) {
100
106
  continue;
101
107
  }
102
- // TypeScript will use cached diagnostics for files that have not been
103
- // changed or affected for this build when using incremental building.
104
- yield* (0, profiling_1.profileSync)('NG_DIAGNOSTICS_SYNTACTIC', () => typeScriptProgram.getSyntacticDiagnostics(sourceFile), true);
108
+ if (syntactic) {
109
+ // TypeScript will use cached diagnostics for files that have not been
110
+ // changed or affected for this build when using incremental building.
111
+ yield* (0, profiling_1.profileSync)('NG_DIAGNOSTICS_SYNTACTIC', () => typeScriptProgram.getSyntacticDiagnostics(sourceFile), true);
112
+ }
113
+ if (!semantic) {
114
+ continue;
115
+ }
105
116
  yield* (0, profiling_1.profileSync)('NG_DIAGNOSTICS_SEMANTIC', () => typeScriptProgram.getSemanticDiagnostics(sourceFile), true);
106
117
  // Declaration files cannot have template diagnostics
107
118
  if (sourceFile.isDeclarationFile) {
@@ -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
- export { AngularCompilation } from './angular-compilation';
8
+ export { AngularCompilation, DiagnosticModes } from './angular-compilation';
9
9
  export { createAngularCompilation } from './factory';
10
10
  export { NoopCompilation } from './noop-compilation';
@@ -7,9 +7,10 @@
7
7
  * found in the LICENSE file at https://angular.io/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.NoopCompilation = exports.createAngularCompilation = exports.AngularCompilation = void 0;
10
+ exports.NoopCompilation = exports.createAngularCompilation = exports.DiagnosticModes = exports.AngularCompilation = void 0;
11
11
  var angular_compilation_1 = require("./angular-compilation");
12
12
  Object.defineProperty(exports, "AngularCompilation", { enumerable: true, get: function () { return angular_compilation_1.AngularCompilation; } });
13
+ Object.defineProperty(exports, "DiagnosticModes", { enumerable: true, get: function () { return angular_compilation_1.DiagnosticModes; } });
13
14
  var factory_1 = require("./factory");
14
15
  Object.defineProperty(exports, "createAngularCompilation", { enumerable: true, get: function () { return factory_1.createAngularCompilation; } });
15
16
  var noop_compilation_1 = require("./noop-compilation");
@@ -8,7 +8,7 @@
8
8
  import type ng from '@angular/compiler-cli';
9
9
  import ts from 'typescript';
10
10
  import { AngularHostOptions } from '../angular-host';
11
- import { AngularCompilation, EmitFileResult } from './angular-compilation';
11
+ import { AngularCompilation, DiagnosticModes, EmitFileResult } from './angular-compilation';
12
12
  export declare class JitCompilation extends AngularCompilation {
13
13
  #private;
14
14
  initialize(tsconfig: string, hostOptions: AngularHostOptions, compilerOptionsTransformer?: (compilerOptions: ng.CompilerOptions) => ng.CompilerOptions): Promise<{
@@ -16,6 +16,6 @@ export declare class JitCompilation extends AngularCompilation {
16
16
  compilerOptions: ng.CompilerOptions;
17
17
  referencedFiles: readonly string[];
18
18
  }>;
19
- collectDiagnostics(): Iterable<ts.Diagnostic>;
19
+ collectDiagnostics(modes: DiagnosticModes): Iterable<ts.Diagnostic>;
20
20
  emitAffectedFiles(): Iterable<EmitFileResult>;
21
21
  }
@@ -51,15 +51,21 @@ class JitCompilation extends angular_compilation_1.AngularCompilation {
51
51
  .map((sourceFile) => sourceFile.fileName);
52
52
  return { affectedFiles, compilerOptions, referencedFiles };
53
53
  }
54
- *collectDiagnostics() {
54
+ *collectDiagnostics(modes) {
55
55
  (0, node_assert_1.default)(this.#state, 'Compilation must be initialized prior to collecting diagnostics.');
56
56
  const { typeScriptProgram } = this.#state;
57
57
  // Collect program level diagnostics
58
- yield* typeScriptProgram.getConfigFileParsingDiagnostics();
59
- yield* typeScriptProgram.getOptionsDiagnostics();
60
- yield* typeScriptProgram.getGlobalDiagnostics();
61
- yield* (0, profiling_1.profileSync)('NG_DIAGNOSTICS_SYNTACTIC', () => typeScriptProgram.getSyntacticDiagnostics());
62
- yield* (0, profiling_1.profileSync)('NG_DIAGNOSTICS_SEMANTIC', () => typeScriptProgram.getSemanticDiagnostics());
58
+ if (modes & angular_compilation_1.DiagnosticModes.Option) {
59
+ yield* typeScriptProgram.getConfigFileParsingDiagnostics();
60
+ yield* typeScriptProgram.getOptionsDiagnostics();
61
+ }
62
+ if (modes & angular_compilation_1.DiagnosticModes.Syntactic) {
63
+ yield* typeScriptProgram.getGlobalDiagnostics();
64
+ yield* (0, profiling_1.profileSync)('NG_DIAGNOSTICS_SYNTACTIC', () => typeScriptProgram.getSyntacticDiagnostics());
65
+ }
66
+ if (modes & angular_compilation_1.DiagnosticModes.Semantic) {
67
+ yield* (0, profiling_1.profileSync)('NG_DIAGNOSTICS_SEMANTIC', () => typeScriptProgram.getSemanticDiagnostics());
68
+ }
63
69
  }
64
70
  emitAffectedFiles() {
65
71
  (0, node_assert_1.default)(this.#state, 'Compilation must be initialized prior to emitting files.');
@@ -9,7 +9,7 @@ import type { CompilerOptions } from '@angular/compiler-cli';
9
9
  import type { PartialMessage } from 'esbuild';
10
10
  import type { SourceFile } from 'typescript';
11
11
  import type { AngularHostOptions } from '../angular-host';
12
- import { AngularCompilation, EmitFileResult } from './angular-compilation';
12
+ import { AngularCompilation, DiagnosticModes, EmitFileResult } from './angular-compilation';
13
13
  /**
14
14
  * An Angular compilation which uses a Node.js Worker thread to load and execute
15
15
  * the TypeScript and Angular compilers. This allows for longer synchronous actions
@@ -32,7 +32,7 @@ export declare class ParallelCompilation extends AngularCompilation {
32
32
  * with the serializable esbuild compatible diagnostics.
33
33
  */
34
34
  protected collectDiagnostics(): never;
35
- diagnoseFiles(): Promise<{
35
+ diagnoseFiles(modes?: DiagnosticModes): Promise<{
36
36
  errors?: PartialMessage[];
37
37
  warnings?: PartialMessage[];
38
38
  }>;
@@ -106,8 +106,8 @@ class ParallelCompilation extends angular_compilation_1.AngularCompilation {
106
106
  collectDiagnostics() {
107
107
  throw new Error('Not implemented in ParallelCompilation.');
108
108
  }
109
- diagnoseFiles() {
110
- return this.#worker.run(undefined, { name: 'diagnose' });
109
+ diagnoseFiles(modes = angular_compilation_1.DiagnosticModes.All) {
110
+ return this.#worker.run(modes, { name: 'diagnose' });
111
111
  }
112
112
  emitAffectedFiles() {
113
113
  return this.#worker.run(undefined, { name: 'emit' });
@@ -10,6 +10,7 @@
10
10
  /// <reference types="@types/node/ts4.8/worker_threads" />
11
11
  import type { PartialMessage } from 'esbuild';
12
12
  import { type MessagePort } from 'node:worker_threads';
13
+ import type { DiagnosticModes } from './angular-compilation';
13
14
  export interface InitRequest {
14
15
  jit: boolean;
15
16
  tsconfig: string;
@@ -26,7 +27,7 @@ export declare function initialize(request: InitRequest): Promise<{
26
27
  allowJs: boolean | undefined;
27
28
  };
28
29
  }>;
29
- export declare function diagnose(): Promise<{
30
+ export declare function diagnose(modes: DiagnosticModes): Promise<{
30
31
  errors?: PartialMessage[];
31
32
  warnings?: PartialMessage[];
32
33
  }>;
@@ -72,9 +72,9 @@ async function initialize(request) {
72
72
  };
73
73
  }
74
74
  exports.initialize = initialize;
75
- async function diagnose() {
75
+ async function diagnose(modes) {
76
76
  (0, node_assert_1.default)(compilation);
77
- const diagnostics = await compilation.diagnoseFiles();
77
+ const diagnostics = await compilation.diagnoseFiles(modes);
78
78
  return diagnostics;
79
79
  }
80
80
  exports.diagnose = diagnose;
@@ -195,13 +195,6 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
195
195
  hasCompilationErrors = await sharedTSCompilationState.waitUntilReady;
196
196
  return result;
197
197
  }
198
- const diagnostics = await compilation.diagnoseFiles();
199
- if (diagnostics.errors?.length) {
200
- (result.errors ??= []).push(...diagnostics.errors);
201
- }
202
- if (diagnostics.warnings?.length) {
203
- (result.warnings ??= []).push(...diagnostics.warnings);
204
- }
205
198
  // Update TypeScript file output cache for all affected files
206
199
  try {
207
200
  await (0, profiling_1.profileAsync)('NG_EMIT_TS', async () => {
@@ -222,6 +215,13 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
222
215
  ],
223
216
  });
224
217
  }
218
+ const diagnostics = await compilation.diagnoseFiles(environment_options_1.useTypeChecking ? compilation_1.DiagnosticModes.All : compilation_1.DiagnosticModes.All & ~compilation_1.DiagnosticModes.Semantic);
219
+ if (diagnostics.errors?.length) {
220
+ (result.errors ??= []).push(...diagnostics.errors);
221
+ }
222
+ if (diagnostics.warnings?.length) {
223
+ (result.warnings ??= []).push(...diagnostics.warnings);
224
+ }
225
225
  // Add errors from failed additional results.
226
226
  // This must be done after emit to capture latest web worker results.
227
227
  for (const { errors } of additionalResults.values()) {
@@ -61,6 +61,7 @@ function createAngularMemoryPlugin(options) {
61
61
  map: mapContents && Buffer.from(mapContents).toString('utf-8'),
62
62
  };
63
63
  },
64
+ // eslint-disable-next-line max-lines-per-function
64
65
  configureServer(server) {
65
66
  const originalssrTransform = server.ssrTransform;
66
67
  server.ssrTransform = async (code, map, url, originalCode) => {
@@ -124,14 +125,15 @@ function createAngularMemoryPlugin(options) {
124
125
  // Returning a function, installs middleware after the main transform middleware but
125
126
  // before the built-in HTML middleware
126
127
  return () => {
128
+ server.middlewares.use(angularHtmlFallbackMiddleware);
127
129
  function angularSSRMiddleware(req, res, next) {
128
130
  const url = req.originalUrl;
129
131
  if (!req.url ||
130
132
  // Skip if path is not defined.
131
133
  !url ||
132
134
  // Skip if path is like a file.
133
- // NOTE: We use a regexp to mitigate against matching requests like: /browse/pl.0ef59752c0cd457dbf1391f08cbd936f
134
- /^\.[a-z]{2,4}$/i.test((0, node_path_1.extname)(url.split('?')[0]))) {
135
+ // NOTE: We use a mime type lookup to mitigate against matching requests like: /browse/pl.0ef59752c0cd457dbf1391f08cbd936f
136
+ lookupMimeTypeFromRequest(url)) {
135
137
  next();
136
138
  return;
137
139
  }
@@ -212,12 +214,13 @@ exports.createAngularMemoryPlugin = createAngularMemoryPlugin;
212
214
  */
213
215
  async function loadViteClientCode(file) {
214
216
  const originalContents = await (0, promises_1.readFile)(file, 'utf-8');
215
- let contents = originalContents.replace('You can also disable this overlay by setting', '');
216
- contents = contents.replace(
217
+ const firstUpdate = originalContents.replace('You can also disable this overlay by setting', '');
218
+ (0, node_assert_1.default)(originalContents !== firstUpdate, 'Failed to update Vite client error overlay text. (1)');
219
+ const secondUpdate = firstUpdate.replace(
217
220
  // eslint-disable-next-line max-len
218
- '<code part="config-option-name">server.hmr.overlay</code> to <code part="config-option-value">false</code> in <code part="config-file-name">vite.config.js.</code>', '');
219
- (0, node_assert_1.default)(originalContents !== contents, 'Failed to update Vite client error overlay text.');
220
- return contents;
221
+ '<code part="config-option-name">server.hmr.overlay</code> to <code part="config-option-value">false</code> in <code part="config-file-name">${hmrConfigName}.</code>', '');
222
+ (0, node_assert_1.default)(firstUpdate !== secondUpdate, 'Failed to update Vite client error overlay text. (2)');
223
+ return secondUpdate;
221
224
  }
222
225
  function pathnameWithoutBasePath(url, basePath) {
223
226
  const parsedUrl = new URL(url, 'http://localhost');
@@ -227,3 +230,23 @@ function pathnameWithoutBasePath(url, basePath) {
227
230
  ? pathname.slice(basePath.length - 1)
228
231
  : pathname;
229
232
  }
233
+ function angularHtmlFallbackMiddleware(req, res, next) {
234
+ // Similar to how it is handled in vite
235
+ // https://github.com/vitejs/vite/blob/main/packages/vite/src/node/server/middlewares/htmlFallback.ts#L15C19-L15C45
236
+ if ((req.method === 'GET' || req.method === 'HEAD') &&
237
+ (!req.url || !lookupMimeTypeFromRequest(req.url)) &&
238
+ (!req.headers.accept ||
239
+ req.headers.accept.includes('text/html') ||
240
+ req.headers.accept.includes('text/*') ||
241
+ req.headers.accept.includes('*/*'))) {
242
+ req.url = '/index.html';
243
+ }
244
+ next();
245
+ }
246
+ function lookupMimeTypeFromRequest(url) {
247
+ const extension = (0, node_path_1.extname)(url.split('?')[0]);
248
+ if (extension === '.ico') {
249
+ return 'image/x-icon';
250
+ }
251
+ return extension && (0, mrmime_1.lookup)(extension);
252
+ }
@@ -13,3 +13,4 @@ export declare const useParallelTs: boolean;
13
13
  export declare const useLegacySass: boolean;
14
14
  export declare const debugPerformance: boolean;
15
15
  export declare const shouldWatchRoot: boolean;
16
+ export declare const useTypeChecking: boolean;
@@ -7,7 +7,7 @@
7
7
  * found in the LICENSE file at https://angular.io/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.shouldWatchRoot = exports.debugPerformance = exports.useLegacySass = exports.useParallelTs = exports.maxWorkers = exports.allowMinify = exports.shouldBeautify = exports.allowMangle = void 0;
10
+ exports.useTypeChecking = exports.shouldWatchRoot = exports.debugPerformance = exports.useLegacySass = exports.useParallelTs = exports.maxWorkers = exports.allowMinify = exports.shouldBeautify = exports.allowMangle = void 0;
11
11
  const color_1 = require("./color");
12
12
  function isDisabled(variable) {
13
13
  return variable === '0' || variable.toLowerCase() === 'false';
@@ -83,3 +83,5 @@ const debugPerfVariable = process.env['NG_BUILD_DEBUG_PERF'];
83
83
  exports.debugPerformance = isPresent(debugPerfVariable) && isEnabled(debugPerfVariable);
84
84
  const watchRootVariable = process.env['NG_BUILD_WATCH_ROOT'];
85
85
  exports.shouldWatchRoot = isPresent(watchRootVariable) && isEnabled(watchRootVariable);
86
+ const typeCheckingVariable = process.env['NG_BUILD_TYPE_CHECK'];
87
+ exports.useTypeChecking = !isPresent(typeCheckingVariable) || !isDisabled(typeCheckingVariable);