@angular-devkit/build-angular 17.1.0 → 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 +27 -27
- package/src/builders/dev-server/options.js +3 -2
- package/src/builders/dev-server/schema.json +1 -1
- package/src/builders/dev-server/vite-server.js +14 -213
- package/src/builders/extract-i18n/options.js +3 -2
- package/src/builders/extract-i18n/schema.json +1 -1
- package/src/builders/jest/index.js +44 -5
- package/src/builders/jest/jest.config.mjs +11 -0
- package/src/builders/prerender/routes-extractor-worker.js +1 -1
- package/src/tools/esbuild/angular/compilation/angular-compilation.d.ts +9 -2
- package/src/tools/esbuild/angular/compilation/angular-compilation.js +11 -3
- package/src/tools/esbuild/angular/compilation/aot-compilation.d.ts +2 -2
- package/src/tools/esbuild/angular/compilation/aot-compilation.js +19 -8
- package/src/tools/esbuild/angular/compilation/index.d.ts +1 -1
- package/src/tools/esbuild/angular/compilation/index.js +2 -1
- package/src/tools/esbuild/angular/compilation/jit-compilation.d.ts +2 -2
- package/src/tools/esbuild/angular/compilation/jit-compilation.js +12 -6
- package/src/tools/esbuild/angular/compilation/parallel-compilation.d.ts +2 -2
- package/src/tools/esbuild/angular/compilation/parallel-compilation.js +2 -2
- package/src/tools/esbuild/angular/compilation/parallel-worker.d.ts +2 -1
- package/src/tools/esbuild/angular/compilation/parallel-worker.js +2 -2
- package/src/tools/esbuild/angular/compiler-plugin.js +7 -7
- package/src/tools/esbuild/angular/component-stylesheets.js +10 -8
- package/src/tools/esbuild/application-code-bundle.js +12 -3
- package/src/tools/esbuild/bundler-context.js +12 -8
- package/src/tools/esbuild/external-packages-plugin.d.ts +16 -0
- package/src/tools/esbuild/external-packages-plugin.js +66 -0
- package/src/tools/esbuild/stylesheets/css-resource-plugin.js +3 -2
- package/src/tools/vite/angular-memory-plugin.d.ts +24 -0
- package/src/tools/vite/angular-memory-plugin.js +252 -0
- package/src/utils/environment-options.d.ts +1 -0
- package/src/utils/environment-options.js +3 -1
- package/src/utils/index-file/inline-critical-css.js +28 -20
- package/src/utils/server-rendering/render-page.js +5 -0
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular-devkit/build-angular",
|
|
3
|
-
"version": "17.
|
|
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.
|
|
11
|
-
"@angular-devkit/build-webpack": "0.
|
|
12
|
-
"@angular-devkit/core": "17.
|
|
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,53 +17,53 @@
|
|
|
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.
|
|
21
|
-
"@babel/runtime": "7.23.
|
|
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.
|
|
24
|
-
"@vitejs/plugin-basic-ssl": "1.0
|
|
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.
|
|
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": "
|
|
30
|
+
"copy-webpack-plugin": "12.0.2",
|
|
31
31
|
"critters": "0.0.20",
|
|
32
|
-
"css-loader": "6.
|
|
33
|
-
"esbuild-wasm": "0.19.
|
|
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.
|
|
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.
|
|
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.
|
|
51
|
+
"piscina": "4.3.0",
|
|
52
52
|
"postcss": "8.4.33",
|
|
53
|
-
"postcss-loader": "
|
|
53
|
+
"postcss-loader": "8.0.0",
|
|
54
54
|
"resolve-url-loader": "5.0.0",
|
|
55
55
|
"rxjs": "7.8.1",
|
|
56
|
-
"sass": "1.
|
|
57
|
-
"sass-loader": "
|
|
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.
|
|
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.
|
|
66
|
-
"vite": "5.0.
|
|
65
|
+
"undici": "6.4.0",
|
|
66
|
+
"vite": "5.0.12",
|
|
67
67
|
"watchpack": "2.4.0",
|
|
68
68
|
"webpack": "5.89.0",
|
|
69
69
|
"webpack-dev-middleware": "6.1.1",
|
|
@@ -72,19 +72,19 @@
|
|
|
72
72
|
"webpack-subresource-integrity": "5.1.0"
|
|
73
73
|
},
|
|
74
74
|
"optionalDependencies": {
|
|
75
|
-
"esbuild": "0.19.
|
|
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
|
-
//
|
|
33
|
-
const
|
|
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]
|
|
16
|
+
"pattern": "^[^:\\s]*:[^:\\s]*(:[^\\s]+)?$"
|
|
17
17
|
},
|
|
18
18
|
"port": {
|
|
19
19
|
"type": "number",
|
|
@@ -34,8 +34,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
34
34
|
};
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.setupServer = exports.serveWithVite = void 0;
|
|
37
|
-
const remapping_1 = __importDefault(require("@ampproject/remapping"));
|
|
38
|
-
const mrmime_1 = require("mrmime");
|
|
39
37
|
const node_assert_1 = __importDefault(require("node:assert"));
|
|
40
38
|
const promises_1 = require("node:fs/promises");
|
|
41
39
|
const node_path_1 = require("node:path");
|
|
@@ -43,10 +41,10 @@ const bundler_context_1 = require("../../tools/esbuild/bundler-context");
|
|
|
43
41
|
const javascript_transformer_1 = require("../../tools/esbuild/javascript-transformer");
|
|
44
42
|
const rxjs_esm_resolution_plugin_1 = require("../../tools/esbuild/rxjs-esm-resolution-plugin");
|
|
45
43
|
const utils_1 = require("../../tools/esbuild/utils");
|
|
44
|
+
const angular_memory_plugin_1 = require("../../tools/vite/angular-memory-plugin");
|
|
46
45
|
const i18n_locale_plugin_1 = require("../../tools/vite/i18n-locale-plugin");
|
|
47
46
|
const utils_2 = require("../../utils");
|
|
48
47
|
const load_esm_1 = require("../../utils/load-esm");
|
|
49
|
-
const render_page_1 = require("../../utils/server-rendering/render-page");
|
|
50
48
|
const supported_browsers_1 = require("../../utils/supported-browsers");
|
|
51
49
|
const webpack_browser_config_1 = require("../../utils/webpack-browser-config");
|
|
52
50
|
const application_1 = require("../application");
|
|
@@ -324,7 +322,6 @@ function analyzeResultFiles(normalizePath, htmlIndexPath, resultFiles, generated
|
|
|
324
322
|
}
|
|
325
323
|
}
|
|
326
324
|
}
|
|
327
|
-
// eslint-disable-next-line max-lines-per-function
|
|
328
325
|
async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks, externalMetadata, ssr, prebundleTransformer, target, prebundleLoaderExtensions, extensionMiddleware, indexHtmlTransformer, thirdPartySourcemaps = false) {
|
|
329
326
|
const proxy = await (0, utils_2.loadProxyConfiguration)(serverOptions.workspaceRoot, serverOptions.proxyConfig, true);
|
|
330
327
|
// dynamically import Vite for ESM compatibility
|
|
@@ -344,7 +341,7 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
|
|
|
344
341
|
publicDir: false,
|
|
345
342
|
esbuild: false,
|
|
346
343
|
mode: 'development',
|
|
347
|
-
appType: '
|
|
344
|
+
appType: 'mpa',
|
|
348
345
|
css: {
|
|
349
346
|
devSourcemap: true,
|
|
350
347
|
},
|
|
@@ -409,189 +406,18 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
|
|
|
409
406
|
},
|
|
410
407
|
plugins: [
|
|
411
408
|
(0, i18n_locale_plugin_1.createAngularLocaleDataPlugin)(),
|
|
412
|
-
{
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
// Remove query if present
|
|
425
|
-
const [importerFile] = importer.split('?', 1);
|
|
426
|
-
source =
|
|
427
|
-
'/' +
|
|
428
|
-
normalizePath((0, node_path_1.join)((0, node_path_1.dirname)((0, node_path_1.relative)(virtualProjectRoot, importerFile)), source));
|
|
429
|
-
}
|
|
430
|
-
const [file] = source.split('?', 1);
|
|
431
|
-
if (outputFiles.has(file)) {
|
|
432
|
-
return (0, node_path_1.join)(virtualProjectRoot, source);
|
|
433
|
-
}
|
|
434
|
-
},
|
|
435
|
-
load(id) {
|
|
436
|
-
const [file] = id.split('?', 1);
|
|
437
|
-
const relativeFile = '/' + normalizePath((0, node_path_1.relative)(virtualProjectRoot, file));
|
|
438
|
-
const codeContents = outputFiles.get(relativeFile)?.contents;
|
|
439
|
-
if (codeContents === undefined) {
|
|
440
|
-
if (relativeFile.endsWith('/node_modules/vite/dist/client/client.mjs')) {
|
|
441
|
-
return loadViteClientCode(file);
|
|
442
|
-
}
|
|
443
|
-
return;
|
|
444
|
-
}
|
|
445
|
-
const code = Buffer.from(codeContents).toString('utf-8');
|
|
446
|
-
const mapContents = outputFiles.get(relativeFile + '.map')?.contents;
|
|
447
|
-
return {
|
|
448
|
-
// Remove source map URL comments from the code if a sourcemap is present.
|
|
449
|
-
// Vite will inline and add an additional sourcemap URL for the sourcemap.
|
|
450
|
-
code: mapContents ? code.replace(/^\/\/# sourceMappingURL=[^\r\n]*/gm, '') : code,
|
|
451
|
-
map: mapContents && Buffer.from(mapContents).toString('utf-8'),
|
|
452
|
-
};
|
|
453
|
-
},
|
|
454
|
-
configureServer(server) {
|
|
455
|
-
const originalssrTransform = server.ssrTransform;
|
|
456
|
-
server.ssrTransform = async (code, map, url, originalCode) => {
|
|
457
|
-
const result = await originalssrTransform(code, null, url, originalCode);
|
|
458
|
-
if (!result || !result.map || !map) {
|
|
459
|
-
return result;
|
|
460
|
-
}
|
|
461
|
-
const remappedMap = (0, remapping_1.default)([result.map, map], () => null);
|
|
462
|
-
// Set the sourcemap root to the workspace root. This is needed since we set a virtual path as root.
|
|
463
|
-
remappedMap.sourceRoot = normalizePath(serverOptions.workspaceRoot) + '/';
|
|
464
|
-
return {
|
|
465
|
-
...result,
|
|
466
|
-
map: remappedMap,
|
|
467
|
-
};
|
|
468
|
-
};
|
|
469
|
-
// Assets and resources get handled first
|
|
470
|
-
server.middlewares.use(function angularAssetsMiddleware(req, res, next) {
|
|
471
|
-
if (req.url === undefined || res.writableEnded) {
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
// Parse the incoming request.
|
|
475
|
-
// The base of the URL is unused but required to parse the URL.
|
|
476
|
-
const pathname = pathnameWithoutBasePath(req.url, server.config.base);
|
|
477
|
-
const extension = (0, node_path_1.extname)(pathname);
|
|
478
|
-
// Rewrite all build assets to a vite raw fs URL
|
|
479
|
-
const assetSourcePath = assets.get(pathname);
|
|
480
|
-
if (assetSourcePath !== undefined) {
|
|
481
|
-
// Workaround to disable Vite transformer middleware.
|
|
482
|
-
// See: https://github.com/vitejs/vite/blob/746a1daab0395f98f0afbdee8f364cb6cf2f3b3f/packages/vite/src/node/server/middlewares/transform.ts#L201 and
|
|
483
|
-
// https://github.com/vitejs/vite/blob/746a1daab0395f98f0afbdee8f364cb6cf2f3b3f/packages/vite/src/node/server/transformRequest.ts#L204-L206
|
|
484
|
-
req.headers.accept = 'text/html';
|
|
485
|
-
// The encoding needs to match what happens in the vite static middleware.
|
|
486
|
-
// ref: https://github.com/vitejs/vite/blob/d4f13bd81468961c8c926438e815ab6b1c82735e/packages/vite/src/node/server/middlewares/static.ts#L163
|
|
487
|
-
req.url = `${server.config.base}@fs/${encodeURI(assetSourcePath)}`;
|
|
488
|
-
next();
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
// Resource files are handled directly.
|
|
492
|
-
// Global stylesheets (CSS files) are currently considered resources to workaround
|
|
493
|
-
// dev server sourcemap issues with stylesheets.
|
|
494
|
-
if (extension !== '.js' && extension !== '.html') {
|
|
495
|
-
const outputFile = outputFiles.get(pathname);
|
|
496
|
-
if (outputFile?.servable) {
|
|
497
|
-
const mimeType = (0, mrmime_1.lookup)(extension);
|
|
498
|
-
if (mimeType) {
|
|
499
|
-
res.setHeader('Content-Type', mimeType);
|
|
500
|
-
}
|
|
501
|
-
res.setHeader('Cache-Control', 'no-cache');
|
|
502
|
-
if (serverOptions.headers) {
|
|
503
|
-
Object.entries(serverOptions.headers).forEach(([name, value]) => res.setHeader(name, value));
|
|
504
|
-
}
|
|
505
|
-
res.end(outputFile.contents);
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
next();
|
|
510
|
-
});
|
|
511
|
-
if (extensionMiddleware?.length) {
|
|
512
|
-
extensionMiddleware.forEach((middleware) => server.middlewares.use(middleware));
|
|
513
|
-
}
|
|
514
|
-
// Returning a function, installs middleware after the main transform middleware but
|
|
515
|
-
// before the built-in HTML middleware
|
|
516
|
-
return () => {
|
|
517
|
-
function angularSSRMiddleware(req, res, next) {
|
|
518
|
-
const url = req.originalUrl;
|
|
519
|
-
if (
|
|
520
|
-
// Skip if path is not defined.
|
|
521
|
-
!url ||
|
|
522
|
-
// Skip if path is like a file.
|
|
523
|
-
// NOTE: We use a regexp to mitigate against matching requests like: /browse/pl.0ef59752c0cd457dbf1391f08cbd936f
|
|
524
|
-
/^\.[a-z]{2,4}$/i.test((0, node_path_1.extname)(url.split('?')[0]))) {
|
|
525
|
-
next();
|
|
526
|
-
return;
|
|
527
|
-
}
|
|
528
|
-
const rawHtml = outputFiles.get('/index.server.html')?.contents;
|
|
529
|
-
if (!rawHtml) {
|
|
530
|
-
next();
|
|
531
|
-
return;
|
|
532
|
-
}
|
|
533
|
-
transformIndexHtmlAndAddHeaders(url, rawHtml, res, next, async (html) => {
|
|
534
|
-
const { content } = await (0, render_page_1.renderPage)({
|
|
535
|
-
document: html,
|
|
536
|
-
route: new URL(req.originalUrl ?? '/', server.resolvedUrls?.local[0]).toString(),
|
|
537
|
-
serverContext: 'ssr',
|
|
538
|
-
loadBundle: (uri) =>
|
|
539
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
540
|
-
server.ssrLoadModule(uri.slice(1)),
|
|
541
|
-
// Files here are only needed for critical CSS inlining.
|
|
542
|
-
outputFiles: {},
|
|
543
|
-
// TODO: add support for critical css inlining.
|
|
544
|
-
inlineCriticalCss: false,
|
|
545
|
-
});
|
|
546
|
-
return indexHtmlTransformer && content
|
|
547
|
-
? await indexHtmlTransformer(content)
|
|
548
|
-
: content;
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
if (ssr) {
|
|
552
|
-
server.middlewares.use(angularSSRMiddleware);
|
|
553
|
-
}
|
|
554
|
-
server.middlewares.use(function angularIndexMiddleware(req, res, next) {
|
|
555
|
-
if (!req.url) {
|
|
556
|
-
next();
|
|
557
|
-
return;
|
|
558
|
-
}
|
|
559
|
-
// Parse the incoming request.
|
|
560
|
-
// The base of the URL is unused but required to parse the URL.
|
|
561
|
-
const pathname = pathnameWithoutBasePath(req.url, server.config.base);
|
|
562
|
-
if (pathname === '/' || pathname === `/index.html`) {
|
|
563
|
-
const rawHtml = outputFiles.get('/index.html')?.contents;
|
|
564
|
-
if (rawHtml) {
|
|
565
|
-
transformIndexHtmlAndAddHeaders(req.url, rawHtml, res, next, indexHtmlTransformer);
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
next();
|
|
570
|
-
});
|
|
571
|
-
};
|
|
572
|
-
function transformIndexHtmlAndAddHeaders(url, rawHtml, res, next, additionalTransformer) {
|
|
573
|
-
server
|
|
574
|
-
.transformIndexHtml(url, Buffer.from(rawHtml).toString('utf-8'))
|
|
575
|
-
.then(async (processedHtml) => {
|
|
576
|
-
if (additionalTransformer) {
|
|
577
|
-
const content = await additionalTransformer(processedHtml);
|
|
578
|
-
if (!content) {
|
|
579
|
-
next();
|
|
580
|
-
return;
|
|
581
|
-
}
|
|
582
|
-
processedHtml = content;
|
|
583
|
-
}
|
|
584
|
-
res.setHeader('Content-Type', 'text/html');
|
|
585
|
-
res.setHeader('Cache-Control', 'no-cache');
|
|
586
|
-
if (serverOptions.headers) {
|
|
587
|
-
Object.entries(serverOptions.headers).forEach(([name, value]) => res.setHeader(name, value));
|
|
588
|
-
}
|
|
589
|
-
res.end(processedHtml);
|
|
590
|
-
})
|
|
591
|
-
.catch((error) => next(error));
|
|
592
|
-
}
|
|
593
|
-
},
|
|
594
|
-
},
|
|
409
|
+
(0, angular_memory_plugin_1.createAngularMemoryPlugin)({
|
|
410
|
+
workspaceRoot: serverOptions.workspaceRoot,
|
|
411
|
+
virtualProjectRoot,
|
|
412
|
+
outputFiles,
|
|
413
|
+
assets,
|
|
414
|
+
ssr,
|
|
415
|
+
external: externalMetadata.explicit,
|
|
416
|
+
indexHtmlTransformer,
|
|
417
|
+
extensionMiddleware,
|
|
418
|
+
extraHeaders: serverOptions.headers,
|
|
419
|
+
normalizePath,
|
|
420
|
+
}),
|
|
595
421
|
],
|
|
596
422
|
// Browser only optimizeDeps. (This does not run for SSR dependencies).
|
|
597
423
|
optimizeDeps: getDepOptimizationConfig({
|
|
@@ -627,31 +453,6 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
|
|
|
627
453
|
return configuration;
|
|
628
454
|
}
|
|
629
455
|
exports.setupServer = setupServer;
|
|
630
|
-
/**
|
|
631
|
-
* Reads the resolved Vite client code from disk and updates the content to remove
|
|
632
|
-
* an unactionable suggestion to update the Vite configuration file to disable the
|
|
633
|
-
* error overlay. The Vite configuration file is not present when used in the Angular
|
|
634
|
-
* CLI.
|
|
635
|
-
* @param file The absolute path to the Vite client code.
|
|
636
|
-
* @returns
|
|
637
|
-
*/
|
|
638
|
-
async function loadViteClientCode(file) {
|
|
639
|
-
const originalContents = await (0, promises_1.readFile)(file, 'utf-8');
|
|
640
|
-
let contents = originalContents.replace('You can also disable this overlay by setting', '');
|
|
641
|
-
contents = contents.replace(
|
|
642
|
-
// eslint-disable-next-line max-len
|
|
643
|
-
'<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>', '');
|
|
644
|
-
(0, node_assert_1.default)(originalContents !== contents, 'Failed to update Vite client error overlay text.');
|
|
645
|
-
return contents;
|
|
646
|
-
}
|
|
647
|
-
function pathnameWithoutBasePath(url, basePath) {
|
|
648
|
-
const parsedUrl = new URL(url, 'http://localhost');
|
|
649
|
-
const pathname = decodeURIComponent(parsedUrl.pathname);
|
|
650
|
-
// slice(basePath.length - 1) to retain the trailing slash
|
|
651
|
-
return basePath !== '/' && pathname.startsWith(basePath)
|
|
652
|
-
? pathname.slice(basePath.length - 1)
|
|
653
|
-
: pathname;
|
|
654
|
-
}
|
|
655
456
|
function getDepOptimizationConfig({ disabled, exclude, include, target, prebundleTransformer, ssr, loader, thirdPartySourcemaps, }) {
|
|
656
457
|
const plugins = [
|
|
657
458
|
{
|
|
@@ -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
|
-
//
|
|
34
|
-
const
|
|
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]
|
|
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
|
|
35
|
-
const
|
|
36
|
-
const
|
|
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,
|
|
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 {};
|
|
@@ -43,7 +43,7 @@ async function extract() {
|
|
|
43
43
|
const browserIndexInputPath = path.join(outputPath, indexFile);
|
|
44
44
|
const document = await fs.promises.readFile(browserIndexInputPath, 'utf8');
|
|
45
45
|
const bootstrapAppFnOrModule = bootstrapAppFn || AppServerModule;
|
|
46
|
-
(0, node_assert_1.default)(bootstrapAppFnOrModule, `
|
|
46
|
+
(0, node_assert_1.default)(bootstrapAppFnOrModule, `The file "${serverBundlePath}" does not have a default export for an AppServerModule or a bootstrapping function.`);
|
|
47
47
|
const routes = [];
|
|
48
48
|
for await (const { route, success } of extractRoutes(bootstrapAppFnOrModule, document)) {
|
|
49
49
|
if (success) {
|
|
@@ -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
|
}
|