@angular/build 20.0.0-next.0 → 20.0.0-next.1

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 (28) hide show
  1. package/package.json +10 -9
  2. package/src/builders/application/execute-build.js +37 -9
  3. package/src/builders/application/options.d.ts +3 -3
  4. package/src/builders/application/options.js +25 -2
  5. package/src/builders/application/schema.d.ts +3 -1
  6. package/src/builders/application/schema.json +1 -1
  7. package/src/builders/dev-server/builder.js +0 -4
  8. package/src/builders/dev-server/schema.d.ts +3 -1
  9. package/src/builders/dev-server/schema.json +1 -1
  10. package/src/builders/dev-server/vite-server.js +1 -0
  11. package/src/builders/extract-i18n/builder.js +1 -1
  12. package/src/tools/babel/plugins/add-code-coverage.js +1 -8
  13. package/src/tools/esbuild/angular/compiler-plugin.js +0 -5
  14. package/src/tools/esbuild/bundler-context.js +5 -7
  15. package/src/tools/esbuild/bundler-execution-result.d.ts +1 -1
  16. package/src/tools/esbuild/bundler-execution-result.js +1 -1
  17. package/src/tools/esbuild/external-packages-plugin.js +31 -9
  18. package/src/tools/esbuild/stylesheets/less-language.js +3 -17
  19. package/src/tools/esbuild/stylesheets/stylesheet-plugin-factory.js +11 -1
  20. package/src/tools/vite/middlewares/chrome-devtools-middleware.d.ts +9 -0
  21. package/src/tools/vite/middlewares/chrome-devtools-middleware.js +52 -0
  22. package/src/tools/vite/middlewares/index.d.ts +1 -0
  23. package/src/tools/vite/middlewares/index.js +3 -1
  24. package/src/tools/vite/plugins/id-prefix-plugin.js +1 -1
  25. package/src/tools/vite/plugins/setup-middlewares-plugin.d.ts +1 -0
  26. package/src/tools/vite/plugins/setup-middlewares-plugin.js +1 -0
  27. package/src/utils/i18n-options.d.ts +2 -0
  28. package/src/utils/normalize-cache.js +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular/build",
3
- "version": "20.0.0-next.0",
3
+ "version": "20.0.0-next.1",
4
4
  "description": "Official build system for Angular",
5
5
  "keywords": [
6
6
  "Angular CLI",
@@ -23,16 +23,16 @@
23
23
  "builders": "builders.json",
24
24
  "dependencies": {
25
25
  "@ampproject/remapping": "2.3.0",
26
- "@angular-devkit/architect": "0.2000.0-next.0",
27
- "@babel/core": "7.26.9",
26
+ "@angular-devkit/architect": "0.2000.0-next.1",
27
+ "@babel/core": "7.26.10",
28
28
  "@babel/helper-annotate-as-pure": "7.25.9",
29
29
  "@babel/helper-split-export-declaration": "7.24.7",
30
30
  "@babel/plugin-syntax-import-attributes": "7.26.0",
31
- "@inquirer/confirm": "5.1.6",
31
+ "@inquirer/confirm": "5.1.7",
32
32
  "@vitejs/plugin-basic-ssl": "2.0.0",
33
33
  "beasties": "0.2.0",
34
34
  "browserslist": "^4.23.0",
35
- "esbuild": "0.25.0",
35
+ "esbuild": "0.25.1",
36
36
  "https-proxy-agent": "7.0.6",
37
37
  "istanbul-lib-instrument": "6.0.3",
38
38
  "listr2": "8.2.5",
@@ -41,12 +41,12 @@
41
41
  "parse5-html-rewriting-stream": "7.0.0",
42
42
  "picomatch": "4.0.2",
43
43
  "piscina": "4.8.0",
44
- "rollup": "4.34.9",
44
+ "rollup": "4.35.0",
45
45
  "sass": "1.85.1",
46
46
  "semver": "7.7.1",
47
47
  "source-map-support": "0.5.21",
48
48
  "tinyglobby": "0.2.12",
49
- "vite": "6.2.0",
49
+ "vite": "6.2.1",
50
50
  "watchpack": "2.4.2"
51
51
  },
52
52
  "optionalDependencies": {
@@ -58,13 +58,13 @@
58
58
  "@angular/localize": "^20.0.0 || ^20.0.0-next.0",
59
59
  "@angular/platform-server": "^20.0.0 || ^20.0.0-next.0",
60
60
  "@angular/service-worker": "^20.0.0 || ^20.0.0-next.0",
61
- "@angular/ssr": "^20.0.0-next.0",
61
+ "@angular/ssr": "^20.0.0-next.1",
62
62
  "karma": "^6.4.0",
63
63
  "less": "^4.2.0",
64
64
  "ng-packagr": "^20.0.0 || ^20.0.0-next.0",
65
65
  "postcss": "^8.4.0",
66
66
  "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0",
67
- "typescript": ">=5.5 <5.9"
67
+ "typescript": ">=5.8 <5.9"
68
68
  },
69
69
  "peerDependenciesMeta": {
70
70
  "@angular/localize": {
@@ -99,6 +99,7 @@
99
99
  "type": "git",
100
100
  "url": "https://github.com/angular/angular-cli.git"
101
101
  },
102
+ "packageManager": "pnpm@9.15.6",
102
103
  "engines": {
103
104
  "node": "^20.11.1 || >=22.0.0",
104
105
  "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
@@ -136,15 +136,43 @@ async function executeBuild(options, context, rebuildState) {
136
136
  }
137
137
  // Analyze external imports if external options are enabled
138
138
  if (options.externalPackages || bundlingResult.externalConfiguration) {
139
- const { externalConfiguration, externalImports: { browser, server }, } = bundlingResult;
140
- const implicitBrowser = browser ? [...browser] : [];
141
- const implicitServer = server ? [...server] : [];
142
- // TODO: Implement wildcard externalConfiguration filtering
143
- executionResult.setExternalMetadata(externalConfiguration
144
- ? implicitBrowser.filter((value) => !externalConfiguration.includes(value))
145
- : implicitBrowser, externalConfiguration
146
- ? implicitServer.filter((value) => !externalConfiguration.includes(value))
147
- : implicitServer, externalConfiguration);
139
+ const { externalConfiguration = [], externalImports: { browser = [], server = [] }, } = bundlingResult;
140
+ // Similar to esbuild, --external:@foo/bar automatically implies --external:@foo/bar/*,
141
+ // which matches import paths like @foo/bar/baz.
142
+ // This means all paths within the @foo/bar package are also marked as external.
143
+ const exclusionsPrefixes = externalConfiguration.map((exclusion) => exclusion + '/');
144
+ const exclusions = new Set(externalConfiguration);
145
+ const explicitExternal = new Set();
146
+ const isExplicitExternal = (dep) => {
147
+ if (exclusions.has(dep)) {
148
+ return true;
149
+ }
150
+ for (const prefix of exclusionsPrefixes) {
151
+ if (dep.startsWith(prefix)) {
152
+ return true;
153
+ }
154
+ }
155
+ return false;
156
+ };
157
+ const implicitBrowser = [];
158
+ for (const dep of browser) {
159
+ if (isExplicitExternal(dep)) {
160
+ explicitExternal.add(dep);
161
+ }
162
+ else {
163
+ implicitBrowser.push(dep);
164
+ }
165
+ }
166
+ const implicitServer = [];
167
+ for (const dep of server) {
168
+ if (isExplicitExternal(dep)) {
169
+ explicitExternal.add(dep);
170
+ }
171
+ else {
172
+ implicitServer.push(dep);
173
+ }
174
+ }
175
+ executionResult.setExternalMetadata(implicitBrowser, implicitServer, [...explicitExternal]);
148
176
  }
149
177
  const { metafile, initialFiles, outputFiles } = bundlingResult;
150
178
  executionResult.outputFiles.push(...outputFiles);
@@ -108,6 +108,9 @@ export declare function normalizeOptions(context: BuilderContext, projectName: s
108
108
  cacheOptions: import("../../utils/normalize-cache").NormalizedCachedOptions;
109
109
  crossOrigin: import("./schema").CrossOrigin | undefined;
110
110
  externalDependencies: string[] | undefined;
111
+ externalPackages: boolean | {
112
+ exclude: string[] | undefined;
113
+ } | undefined;
111
114
  extractLicenses: boolean | undefined;
112
115
  inlineStyleLanguage: string;
113
116
  jit: boolean;
@@ -115,9 +118,6 @@ export declare function normalizeOptions(context: BuilderContext, projectName: s
115
118
  polyfills: string[] | undefined;
116
119
  poll: number | undefined;
117
120
  progress: boolean;
118
- externalPackages: boolean | {
119
- exclude: string[];
120
- } | undefined;
121
121
  preserveSymlinks: boolean;
122
122
  stylePreprocessorOptions: import("./schema").StylePreprocessorOptions | undefined;
123
123
  subresourceIntegrity: boolean | undefined;
@@ -253,7 +253,13 @@ async function normalizeOptions(context, projectName, options, extensions) {
253
253
  baseHref,
254
254
  cacheOptions,
255
255
  crossOrigin,
256
- externalDependencies,
256
+ externalDependencies: normalizeExternals(externalDependencies),
257
+ externalPackages: typeof externalPackages === 'object'
258
+ ? {
259
+ ...externalPackages,
260
+ exclude: normalizeExternals(externalPackages.exclude),
261
+ }
262
+ : externalPackages,
257
263
  extractLicenses,
258
264
  inlineStyleLanguage,
259
265
  jit: !aot,
@@ -261,7 +267,6 @@ async function normalizeOptions(context, projectName, options, extensions) {
261
267
  polyfills: polyfills === undefined || Array.isArray(polyfills) ? polyfills : [polyfills],
262
268
  poll,
263
269
  progress,
264
- externalPackages,
265
270
  preserveSymlinks,
266
271
  stylePreprocessorOptions,
267
272
  subresourceIntegrity,
@@ -447,3 +452,21 @@ function getLocaleBaseHref(baseHref = '', i18n, locale) {
447
452
  const baseHrefSuffix = localeData.baseHref ?? localeData.subPath + '/';
448
453
  return baseHrefSuffix !== '' ? (0, url_1.urlJoin)(baseHref, baseHrefSuffix) : undefined;
449
454
  }
455
+ /**
456
+ * Normalizes an array of external dependency paths by ensuring that
457
+ * wildcard patterns (`/*`) are removed from package names.
458
+ *
459
+ * This avoids the need to handle this normalization repeatedly in our plugins,
460
+ * as esbuild already treats `--external:@foo/bar` as implicitly including
461
+ * `--external:@foo/bar/*`. By standardizing the input, we ensure consistency
462
+ * and reduce redundant checks across our plugins.
463
+ *
464
+ * @param value - An optional array of dependency paths to normalize.
465
+ * @returns A new array with wildcard patterns removed from package names, or `undefined` if input is `undefined`.
466
+ */
467
+ function normalizeExternals(value) {
468
+ if (!value) {
469
+ return undefined;
470
+ }
471
+ return [...new Set(value.map((d) => (d.endsWith('/*') ? d.slice(0, -2) : d)))];
472
+ }
@@ -62,7 +62,9 @@ export type Schema = {
62
62
  deployUrl?: string;
63
63
  /**
64
64
  * Exclude the listed external dependencies from being bundled into the bundle. Instead, the
65
- * created bundle relies on these dependencies to be available during runtime.
65
+ * created bundle relies on these dependencies to be available during runtime. Note:
66
+ * `@foo/bar` marks all paths within the `@foo/bar` package as external, including sub-paths
67
+ * like `@foo/bar/baz`.
66
68
  */
67
69
  externalDependencies?: string[];
68
70
  /**
@@ -196,7 +196,7 @@
196
196
  "additionalProperties": false
197
197
  },
198
198
  "externalDependencies": {
199
- "description": "Exclude the listed external dependencies from being bundled into the bundle. Instead, the created bundle relies on these dependencies to be available during runtime.",
199
+ "description": "Exclude the listed external dependencies from being bundled into the bundle. Instead, the created bundle relies on these dependencies to be available during runtime. Note: `@foo/bar` marks all paths within the `@foo/bar` package as external, including sub-paths like `@foo/bar/baz`.",
200
200
  "type": "array",
201
201
  "items": {
202
202
  "type": "string"
@@ -33,10 +33,6 @@ async function* execute(options, context, extensions) {
33
33
  return;
34
34
  }
35
35
  const { builderName, normalizedOptions } = await initialize(options, projectName, context);
36
- // Warn if the initial options provided by the user enable prebundling but caching is disabled
37
- if (options.prebundle && !normalizedOptions.cacheOptions.enabled) {
38
- context.logger.warn(`Prebundling has been configured but will not be used because caching has been disabled.`);
39
- }
40
36
  yield* (0, vite_server_1.serveWithVite)(normalizedOptions, builderName, (options, context, plugins) => (0, internal_1.buildApplicationInternal)(options, context, { codePlugins: plugins }), context, { indexHtml: extensions?.indexHtmlTransformer }, extensions);
41
37
  }
42
38
  async function initialize(initialOptions, projectName, context) {
@@ -104,7 +104,9 @@ export type PrebundleUnion = boolean | PrebundleClass;
104
104
  export type PrebundleClass = {
105
105
  /**
106
106
  * List of package imports that should not be prebundled by the development server. The
107
- * packages will be bundled into the application code itself.
107
+ * packages will be bundled into the application code itself. Note: specifying `@foo/bar`
108
+ * marks all paths within the `@foo/bar` package as excluded, including sub-paths like
109
+ * `@foo/bar/baz`.
108
110
  */
109
111
  exclude: string[];
110
112
  };
@@ -115,7 +115,7 @@
115
115
  "type": "object",
116
116
  "properties": {
117
117
  "exclude": {
118
- "description": "List of package imports that should not be prebundled by the development server. The packages will be bundled into the application code itself.",
118
+ "description": "List of package imports that should not be prebundled by the development server. The packages will be bundled into the application code itself. Note: specifying `@foo/bar` marks all paths within the `@foo/bar` package as excluded, including sub-paths like `@foo/bar/baz`.",
119
119
  "type": "array",
120
120
  "items": { "type": "string" }
121
121
  }
@@ -671,6 +671,7 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
671
671
  templateUpdates,
672
672
  ssrMode,
673
673
  resetComponentUpdates: () => templateUpdates.clear(),
674
+ projectRoot: serverOptions.projectRoot,
674
675
  }),
675
676
  (0, plugins_1.createRemoveIdPrefixPlugin)(externalMetadata.explicitBrowser),
676
677
  await (0, plugins_1.createAngularSsrTransformPlugin)(serverOptions.workspaceRoot),
@@ -102,7 +102,7 @@ async function execute(options, context, extensions) {
102
102
  };
103
103
  const diagnostics = checkDuplicateMessages(
104
104
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
105
- checkFileSystem, extractionResult.messages, 'warning',
105
+ checkFileSystem, extractionResult.messages, normalizedOptions.i18nOptions.i18nDuplicateTranslation || 'warning',
106
106
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
107
107
  extractionResult.basePath);
108
108
  if (diagnostics.messages.length > 0) {
@@ -14,7 +14,6 @@ exports.default = default_1;
14
14
  const core_1 = require("@babel/core");
15
15
  const istanbul_lib_instrument_1 = require("istanbul-lib-instrument");
16
16
  const node_assert_1 = __importDefault(require("node:assert"));
17
- const node_url_1 = require("node:url");
18
17
  /**
19
18
  * A babel plugin factory function for adding istanbul instrumentation.
20
19
  *
@@ -26,15 +25,9 @@ function default_1() {
26
25
  visitor: {
27
26
  Program: {
28
27
  enter(path, state) {
29
- const inputSourceMap = // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
- state.file.inputMap?.toObject();
31
- // istanbul does not support URL as sources.
32
- if (inputSourceMap?.sources) {
33
- inputSourceMap.sources = inputSourceMap.sources.map((s) => s.startsWith('file://') ? (0, node_url_1.fileURLToPath)(s) : s);
34
- }
35
28
  const visitor = (0, istanbul_lib_instrument_1.programVisitor)(core_1.types, state.filename, {
36
29
  // Babel returns a Converter object from the `convert-source-map` package
37
- inputSourceMap,
30
+ inputSourceMap: state.file.inputMap?.toObject(),
38
31
  });
39
32
  visitors.set(path, visitor);
40
33
  visitor.enter(path);
@@ -47,7 +47,6 @@ exports.createCompilerPlugin = createCompilerPlugin;
47
47
  const node_assert_1 = __importDefault(require("node:assert"));
48
48
  const node_crypto_1 = require("node:crypto");
49
49
  const path = __importStar(require("node:path"));
50
- const node_url_1 = require("node:url");
51
50
  const environment_options_1 = require("../../../utils/environment-options");
52
51
  const compilation_1 = require("../../angular/compilation");
53
52
  const javascript_transformer_1 = require("../javascript-transformer");
@@ -543,10 +542,6 @@ function createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserve
543
542
  return {
544
543
  ...compilerOptions,
545
544
  noEmitOnError: false,
546
- // Using the path as a URL is necessary here; otherwise, esbuild will not generate source maps correctly.
547
- // https://github.com/evanw/esbuild/issues/4070
548
- // https://github.com/evanw/esbuild/issues/4075
549
- outDir: absWorkingDir ? (0, node_url_1.pathToFileURL)(absWorkingDir + '/').href : undefined,
550
545
  inlineSources: !!pluginOptions.sourcemap,
551
546
  inlineSourceMap: !!pluginOptions.sourcemap,
552
547
  sourceMap: undefined,
@@ -276,15 +276,13 @@ class BundlerContext {
276
276
  // Collect all external package names
277
277
  const externalImports = new Set();
278
278
  for (const { imports } of Object.values(result.metafile.outputs)) {
279
- for (const importData of imports) {
280
- if (!importData.external ||
281
- utils_1.SERVER_GENERATED_EXTERNALS.has(importData.path) ||
282
- (importData.kind !== 'import-statement' &&
283
- importData.kind !== 'dynamic-import' &&
284
- importData.kind !== 'require-call')) {
279
+ for (const { external, kind, path } of imports) {
280
+ if (!external ||
281
+ utils_1.SERVER_GENERATED_EXTERNALS.has(path) ||
282
+ (kind !== 'import-statement' && kind !== 'dynamic-import' && kind !== 'require-call')) {
285
283
  continue;
286
284
  }
287
- externalImports.add(importData.path);
285
+ externalImports.add(path);
288
286
  }
289
287
  }
290
288
  (0, node_assert_1.default)(this.#esbuildOptions, 'esbuild options cannot be undefined.');
@@ -74,7 +74,7 @@ export declare class ExecutionResult {
74
74
  * @param implicitServer External dependencies for the server bundles due to the external packages option.
75
75
  * @param explicit External dependencies due to explicit project configuration.
76
76
  */
77
- setExternalMetadata(implicitBrowser: string[], implicitServer: string[], explicit: string[] | undefined): void;
77
+ setExternalMetadata(implicitBrowser: string[], implicitServer: string[], explicit: string[]): void;
78
78
  get output(): {
79
79
  success: boolean;
80
80
  };
@@ -86,7 +86,7 @@ class ExecutionResult {
86
86
  * @param explicit External dependencies due to explicit project configuration.
87
87
  */
88
88
  setExternalMetadata(implicitBrowser, implicitServer, explicit) {
89
- this.externalMetadata = { implicitBrowser, implicitServer, explicit: explicit ?? [] };
89
+ this.externalMetadata = { implicitBrowser, implicitServer, explicit };
90
90
  }
91
91
  get output() {
92
92
  return {
@@ -18,7 +18,14 @@ const EXTERNAL_PACKAGE_RESOLUTION = Symbol('EXTERNAL_PACKAGE_RESOLUTION');
18
18
  * @returns An esbuild plugin.
19
19
  */
20
20
  function createExternalPackagesPlugin(options) {
21
- const exclusions = options?.exclude?.length ? new Set(options.exclude) : undefined;
21
+ const exclusions = new Set(options?.exclude);
22
+ // Similar to esbuild, --external:@foo/bar automatically implies --external:@foo/bar/*,
23
+ // which matches import paths like @foo/bar/baz.
24
+ // This means all paths within the @foo/bar package are also marked as external.
25
+ const exclusionsPrefixes = options?.exclude?.map((exclusion) => exclusion + '/') ?? [];
26
+ const seenExclusions = new Set();
27
+ const seenExternals = new Set();
28
+ const seenNonExclusions = new Set();
22
29
  return {
23
30
  name: 'angular-external-packages',
24
31
  setup(build) {
@@ -29,7 +36,7 @@ function createExternalPackagesPlugin(options) {
29
36
  .filter(([, value]) => value !== 'file')
30
37
  .map(([key]) => key);
31
38
  // Safe to use native packages external option if no loader options or exclusions present
32
- if (!exclusions && !loaderOptionKeys?.length) {
39
+ if (!exclusions.size && !loaderOptionKeys?.length) {
33
40
  build.initialOptions.packages = 'external';
34
41
  return;
35
42
  }
@@ -39,9 +46,21 @@ function createExternalPackagesPlugin(options) {
39
46
  if (args.pluginData?.[EXTERNAL_PACKAGE_RESOLUTION]) {
40
47
  return null;
41
48
  }
42
- if (exclusions?.has(args.path)) {
49
+ if (seenExternals.has(args.path)) {
50
+ return { external: true };
51
+ }
52
+ if (exclusions.has(args.path) || seenExclusions.has(args.path)) {
43
53
  return null;
44
54
  }
55
+ if (!seenNonExclusions.has(args.path)) {
56
+ for (const exclusion of exclusionsPrefixes) {
57
+ if (args.path.startsWith(exclusion)) {
58
+ seenExclusions.add(args.path);
59
+ return null;
60
+ }
61
+ }
62
+ seenNonExclusions.add(args.path);
63
+ }
45
64
  const { importer, kind, resolveDir, namespace, pluginData = {} } = args;
46
65
  pluginData[EXTERNAL_PACKAGE_RESOLUTION] = true;
47
66
  const result = await build.resolve(args.path, {
@@ -51,20 +70,23 @@ function createExternalPackagesPlugin(options) {
51
70
  pluginData,
52
71
  resolveDir,
53
72
  });
54
- // Return result if unable to resolve or explicitly marked external (externalDependencies option)
55
- if (!result.path || result.external) {
73
+ // Return result if unable to resolve
74
+ if (!result.path) {
56
75
  return result;
57
76
  }
77
+ // Return if explicitly marked external (externalDependencies option)
78
+ if (result.external) {
79
+ seenExternals.add(args.path);
80
+ return { external: true };
81
+ }
58
82
  // Allow customized loaders to run against configured paths regardless of location
59
83
  if (loaderFileExtensions.has((0, node_path_1.extname)(result.path))) {
60
84
  return result;
61
85
  }
62
86
  // Mark paths from a node modules directory as external
63
87
  if (/[\\/]node_modules[\\/]/.test(result.path)) {
64
- return {
65
- path: args.path,
66
- external: true,
67
- };
88
+ seenExternals.add(args.path);
89
+ return { external: true };
68
90
  }
69
91
  // Otherwise return original result
70
92
  return result;
@@ -42,8 +42,6 @@ var __importStar = (this && this.__importStar) || (function () {
42
42
  Object.defineProperty(exports, "__esModule", { value: true });
43
43
  exports.LessStylesheetLanguage = void 0;
44
44
  const promises_1 = require("node:fs/promises");
45
- const node_path_1 = require("node:path");
46
- const node_url_1 = require("node:url");
47
45
  /**
48
46
  * The lazy-loaded instance of the less stylesheet preprocessor.
49
47
  * It is only imported and initialized if a less stylesheet is used.
@@ -117,7 +115,7 @@ async function compileString(data, filename, options, resolver, unsafeInlineJava
117
115
  },
118
116
  };
119
117
  try {
120
- const { imports, map, css } = await less.render(data, {
118
+ const { imports, css } = await less.render(data, {
121
119
  filename,
122
120
  paths: options.includePaths,
123
121
  plugins: [resolverPlugin],
@@ -125,15 +123,13 @@ async function compileString(data, filename, options, resolver, unsafeInlineJava
125
123
  javascriptEnabled: unsafeInlineJavaScript,
126
124
  sourceMap: options.sourcemap
127
125
  ? {
128
- sourceMapFileInline: false,
126
+ sourceMapFileInline: true,
129
127
  outputSourceFiles: true,
130
128
  }
131
129
  : undefined,
132
130
  });
133
131
  return {
134
- // There can be cases where `less` will return an undefined `map` even
135
- // though the types do not specify this as a possibility.
136
- contents: map ? `${css}\n${sourceMapToUrlComment(map)}` : css,
132
+ contents: css,
137
133
  loader: 'css',
138
134
  watchFiles: [filename, ...imports],
139
135
  };
@@ -186,13 +182,3 @@ function convertExceptionLocation(exception) {
186
182
  lineText: exception.extract && exception.extract[Math.trunc(exception.extract.length / 2)],
187
183
  };
188
184
  }
189
- function sourceMapToUrlComment(sourceMap) {
190
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
191
- const map = JSON.parse(sourceMap);
192
- // Using file URLs instead of paths ensures that esbuild correctly resolves the source map.
193
- // https://github.com/evanw/esbuild/issues/4070
194
- // https://github.com/evanw/esbuild/issues/4075
195
- map.sources = map.sources.map((source) => source && (0, node_path_1.isAbsolute)(source) ? (0, node_url_1.pathToFileURL)(source).href : source);
196
- const urlSourceMap = Buffer.from(JSON.stringify(map), 'utf-8').toString('base64');
197
- return `/*# sourceMappingURL=data:application/json;charset=utf-8;base64,${urlSourceMap} */`;
198
- }
@@ -48,6 +48,7 @@ const node_assert_1 = __importDefault(require("node:assert"));
48
48
  const promises_1 = require("node:fs/promises");
49
49
  const node_path_1 = require("node:path");
50
50
  const tinyglobby_1 = require("tinyglobby");
51
+ const error_1 = require("../../../utils/error");
51
52
  const load_result_cache_1 = require("../load-result-cache");
52
53
  /**
53
54
  * The lazy-loaded instance of the postcss stylesheet postprocessor.
@@ -313,6 +314,15 @@ async function compileString(data, filename, postcssProcessor, options) {
313
314
  ],
314
315
  };
315
316
  }
316
- throw error;
317
+ else {
318
+ (0, error_1.assertIsError)(error);
319
+ return {
320
+ errors: [
321
+ {
322
+ text: error.message,
323
+ },
324
+ ],
325
+ };
326
+ }
317
327
  }
318
328
  }
@@ -0,0 +1,9 @@
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.dev/license
7
+ */
8
+ import type { Connect } from 'vite';
9
+ export declare function createChromeDevtoolsMiddleware(cacheDir: string, projectRoot: string): Connect.NextHandleFunction;
@@ -0,0 +1,52 @@
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.dev/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.createChromeDevtoolsMiddleware = createChromeDevtoolsMiddleware;
14
+ const node_assert_1 = __importDefault(require("node:assert"));
15
+ const node_crypto_1 = require("node:crypto");
16
+ const node_fs_1 = require("node:fs");
17
+ const node_path_1 = require("node:path");
18
+ const CHROME_DEVTOOLS_ROUTE = '/.well-known/appspecific/com.chrome.devtools.json';
19
+ function createChromeDevtoolsMiddleware(cacheDir, projectRoot) {
20
+ let devtoolsConfig;
21
+ const devtoolsConfigPath = (0, node_path_1.join)(cacheDir, 'com.chrome.devtools.json');
22
+ return function chromeDevtoolsMiddleware(req, res, next) {
23
+ if (req.url !== CHROME_DEVTOOLS_ROUTE) {
24
+ next();
25
+ return;
26
+ }
27
+ if (!devtoolsConfig) {
28
+ // We store the UUID and re-use it to ensure Chrome does not repeatedly ask for permissions when restarting the dev server.
29
+ try {
30
+ const devtoolsConfig = (0, node_fs_1.readFileSync)(devtoolsConfigPath, 'utf-8');
31
+ const devtoolsConfigJson = JSON.parse(devtoolsConfig);
32
+ node_assert_1.default.equal(projectRoot, devtoolsConfigJson?.workspace.root);
33
+ }
34
+ catch {
35
+ const devtoolsConfigJson = {
36
+ workspace: {
37
+ root: projectRoot,
38
+ uuid: (0, node_crypto_1.randomUUID)(),
39
+ },
40
+ };
41
+ devtoolsConfig = JSON.stringify(devtoolsConfigJson, undefined, 2);
42
+ try {
43
+ (0, node_fs_1.mkdirSync)(cacheDir, { recursive: true });
44
+ (0, node_fs_1.writeFileSync)(devtoolsConfigPath, devtoolsConfig);
45
+ }
46
+ catch { }
47
+ }
48
+ }
49
+ res.setHeader('Content-Type', 'application/json');
50
+ res.end(devtoolsConfig);
51
+ };
52
+ }
@@ -11,3 +11,4 @@ export { createAngularIndexHtmlMiddleware } from './index-html-middleware';
11
11
  export { createAngularSsrExternalMiddleware, createAngularSsrInternalMiddleware, } from './ssr-middleware';
12
12
  export { createAngularHeadersMiddleware } from './headers-middleware';
13
13
  export { createAngularComponentMiddleware } from './component-middleware';
14
+ export { createChromeDevtoolsMiddleware } from './chrome-devtools-middleware';
@@ -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
- exports.createAngularComponentMiddleware = exports.createAngularHeadersMiddleware = exports.createAngularSsrInternalMiddleware = exports.createAngularSsrExternalMiddleware = exports.createAngularIndexHtmlMiddleware = exports.angularHtmlFallbackMiddleware = exports.createAngularAssetsMiddleware = void 0;
10
+ exports.createChromeDevtoolsMiddleware = exports.createAngularComponentMiddleware = exports.createAngularHeadersMiddleware = exports.createAngularSsrInternalMiddleware = exports.createAngularSsrExternalMiddleware = exports.createAngularIndexHtmlMiddleware = exports.angularHtmlFallbackMiddleware = exports.createAngularAssetsMiddleware = void 0;
11
11
  var assets_middleware_1 = require("./assets-middleware");
12
12
  Object.defineProperty(exports, "createAngularAssetsMiddleware", { enumerable: true, get: function () { return assets_middleware_1.createAngularAssetsMiddleware; } });
13
13
  var html_fallback_middleware_1 = require("./html-fallback-middleware");
@@ -21,3 +21,5 @@ var headers_middleware_1 = require("./headers-middleware");
21
21
  Object.defineProperty(exports, "createAngularHeadersMiddleware", { enumerable: true, get: function () { return headers_middleware_1.createAngularHeadersMiddleware; } });
22
22
  var component_middleware_1 = require("./component-middleware");
23
23
  Object.defineProperty(exports, "createAngularComponentMiddleware", { enumerable: true, get: function () { return component_middleware_1.createAngularComponentMiddleware; } });
24
+ var chrome_devtools_middleware_1 = require("./chrome-devtools-middleware");
25
+ Object.defineProperty(exports, "createChromeDevtoolsMiddleware", { enumerable: true, get: function () { return chrome_devtools_middleware_1.createChromeDevtoolsMiddleware; } });
@@ -23,7 +23,7 @@ function createRemoveIdPrefixPlugin(externals) {
23
23
  if (externals.length === 0) {
24
24
  return;
25
25
  }
26
- const escapedExternals = externals.map(escapeRegexSpecialChars);
26
+ const escapedExternals = externals.map((e) => escapeRegexSpecialChars(e) + '(?:/.+)?');
27
27
  const prefixedExternalRegex = new RegExp(`${resolvedConfig.base}${VITE_ID_PREFIX}(${escapedExternals.join('|')})`, 'g');
28
28
  // @ts-expect-error: Property 'push' does not exist on type 'readonly Plugin<any>[]'
29
29
  // Reasoning:
@@ -39,6 +39,7 @@ interface AngularSetupMiddlewaresPluginOptions {
39
39
  templateUpdates: Map<string, string>;
40
40
  ssrMode: ServerSsrMode;
41
41
  resetComponentUpdates: () => void;
42
+ projectRoot: string;
42
43
  }
43
44
  export declare function createAngularSetupMiddlewaresPlugin(options: AngularSetupMiddlewaresPluginOptions): Plugin;
44
45
  export {};
@@ -51,6 +51,7 @@ function createAngularSetupMiddlewaresPlugin(options) {
51
51
  server.middlewares.use((0, middlewares_1.createAngularHeadersMiddleware)(server));
52
52
  server.middlewares.use((0, middlewares_1.createAngularComponentMiddleware)(server, templateUpdates));
53
53
  server.middlewares.use((0, middlewares_1.createAngularAssetsMiddleware)(server, assets, outputFiles, componentStyles, await createEncapsulateStyle()));
54
+ server.middlewares.use((0, middlewares_1.createChromeDevtoolsMiddleware)(server.config.cacheDir, options.projectRoot));
54
55
  extensionMiddleware?.forEach((middleware) => server.middlewares.use(middleware));
55
56
  // Returning a function, installs middleware after the main transform middleware but
56
57
  // before the built-in HTML middleware
@@ -5,6 +5,7 @@
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.dev/license
7
7
  */
8
+ import { DiagnosticHandlingStrategy } from '@angular/localize/tools';
8
9
  import type { TranslationLoader } from './load-translations';
9
10
  export interface LocaleDescription {
10
11
  files: {
@@ -24,6 +25,7 @@ export interface I18nOptions {
24
25
  flatOutput?: boolean;
25
26
  readonly shouldInline: boolean;
26
27
  hasDefinedSourceLocale?: boolean;
28
+ i18nDuplicateTranslation?: DiagnosticHandlingStrategy;
27
29
  }
28
30
  export declare function createI18nOptions(projectMetadata: {
29
31
  i18n?: unknown;
@@ -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 = '20.0.0-next.0';
13
+ const VERSION = '20.0.0-next.1';
14
14
  function hasCacheMetadata(value) {
15
15
  return (!!value &&
16
16
  typeof value === 'object' &&