@angular/build 20.3.10 → 20.3.12

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": "20.3.10",
3
+ "version": "20.3.12",
4
4
  "description": "Official build system for Angular",
5
5
  "keywords": [
6
6
  "Angular CLI",
@@ -23,7 +23,7 @@
23
23
  "builders": "builders.json",
24
24
  "dependencies": {
25
25
  "@ampproject/remapping": "2.3.0",
26
- "@angular-devkit/architect": "0.2003.10",
26
+ "@angular-devkit/architect": "0.2003.12",
27
27
  "@babel/core": "7.28.3",
28
28
  "@babel/helper-annotate-as-pure": "7.27.3",
29
29
  "@babel/helper-split-export-declaration": "7.24.7",
@@ -60,7 +60,7 @@
60
60
  "@angular/platform-browser": "^20.0.0",
61
61
  "@angular/platform-server": "^20.0.0",
62
62
  "@angular/service-worker": "^20.0.0",
63
- "@angular/ssr": "^20.3.10",
63
+ "@angular/ssr": "^20.3.12",
64
64
  "karma": "^6.4.0",
65
65
  "less": "^4.2.0",
66
66
  "ng-packagr": "^20.0.0",
@@ -449,7 +449,9 @@ function getLocaleBaseHref(baseHref = '', i18n, locale) {
449
449
  return undefined;
450
450
  }
451
451
  const baseHrefSuffix = localeData.baseHref ?? localeData.subPath + '/';
452
- return baseHrefSuffix !== '' ? (0, url_1.urlJoin)(baseHref, baseHrefSuffix) : undefined;
452
+ return baseHrefSuffix !== ''
453
+ ? (0, url_1.addTrailingSlash)((0, url_1.joinUrlParts)(baseHref, baseHrefSuffix))
454
+ : undefined;
453
455
  }
454
456
  /**
455
457
  * Normalizes an array of external dependency paths by ensuring that
@@ -423,9 +423,10 @@ async function invalidateUpdatedFiles(normalizePath, generatedFiles, assetFiles,
423
423
  updatedModules?.forEach((m) => server.moduleGraph.invalidateModule(m));
424
424
  }
425
425
  if (serverApplicationChanged) {
426
- // Clear the server app cache and
427
- // trigger module evaluation before reload to initiate dependency optimization.
428
- const { ɵdestroyAngularServerApp } = (await server.ssrLoadModule('/main.server.mjs'));
426
+ // Clear the server app cache and trigger module evaluation before reload to initiate dependency optimization.
427
+ // The querystring is needed as a workaround for:
428
+ // `ɵgetOrCreateAngularServerApp` can be undefined right after an error.
429
+ const { ɵdestroyAngularServerApp } = (await server.ssrLoadModule(`/main.server.mjs?timestamp=${Date.now()}`));
429
430
  ɵdestroyAngularServerApp();
430
431
  }
431
432
  return updatedFiles;
@@ -23,11 +23,6 @@ function createAngularSsrInternalMiddleware(server, indexHtmlTransformer) {
23
23
  await (0, load_esm_1.loadEsmModule)('@angular/compiler');
24
24
  const { writeResponseToNodeResponse, createWebRequestFromNodeRequest } = await (0, load_esm_1.loadEsmModule)('@angular/ssr/node');
25
25
  const { ɵgetOrCreateAngularServerApp } = (await server.ssrLoadModule('/main.server.mjs'));
26
- // `ɵgetOrCreateAngularServerApp` can be undefined right after an error.
27
- // See: https://github.com/angular/angular-cli/issues/29907
28
- if (!ɵgetOrCreateAngularServerApp) {
29
- return next();
30
- }
31
26
  const angularServerApp = ɵgetOrCreateAngularServerApp({
32
27
  allowStaticRouteRender: true,
33
28
  });
@@ -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.3.10';
13
+ const VERSION = '20.3.12';
14
14
  function hasCacheMetadata(value) {
15
15
  return (!!value &&
16
16
  typeof value === 'object' &&
@@ -51,7 +51,7 @@ async function prerenderPages(workspaceRoot, baseHref, appShellOptions, prerende
51
51
  serverBundlesSourceMaps.clear();
52
52
  const assetsReversed = {};
53
53
  for (const { source, destination } of assets) {
54
- assetsReversed[addLeadingSlash((0, path_1.toPosixPath)(destination))] = source;
54
+ assetsReversed[(0, url_1.addLeadingSlash)((0, path_1.toPosixPath)(destination))] = source;
55
55
  }
56
56
  // Get routes to prerender
57
57
  const { errors: extractionErrors, serializedRouteTree: serializableRouteTreeNode, appShellRoute, } = await getAllRoutes(workspaceRoot, baseHref, outputFilesForWorker, assetsReversed, appShellOptions, prerenderOptions, sourcemap, outputMode).catch((err) => {
@@ -129,14 +129,14 @@ async function renderPages(baseHref, sourcemap, serializableRouteTreeNode, maxTh
129
129
  });
130
130
  try {
131
131
  const renderingPromises = [];
132
- const appShellRouteWithLeadingSlash = appShellRoute && addLeadingSlash(appShellRoute);
132
+ const appShellRouteWithLeadingSlash = appShellRoute && (0, url_1.addLeadingSlash)(appShellRoute);
133
133
  const baseHrefPathnameWithLeadingSlash = new URL(baseHref, 'http://localhost').pathname;
134
134
  for (const { route, redirectTo } of serializableRouteTreeNode) {
135
135
  // Remove the base href from the file output path.
136
- const routeWithoutBaseHref = addTrailingSlash(route).startsWith(baseHrefPathnameWithLeadingSlash)
137
- ? addLeadingSlash(route.slice(baseHrefPathnameWithLeadingSlash.length))
136
+ const routeWithoutBaseHref = (0, url_1.addTrailingSlash)(route).startsWith(baseHrefPathnameWithLeadingSlash)
137
+ ? (0, url_1.addLeadingSlash)(route.slice(baseHrefPathnameWithLeadingSlash.length))
138
138
  : route;
139
- const outPath = node_path_1.posix.join(removeLeadingSlash(routeWithoutBaseHref), 'index.html');
139
+ const outPath = (0, url_1.stripLeadingSlash)(node_path_1.posix.join(routeWithoutBaseHref, 'index.html'));
140
140
  if (typeof redirectTo === 'string') {
141
141
  output[outPath] = { content: (0, utils_2.generateRedirectStaticPage)(redirectTo), appShellRoute: false };
142
142
  continue;
@@ -172,7 +172,7 @@ async function getAllRoutes(workspaceRoot, baseHref, outputFilesForWorker, asset
172
172
  const routes = [];
173
173
  let appShellRoute;
174
174
  if (appShellOptions) {
175
- appShellRoute = (0, url_1.urlJoin)(baseHref, appShellOptions.route);
175
+ appShellRoute = (0, url_1.joinUrlParts)(baseHref, appShellOptions.route);
176
176
  routes.push({
177
177
  renderMode: models_1.RouteRenderMode.Prerender,
178
178
  route: appShellRoute,
@@ -183,7 +183,7 @@ async function getAllRoutes(workspaceRoot, baseHref, outputFilesForWorker, asset
183
183
  for (const route of routesFromFile) {
184
184
  routes.push({
185
185
  renderMode: models_1.RouteRenderMode.Prerender,
186
- route: (0, url_1.urlJoin)(baseHref, route.trim()),
186
+ route: (0, url_1.joinUrlParts)(baseHref, route.trim()),
187
187
  });
188
188
  }
189
189
  }
@@ -233,12 +233,3 @@ async function getAllRoutes(workspaceRoot, baseHref, outputFilesForWorker, asset
233
233
  void renderWorker.destroy();
234
234
  }
235
235
  }
236
- function addLeadingSlash(value) {
237
- return value[0] === '/' ? value : '/' + value;
238
- }
239
- function addTrailingSlash(url) {
240
- return url[url.length - 1] === '/' ? url : `${url}/`;
241
- }
242
- function removeLeadingSlash(value) {
243
- return value[0] === '/' ? value.slice(1) : value;
244
- }
@@ -5,4 +5,77 @@
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
- export declare function urlJoin(...parts: string[]): string;
8
+ /**
9
+ * Removes the trailing slash from a URL if it exists.
10
+ *
11
+ * @param url - The URL string from which to remove the trailing slash.
12
+ * @returns The URL string without a trailing slash.
13
+ *
14
+ * @example
15
+ * ```js
16
+ * stripTrailingSlash('path/'); // 'path'
17
+ * stripTrailingSlash('/path'); // '/path'
18
+ * stripTrailingSlash('/'); // '/'
19
+ * stripTrailingSlash(''); // ''
20
+ * ```
21
+ */
22
+ export declare function stripTrailingSlash(url: string): string;
23
+ /**
24
+ * Removes the leading slash from a URL if it exists.
25
+ *
26
+ * @param url - The URL string from which to remove the leading slash.
27
+ * @returns The URL string without a leading slash.
28
+ *
29
+ * @example
30
+ * ```js
31
+ * stripLeadingSlash('/path'); // 'path'
32
+ * stripLeadingSlash('/path/'); // 'path/'
33
+ * stripLeadingSlash('/'); // '/'
34
+ * stripLeadingSlash(''); // ''
35
+ * ```
36
+ */
37
+ export declare function stripLeadingSlash(url: string): string;
38
+ /**
39
+ * Adds a leading slash to a URL if it does not already have one.
40
+ *
41
+ * @param url - The URL string to which the leading slash will be added.
42
+ * @returns The URL string with a leading slash.
43
+ *
44
+ * @example
45
+ * ```js
46
+ * addLeadingSlash('path'); // '/path'
47
+ * addLeadingSlash('/path'); // '/path'
48
+ * ```
49
+ */
50
+ export declare function addLeadingSlash(url: string): string;
51
+ /**
52
+ * Adds a trailing slash to a URL if it does not already have one.
53
+ *
54
+ * @param url - The URL string to which the trailing slash will be added.
55
+ * @returns The URL string with a trailing slash.
56
+ *
57
+ * @example
58
+ * ```js
59
+ * addTrailingSlash('path'); // 'path/'
60
+ * addTrailingSlash('path/'); // 'path/'
61
+ * ```
62
+ */
63
+ export declare function addTrailingSlash(url: string): string;
64
+ /**
65
+ * Joins URL parts into a single URL string.
66
+ *
67
+ * This function takes multiple URL segments, normalizes them by removing leading
68
+ * and trailing slashes where appropriate, and then joins them into a single URL.
69
+ *
70
+ * @param parts - The parts of the URL to join. Each part can be a string with or without slashes.
71
+ * @returns The joined URL string, with normalized slashes.
72
+ *
73
+ * @example
74
+ * ```js
75
+ * joinUrlParts('path/', '/to/resource'); // '/path/to/resource'
76
+ * joinUrlParts('/path/', 'to/resource'); // '/path/to/resource'
77
+ * joinUrlParts('http://localhost/path/', 'to/resource'); // 'http://localhost/path/to/resource'
78
+ * joinUrlParts('', ''); // '/'
79
+ * ```
80
+ */
81
+ export declare function joinUrlParts(...parts: string[]): string;
package/src/utils/url.js CHANGED
@@ -7,11 +7,115 @@
7
7
  * found in the LICENSE file at https://angular.dev/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.urlJoin = urlJoin;
11
- function urlJoin(...parts) {
12
- const [p, ...rest] = parts;
13
- // Remove trailing slash from first part
14
- // Join all parts with `/`
15
- // Dedupe double slashes from path names
16
- return p.replace(/\/$/, '') + ('/' + rest.join('/')).replace(/\/\/+/g, '/');
10
+ exports.stripTrailingSlash = stripTrailingSlash;
11
+ exports.stripLeadingSlash = stripLeadingSlash;
12
+ exports.addLeadingSlash = addLeadingSlash;
13
+ exports.addTrailingSlash = addTrailingSlash;
14
+ exports.joinUrlParts = joinUrlParts;
15
+ /**
16
+ * Removes the trailing slash from a URL if it exists.
17
+ *
18
+ * @param url - The URL string from which to remove the trailing slash.
19
+ * @returns The URL string without a trailing slash.
20
+ *
21
+ * @example
22
+ * ```js
23
+ * stripTrailingSlash('path/'); // 'path'
24
+ * stripTrailingSlash('/path'); // '/path'
25
+ * stripTrailingSlash('/'); // '/'
26
+ * stripTrailingSlash(''); // ''
27
+ * ```
28
+ */
29
+ function stripTrailingSlash(url) {
30
+ // Check if the last character of the URL is a slash
31
+ return url.length > 1 && url[url.length - 1] === '/' ? url.slice(0, -1) : url;
32
+ }
33
+ /**
34
+ * Removes the leading slash from a URL if it exists.
35
+ *
36
+ * @param url - The URL string from which to remove the leading slash.
37
+ * @returns The URL string without a leading slash.
38
+ *
39
+ * @example
40
+ * ```js
41
+ * stripLeadingSlash('/path'); // 'path'
42
+ * stripLeadingSlash('/path/'); // 'path/'
43
+ * stripLeadingSlash('/'); // '/'
44
+ * stripLeadingSlash(''); // ''
45
+ * ```
46
+ */
47
+ function stripLeadingSlash(url) {
48
+ // Check if the first character of the URL is a slash
49
+ return url.length > 1 && url[0] === '/' ? url.slice(1) : url;
50
+ }
51
+ /**
52
+ * Adds a leading slash to a URL if it does not already have one.
53
+ *
54
+ * @param url - The URL string to which the leading slash will be added.
55
+ * @returns The URL string with a leading slash.
56
+ *
57
+ * @example
58
+ * ```js
59
+ * addLeadingSlash('path'); // '/path'
60
+ * addLeadingSlash('/path'); // '/path'
61
+ * ```
62
+ */
63
+ function addLeadingSlash(url) {
64
+ // Check if the URL already starts with a slash
65
+ return url[0] === '/' ? url : `/${url}`;
66
+ }
67
+ /**
68
+ * Adds a trailing slash to a URL if it does not already have one.
69
+ *
70
+ * @param url - The URL string to which the trailing slash will be added.
71
+ * @returns The URL string with a trailing slash.
72
+ *
73
+ * @example
74
+ * ```js
75
+ * addTrailingSlash('path'); // 'path/'
76
+ * addTrailingSlash('path/'); // 'path/'
77
+ * ```
78
+ */
79
+ function addTrailingSlash(url) {
80
+ // Check if the URL already end with a slash
81
+ return url[url.length - 1] === '/' ? url : `${url}/`;
82
+ }
83
+ /**
84
+ * Joins URL parts into a single URL string.
85
+ *
86
+ * This function takes multiple URL segments, normalizes them by removing leading
87
+ * and trailing slashes where appropriate, and then joins them into a single URL.
88
+ *
89
+ * @param parts - The parts of the URL to join. Each part can be a string with or without slashes.
90
+ * @returns The joined URL string, with normalized slashes.
91
+ *
92
+ * @example
93
+ * ```js
94
+ * joinUrlParts('path/', '/to/resource'); // '/path/to/resource'
95
+ * joinUrlParts('/path/', 'to/resource'); // '/path/to/resource'
96
+ * joinUrlParts('http://localhost/path/', 'to/resource'); // 'http://localhost/path/to/resource'
97
+ * joinUrlParts('', ''); // '/'
98
+ * ```
99
+ */
100
+ function joinUrlParts(...parts) {
101
+ const normalizeParts = [];
102
+ for (const part of parts) {
103
+ if (part === '') {
104
+ // Skip any empty parts
105
+ continue;
106
+ }
107
+ let normalizedPart = part;
108
+ if (part[0] === '/') {
109
+ normalizedPart = normalizedPart.slice(1);
110
+ }
111
+ if (part[part.length - 1] === '/') {
112
+ normalizedPart = normalizedPart.slice(0, -1);
113
+ }
114
+ if (normalizedPart !== '') {
115
+ normalizeParts.push(normalizedPart);
116
+ }
117
+ }
118
+ const protocolMatch = normalizeParts.length && /^https?:\/\//.test(normalizeParts[0]);
119
+ const joinedParts = normalizeParts.join('/');
120
+ return protocolMatch ? joinedParts : addLeadingSlash(joinedParts);
17
121
  }