@angular-devkit/build-angular 17.1.0-next.0 → 17.1.0-next.2
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 +22 -19
- package/src/builders/application/build-action.d.ts +1 -0
- package/src/builders/application/build-action.js +20 -12
- package/src/builders/application/execute-post-bundle.js +8 -4
- package/src/builders/application/index.js +9 -1
- package/src/builders/application/options.js +1 -1
- package/src/builders/browser-esbuild/builder-status-warnings.js +1 -3
- package/src/builders/dev-server/builder.js +5 -0
- package/src/builders/dev-server/vite-server.js +12 -5
- package/src/builders/karma/index.js +4 -1
- package/src/builders/karma/schema.d.ts +6 -2
- package/src/builders/karma/schema.json +12 -2
- package/src/builders/ssr-dev-server/index.js +27 -18
- package/src/tools/esbuild/angular/angular-host.js +6 -0
- package/src/tools/esbuild/angular/compiler-plugin.js +1 -1
- package/src/tools/esbuild/angular/component-stylesheets.js +1 -1
- package/src/tools/esbuild/angular/jit-plugin-callbacks.d.ts +2 -1
- package/src/tools/esbuild/angular/jit-plugin-callbacks.js +15 -15
- package/src/tools/esbuild/angular/source-file-cache.js +0 -1
- package/src/tools/esbuild/compiler-plugin-options.js +4 -2
- package/src/tools/esbuild/global-styles.js +4 -2
- package/src/tools/esbuild/i18n-locale-plugin.d.ts +4 -0
- package/src/tools/esbuild/i18n-locale-plugin.js +48 -18
- package/src/tools/esbuild/stylesheets/bundle-options.d.ts +3 -0
- package/src/tools/esbuild/stylesheets/bundle-options.js +11 -6
- package/src/tools/esbuild/stylesheets/css-inline-fonts-plugin.d.ts +25 -0
- package/src/tools/esbuild/stylesheets/css-inline-fonts-plugin.js +57 -0
- package/src/tools/esbuild/watcher.d.ts +1 -0
- package/src/tools/esbuild/watcher.js +56 -106
- package/src/tools/sass/rebasing-importer.js +29 -4
- package/src/utils/check-port.js +15 -29
- package/src/utils/delete-output-dir.d.ts +1 -1
- package/src/utils/delete-output-dir.js +11 -2
- package/src/utils/index-file/inline-fonts.d.ts +6 -1
- package/src/utils/index-file/inline-fonts.js +30 -14
- package/src/utils/server-rendering/esm-in-memory-loader/node-18-utils.js +6 -5
- package/src/utils/server-rendering/esm-in-memory-loader/register-hooks.js +1 -3
- package/src/utils/spinner.js +1 -1
|
@@ -16,6 +16,25 @@ const node_fs_1 = require("node:fs");
|
|
|
16
16
|
const node_path_1 = require("node:path");
|
|
17
17
|
const node_url_1 = require("node:url");
|
|
18
18
|
const lexer_1 = require("./lexer");
|
|
19
|
+
/**
|
|
20
|
+
* Ensures that a bare specifier URL path that is intended to be treated as
|
|
21
|
+
* a relative path has a leading `./` or `../` prefix.
|
|
22
|
+
*
|
|
23
|
+
* @param url A bare specifier URL path that should be considered relative.
|
|
24
|
+
* @returns
|
|
25
|
+
*/
|
|
26
|
+
function ensureRelative(url) {
|
|
27
|
+
// Empty
|
|
28
|
+
if (!url) {
|
|
29
|
+
return url;
|
|
30
|
+
}
|
|
31
|
+
// Already relative
|
|
32
|
+
if (url[0] === '.' && (url[1] === '/' || (url[1] === '.' && url[2] === '/'))) {
|
|
33
|
+
return url;
|
|
34
|
+
}
|
|
35
|
+
// Needs prefix
|
|
36
|
+
return './' + url;
|
|
37
|
+
}
|
|
19
38
|
/**
|
|
20
39
|
* A Sass Importer base class that provides the load logic to rebase all `url()` functions
|
|
21
40
|
* within a stylesheet. The rebasing will ensure that the URLs in the output of the Sass compiler
|
|
@@ -46,8 +65,13 @@ class UrlRebasingImporter {
|
|
|
46
65
|
// Rebase any URLs that are found
|
|
47
66
|
let updatedContents;
|
|
48
67
|
for (const { start, end, value } of (0, lexer_1.findUrls)(contents)) {
|
|
49
|
-
// Skip if value is empty
|
|
50
|
-
if (value.length === 0 || value[0] === '
|
|
68
|
+
// Skip if value is empty or Webpack-specific prefix
|
|
69
|
+
if (value.length === 0 || value[0] === '~' || value[0] === '^') {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
// Skip if value is a Sass variable.
|
|
73
|
+
// Sass variable usage either starts with a `$` or contains a namespace and a `.$`
|
|
74
|
+
if (value[0] === '$' || /^\w+\.\$/.test(value)) {
|
|
51
75
|
continue;
|
|
52
76
|
}
|
|
53
77
|
// Skip if root-relative, absolute or protocol relative url
|
|
@@ -57,9 +81,10 @@ class UrlRebasingImporter {
|
|
|
57
81
|
const rebasedPath = (0, node_path_1.relative)(this.entryDirectory, (0, node_path_1.join)(stylesheetDirectory, value));
|
|
58
82
|
// Normalize path separators and escape characters
|
|
59
83
|
// https://developer.mozilla.org/en-US/docs/Web/CSS/url#syntax
|
|
60
|
-
const rebasedUrl =
|
|
84
|
+
const rebasedUrl = ensureRelative(rebasedPath.replace(/\\/g, '/').replace(/[()\s'"]/g, '\\$&'));
|
|
61
85
|
updatedContents ??= new magic_string_1.default(contents);
|
|
62
|
-
|
|
86
|
+
// Always quote the URL to avoid potential downstream parsing problems
|
|
87
|
+
updatedContents.update(start, end, `"${rebasedUrl}"`);
|
|
63
88
|
}
|
|
64
89
|
if (updatedContents) {
|
|
65
90
|
contents = updatedContents.toString();
|
package/src/utils/check-port.js
CHANGED
|
@@ -6,43 +6,26 @@
|
|
|
6
6
|
* Use of this source code is governed by an MIT-style license that can be
|
|
7
7
|
* found in the LICENSE file at https://angular.io/license
|
|
8
8
|
*/
|
|
9
|
-
var
|
|
10
|
-
|
|
11
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
-
}
|
|
15
|
-
Object.defineProperty(o, k2, desc);
|
|
16
|
-
}) : (function(o, m, k, k2) {
|
|
17
|
-
if (k2 === undefined) k2 = k;
|
|
18
|
-
o[k2] = m[k];
|
|
19
|
-
}));
|
|
20
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
-
}) : function(o, v) {
|
|
23
|
-
o["default"] = v;
|
|
24
|
-
});
|
|
25
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
26
|
-
if (mod && mod.__esModule) return mod;
|
|
27
|
-
var result = {};
|
|
28
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
29
|
-
__setModuleDefault(result, mod);
|
|
30
|
-
return result;
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
31
11
|
};
|
|
32
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
13
|
exports.checkPort = void 0;
|
|
34
|
-
const
|
|
14
|
+
const node_assert_1 = __importDefault(require("node:assert"));
|
|
15
|
+
const node_net_1 = require("node:net");
|
|
35
16
|
const load_esm_1 = require("./load-esm");
|
|
36
17
|
const tty_1 = require("./tty");
|
|
37
18
|
function createInUseError(port) {
|
|
38
19
|
return new Error(`Port ${port} is already in use. Use '--port' to specify a different port.`);
|
|
39
20
|
}
|
|
40
21
|
async function checkPort(port, host) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
22
|
+
// Disabled due to Vite not handling port 0 and instead always using the default value (5173)
|
|
23
|
+
// TODO: Enable this again once Vite is fixed
|
|
24
|
+
// if (port === 0) {
|
|
25
|
+
// return 0;
|
|
26
|
+
// }
|
|
44
27
|
return new Promise((resolve, reject) => {
|
|
45
|
-
const server =
|
|
28
|
+
const server = (0, node_net_1.createServer)();
|
|
46
29
|
server
|
|
47
30
|
.once('error', (err) => {
|
|
48
31
|
if (err.code !== 'EADDRINUSE') {
|
|
@@ -60,11 +43,14 @@ async function checkPort(port, host) {
|
|
|
60
43
|
message: `Port ${port} is already in use.\nWould you like to use a different port?`,
|
|
61
44
|
default: true,
|
|
62
45
|
}))
|
|
63
|
-
.then((answers) =>
|
|
46
|
+
.then((answers) => answers.useDifferent ? resolve(checkPort(0, host)) : reject(createInUseError(port)), () => reject(createInUseError(port)));
|
|
64
47
|
})
|
|
65
48
|
.once('listening', () => {
|
|
49
|
+
// Get the actual address from the listening server instance
|
|
50
|
+
const address = server.address();
|
|
51
|
+
(0, node_assert_1.default)(address && typeof address !== 'string', 'Port check server address should always be an object.');
|
|
66
52
|
server.close();
|
|
67
|
-
resolve(port);
|
|
53
|
+
resolve(address.port);
|
|
68
54
|
})
|
|
69
55
|
.listen(port, host);
|
|
70
56
|
});
|
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
/**
|
|
9
9
|
* Delete an output directory, but error out if it's the root of the project.
|
|
10
10
|
*/
|
|
11
|
-
export declare function deleteOutputDir(root: string, outputPath: string): Promise<void>;
|
|
11
|
+
export declare function deleteOutputDir(root: string, outputPath: string, emptyOnlyDirectories?: string[]): Promise<void>;
|
|
@@ -13,11 +13,14 @@ const node_path_1 = require("node:path");
|
|
|
13
13
|
/**
|
|
14
14
|
* Delete an output directory, but error out if it's the root of the project.
|
|
15
15
|
*/
|
|
16
|
-
async function deleteOutputDir(root, outputPath) {
|
|
16
|
+
async function deleteOutputDir(root, outputPath, emptyOnlyDirectories) {
|
|
17
17
|
const resolvedOutputPath = (0, node_path_1.resolve)(root, outputPath);
|
|
18
18
|
if (resolvedOutputPath === root) {
|
|
19
19
|
throw new Error('Output path MUST not be project root directory!');
|
|
20
20
|
}
|
|
21
|
+
const directoriesToEmpty = emptyOnlyDirectories
|
|
22
|
+
? new Set(emptyOnlyDirectories.map((directory) => (0, node_path_1.join)(resolvedOutputPath, directory)))
|
|
23
|
+
: undefined;
|
|
21
24
|
// Avoid removing the actual directory to avoid errors in cases where the output
|
|
22
25
|
// directory is mounted or symlinked. Instead the contents are removed.
|
|
23
26
|
let entries;
|
|
@@ -31,7 +34,13 @@ async function deleteOutputDir(root, outputPath) {
|
|
|
31
34
|
throw error;
|
|
32
35
|
}
|
|
33
36
|
for (const entry of entries) {
|
|
34
|
-
|
|
37
|
+
const fullEntry = (0, node_path_1.join)(resolvedOutputPath, entry);
|
|
38
|
+
// Leave requested directories. This allows symlinks to continue to function.
|
|
39
|
+
if (directoriesToEmpty?.has(fullEntry)) {
|
|
40
|
+
await deleteOutputDir(resolvedOutputPath, fullEntry);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
await (0, promises_1.rm)(fullEntry, { force: true, recursive: true, maxRetries: 3 });
|
|
35
44
|
}
|
|
36
45
|
}
|
|
37
46
|
exports.deleteOutputDir = deleteOutputDir;
|
|
@@ -5,6 +5,10 @@
|
|
|
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
|
+
/// <reference types="node" />
|
|
9
|
+
/// <reference types="@types/node/url" />
|
|
10
|
+
/// <reference types="@types/node/ts4.8/url" />
|
|
11
|
+
import { URL } from 'node:url';
|
|
8
12
|
import { NormalizedCachedOptions } from '../normalize-cache';
|
|
9
13
|
export interface InlineFontsOptions {
|
|
10
14
|
minify?: boolean;
|
|
@@ -16,7 +20,8 @@ export declare class InlineFontsProcessor {
|
|
|
16
20
|
constructor(options: InlineFontsOptions);
|
|
17
21
|
process(content: string): Promise<string>;
|
|
18
22
|
private getResponse;
|
|
19
|
-
|
|
23
|
+
processURL(url: string | URL): Promise<string | undefined>;
|
|
24
|
+
canInlineRequest(url: string): boolean;
|
|
20
25
|
private getFontProviderDetails;
|
|
21
26
|
private createNormalizedUrl;
|
|
22
27
|
}
|
|
@@ -114,7 +114,7 @@ class InlineFontsProcessor {
|
|
|
114
114
|
if (!url) {
|
|
115
115
|
continue;
|
|
116
116
|
}
|
|
117
|
-
const content = await this.
|
|
117
|
+
const content = await this.processURL(url);
|
|
118
118
|
if (content === undefined) {
|
|
119
119
|
continue;
|
|
120
120
|
}
|
|
@@ -195,7 +195,16 @@ class InlineFontsProcessor {
|
|
|
195
195
|
.get(url, {
|
|
196
196
|
agent,
|
|
197
197
|
headers: {
|
|
198
|
-
|
|
198
|
+
/**
|
|
199
|
+
* Always use a Windows UA. This is because Google fonts will including hinting in fonts for Windows.
|
|
200
|
+
* Hinting is a technique used with Windows files to improve appearance however
|
|
201
|
+
* results in 20-50% larger file sizes.
|
|
202
|
+
*
|
|
203
|
+
* @see http://google3/java/com/google/fonts/css/OpenSansWebFontsCssBuilder.java?l=22
|
|
204
|
+
* @see https://fonts.google.com/knowledge/glossary/hinting (short)
|
|
205
|
+
* @see https://glyphsapp.com/learn/hinting-manual-truetype-hinting (deep dive)
|
|
206
|
+
*/
|
|
207
|
+
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
199
208
|
},
|
|
200
209
|
}, (res) => {
|
|
201
210
|
if (res.statusCode !== 200) {
|
|
@@ -216,12 +225,16 @@ class InlineFontsProcessor {
|
|
|
216
225
|
}
|
|
217
226
|
return data;
|
|
218
227
|
}
|
|
219
|
-
async
|
|
220
|
-
const
|
|
228
|
+
async processURL(url) {
|
|
229
|
+
const normalizedURL = url instanceof node_url_1.URL ? url : this.createNormalizedUrl(url);
|
|
230
|
+
if (!normalizedURL) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const provider = this.getFontProviderDetails(normalizedURL);
|
|
221
234
|
if (!provider) {
|
|
222
235
|
return undefined;
|
|
223
236
|
}
|
|
224
|
-
let cssContent = await this.getResponse(
|
|
237
|
+
let cssContent = await this.getResponse(normalizedURL);
|
|
225
238
|
if (this.options.minify) {
|
|
226
239
|
cssContent = cssContent
|
|
227
240
|
// Comments.
|
|
@@ -233,21 +246,24 @@ class InlineFontsProcessor {
|
|
|
233
246
|
}
|
|
234
247
|
return cssContent;
|
|
235
248
|
}
|
|
249
|
+
canInlineRequest(url) {
|
|
250
|
+
const normalizedUrl = this.createNormalizedUrl(url);
|
|
251
|
+
return normalizedUrl ? !!this.getFontProviderDetails(normalizedUrl) : false;
|
|
252
|
+
}
|
|
236
253
|
getFontProviderDetails(url) {
|
|
237
254
|
return SUPPORTED_PROVIDERS[url.hostname];
|
|
238
255
|
}
|
|
239
256
|
createNormalizedUrl(value) {
|
|
240
257
|
// Need to convert '//' to 'https://' because the URL parser will fail with '//'.
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
258
|
+
const url = new node_url_1.URL(value.startsWith('//') ? `https:${value}` : value, 'resolve://');
|
|
259
|
+
switch (url.protocol) {
|
|
260
|
+
case 'http:':
|
|
261
|
+
case 'https:':
|
|
262
|
+
url.protocol = 'https:';
|
|
263
|
+
return url;
|
|
264
|
+
default:
|
|
265
|
+
return undefined;
|
|
246
266
|
}
|
|
247
|
-
const url = new node_url_1.URL(normalizedHref);
|
|
248
|
-
// Force HTTPS protocol
|
|
249
|
-
url.protocol = 'https:';
|
|
250
|
-
return url;
|
|
251
267
|
}
|
|
252
268
|
}
|
|
253
269
|
exports.InlineFontsProcessor = InlineFontsProcessor;
|
|
@@ -11,19 +11,20 @@ exports.getESMLoaderArgs = exports.callInitializeIfNeeded = void 0;
|
|
|
11
11
|
const node_path_1 = require("node:path");
|
|
12
12
|
const node_url_1 = require("node:url");
|
|
13
13
|
const node_worker_threads_1 = require("node:worker_threads");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
const semver_1 = require("semver");
|
|
15
|
+
let SUPPORTS_IMPORT_FLAG;
|
|
16
|
+
function supportsImportFlag() {
|
|
17
|
+
return (SUPPORTS_IMPORT_FLAG ??= (0, semver_1.satisfies)(process.versions.node, '>= 18.19'));
|
|
17
18
|
}
|
|
18
19
|
/** Call the initialize hook when running on Node.js 18 */
|
|
19
20
|
function callInitializeIfNeeded(initialize) {
|
|
20
|
-
if (
|
|
21
|
+
if (!supportsImportFlag()) {
|
|
21
22
|
initialize(node_worker_threads_1.workerData);
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
exports.callInitializeIfNeeded = callInitializeIfNeeded;
|
|
25
26
|
function getESMLoaderArgs() {
|
|
26
|
-
if (
|
|
27
|
+
if (!supportsImportFlag()) {
|
|
27
28
|
return [
|
|
28
29
|
'--no-warnings', // Suppress `ExperimentalWarning: Custom ESM Loaders is an experimental feature...`.
|
|
29
30
|
'--loader',
|
|
@@ -7,9 +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
|
-
// TODO: remove the below once @types/node are version 20.x.x
|
|
11
|
-
// @ts-expect-error "node:module"' has no exported member 'register'.ts(2305)
|
|
12
10
|
const node_module_1 = require("node:module");
|
|
13
11
|
const node_url_1 = require("node:url");
|
|
14
12
|
const node_worker_threads_1 = require("node:worker_threads");
|
|
15
|
-
(0, node_module_1.register)('./loader-hooks.js', (0, node_url_1.pathToFileURL)(__filename),
|
|
13
|
+
(0, node_module_1.register)('./loader-hooks.js', { parentURL: (0, node_url_1.pathToFileURL)(__filename), data: node_worker_threads_1.workerData });
|
package/src/utils/spinner.js
CHANGED
|
@@ -21,7 +21,7 @@ class Spinner {
|
|
|
21
21
|
#isTTY = (0, tty_1.isTTY)();
|
|
22
22
|
constructor(text) {
|
|
23
23
|
this.spinner = (0, ora_1.default)({
|
|
24
|
-
text,
|
|
24
|
+
text: text === undefined ? undefined : text + '\n',
|
|
25
25
|
// The below 2 options are needed because otherwise CTRL+C will be delayed
|
|
26
26
|
// when the underlying process is sync.
|
|
27
27
|
hideCursor: false,
|