@angular-devkit/build-angular 17.0.0-rc.1 → 17.0.0-rc.3
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 +11 -10
- package/src/builders/app-shell/render-worker.d.ts +1 -1
- package/src/builders/app-shell/render-worker.js +16 -9
- package/src/builders/application/build-action.js +5 -2
- package/src/builders/application/execute-build.js +28 -18
- package/src/builders/browser-esbuild/index.js +9 -1
- package/src/builders/dev-server/vite-server.js +59 -20
- package/src/builders/extract-i18n/application-extraction.js +1 -0
- package/src/builders/prerender/routes-extractor-worker.js +1 -1
- package/src/tools/babel/plugins/elide-angular-metadata.js +14 -2
- package/src/tools/esbuild/angular/compiler-plugin.js +2 -1
- package/src/tools/esbuild/application-code-bundle.d.ts +3 -2
- package/src/tools/esbuild/application-code-bundle.js +8 -12
- package/src/tools/esbuild/bundler-context.d.ts +1 -1
- package/src/tools/esbuild/bundler-context.js +7 -2
- package/src/tools/esbuild/bundler-execution-result.d.ts +2 -0
- package/src/tools/esbuild/bundler-execution-result.js +14 -0
- package/src/tools/esbuild/commonjs-checker.js +3 -3
- package/src/tools/esbuild/global-scripts.d.ts +2 -3
- package/src/tools/esbuild/global-scripts.js +72 -69
- package/src/tools/esbuild/global-styles.d.ts +2 -3
- package/src/tools/esbuild/global-styles.js +35 -33
- package/src/tools/esbuild/javascript-transformer-worker.js +3 -2
- package/src/tools/esbuild/javascript-transformer.d.ts +1 -0
- package/src/tools/esbuild/javascript-transformer.js +25 -13
- package/src/tools/esbuild/utils.d.ts +1 -1
- package/src/tools/esbuild/utils.js +18 -4
- package/src/tools/esbuild/watcher.d.ts +1 -0
- package/src/tools/esbuild/watcher.js +3 -0
- package/src/utils/check-port.js +3 -1
- package/src/utils/environment-options.d.ts +1 -0
- package/src/utils/environment-options.js +3 -1
- package/src/utils/load-esm.d.ts +0 -2
- package/src/utils/routes-extractor/extractor.d.ts +1 -1
- package/src/utils/routes-extractor/extractor.js +2 -2
- package/src/utils/server-rendering/esm-in-memory-loader/loader-hooks.js +3 -2
- package/src/utils/server-rendering/fetch-patch.d.ts +8 -0
- package/src/utils/server-rendering/fetch-patch.js +66 -0
- package/src/utils/server-rendering/prerender.js +25 -30
- package/src/utils/server-rendering/render-worker.d.ts +4 -2
- package/src/utils/server-rendering/render-worker.js +8 -4
- package/src/utils/server-rendering/routes-extractor-worker.d.ts +5 -3
- package/src/utils/server-rendering/routes-extractor-worker.js +10 -4
- package/src/tools/esbuild/javascript-transfomer-plugin.d.ts +0 -19
- package/src/tools/esbuild/javascript-transfomer-plugin.js +0 -51
- package/src/utils/server-rendering/prerender-server.d.ts +0 -21
- package/src/utils/server-rendering/prerender-server.js +0 -102
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular-devkit/build-angular",
|
|
3
|
-
"version": "17.0.0-rc.
|
|
3
|
+
"version": "17.0.0-rc.3",
|
|
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.1700.0-rc.
|
|
11
|
-
"@angular-devkit/build-webpack": "0.1700.0-rc.
|
|
12
|
-
"@angular-devkit/core": "17.0.0-rc.
|
|
10
|
+
"@angular-devkit/architect": "0.1700.0-rc.3",
|
|
11
|
+
"@angular-devkit/build-webpack": "0.1700.0-rc.3",
|
|
12
|
+
"@angular-devkit/core": "17.0.0-rc.3",
|
|
13
13
|
"@babel/core": "7.23.2",
|
|
14
14
|
"@babel/generator": "7.23.0",
|
|
15
15
|
"@babel/helper-annotate-as-pure": "7.22.5",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"@babel/preset-env": "7.23.2",
|
|
21
21
|
"@babel/runtime": "7.23.2",
|
|
22
22
|
"@discoveryjs/json-ext": "0.5.7",
|
|
23
|
-
"@ngtools/webpack": "17.0.0-rc.
|
|
23
|
+
"@ngtools/webpack": "17.0.0-rc.3",
|
|
24
24
|
"@vitejs/plugin-basic-ssl": "1.0.1",
|
|
25
25
|
"ansi-colors": "4.1.3",
|
|
26
26
|
"autoprefixer": "10.4.16",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"fast-glob": "3.3.1",
|
|
37
37
|
"https-proxy-agent": "7.0.2",
|
|
38
38
|
"http-proxy-middleware": "2.0.6",
|
|
39
|
-
"inquirer": "
|
|
39
|
+
"inquirer": "9.2.11",
|
|
40
40
|
"jsonc-parser": "3.2.0",
|
|
41
41
|
"karma-source-map-support": "1.4.0",
|
|
42
42
|
"less": "4.2.0",
|
|
@@ -49,21 +49,22 @@
|
|
|
49
49
|
"open": "8.4.2",
|
|
50
50
|
"ora": "5.4.1",
|
|
51
51
|
"parse5-html-rewriting-stream": "7.0.0",
|
|
52
|
-
"picomatch": "
|
|
52
|
+
"picomatch": "3.0.1",
|
|
53
53
|
"piscina": "4.1.0",
|
|
54
54
|
"postcss": "8.4.31",
|
|
55
55
|
"postcss-loader": "7.3.3",
|
|
56
56
|
"resolve-url-loader": "5.0.0",
|
|
57
57
|
"rxjs": "7.8.1",
|
|
58
|
-
"sass": "1.69.
|
|
58
|
+
"sass": "1.69.5",
|
|
59
59
|
"sass-loader": "13.3.2",
|
|
60
60
|
"semver": "7.5.4",
|
|
61
61
|
"source-map-loader": "4.0.1",
|
|
62
62
|
"source-map-support": "0.5.21",
|
|
63
|
-
"terser": "5.
|
|
63
|
+
"terser": "5.24.0",
|
|
64
64
|
"text-table": "0.2.0",
|
|
65
65
|
"tree-kill": "1.2.2",
|
|
66
66
|
"tslib": "2.6.2",
|
|
67
|
+
"undici": "5.27.0",
|
|
67
68
|
"vite": "4.5.0",
|
|
68
69
|
"webpack": "5.89.0",
|
|
69
70
|
"webpack-dev-middleware": "6.1.1",
|
|
@@ -128,7 +129,7 @@
|
|
|
128
129
|
"url": "https://github.com/angular/angular-cli.git"
|
|
129
130
|
},
|
|
130
131
|
"engines": {
|
|
131
|
-
"node": "
|
|
132
|
+
"node": "^18.13.0 || >=20.9.0",
|
|
132
133
|
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
|
|
133
134
|
"yarn": ">= 1.13.0"
|
|
134
135
|
},
|
|
@@ -20,7 +20,7 @@ interface RenderRequest {
|
|
|
20
20
|
/**
|
|
21
21
|
* An optional URL path that represents the Angular route that should be rendered.
|
|
22
22
|
*/
|
|
23
|
-
url: string
|
|
23
|
+
url: string;
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
26
|
* Renders an application based on a provided server bundle path, initial document, and optional URL route.
|
|
@@ -54,23 +54,30 @@ async function render({ serverBundlePath, document, url }) {
|
|
|
54
54
|
useValue: 'app-shell',
|
|
55
55
|
},
|
|
56
56
|
];
|
|
57
|
+
let renderAppPromise;
|
|
57
58
|
// Render platform server module
|
|
58
59
|
if (isBootstrapFn(bootstrapAppFn)) {
|
|
59
60
|
(0, node_assert_1.default)(renderApplication, `renderApplication was not exported from: ${serverBundlePath}.`);
|
|
60
|
-
|
|
61
|
+
renderAppPromise = renderApplication(bootstrapAppFn, {
|
|
61
62
|
document,
|
|
62
63
|
url,
|
|
63
64
|
platformProviders,
|
|
64
65
|
});
|
|
65
66
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
else {
|
|
68
|
+
(0, node_assert_1.default)(renderModule, `renderModule was not exported from: ${serverBundlePath}.`);
|
|
69
|
+
const moduleClass = bootstrapAppFn || AppServerModule;
|
|
70
|
+
(0, node_assert_1.default)(moduleClass, `Neither an AppServerModule nor a bootstrapping function was exported from: ${serverBundlePath}.`);
|
|
71
|
+
renderAppPromise = renderModule(moduleClass, {
|
|
72
|
+
document,
|
|
73
|
+
url,
|
|
74
|
+
extraProviders: platformProviders,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
// The below should really handled by the framework!!!.
|
|
78
|
+
let timer;
|
|
79
|
+
const renderingTimeout = new Promise((_, reject) => (timer = setTimeout(() => reject(new Error(`Page ${new URL(url, 'resolve://').pathname} did not render in 30 seconds.`)), 30000)));
|
|
80
|
+
return Promise.race([renderAppPromise, renderingTimeout]).finally(() => clearTimeout(timer));
|
|
74
81
|
}
|
|
75
82
|
function isBootstrapFn(value) {
|
|
76
83
|
// We can differentiate between a module and a bootstrap function by reading compiler-generated `ɵmod` static property:
|
|
@@ -38,6 +38,7 @@ const promises_1 = __importDefault(require("node:fs/promises"));
|
|
|
38
38
|
const node_path_1 = __importDefault(require("node:path"));
|
|
39
39
|
const sass_language_1 = require("../../tools/esbuild/stylesheets/sass-language");
|
|
40
40
|
const utils_1 = require("../../tools/esbuild/utils");
|
|
41
|
+
const environment_options_1 = require("../../utils/environment-options");
|
|
41
42
|
const error_1 = require("../../utils/error");
|
|
42
43
|
async function* runEsBuildBuildAction(action, options) {
|
|
43
44
|
const { writeToFileSystemFilter, writeToFileSystem = true, watch, poll, logger, deleteOutputPath, cacheOptions, outputPath, verbose, projectRoot, workspaceRoot, progress, } = options;
|
|
@@ -95,8 +96,10 @@ async function* runEsBuildBuildAction(action, options) {
|
|
|
95
96
|
});
|
|
96
97
|
// Setup abort support
|
|
97
98
|
options.signal?.addEventListener('abort', () => void watcher?.close());
|
|
98
|
-
//
|
|
99
|
-
|
|
99
|
+
// Watch the entire project root if 'NG_BUILD_WATCH_ROOT' environment variable is set
|
|
100
|
+
if (environment_options_1.shouldWatchRoot) {
|
|
101
|
+
watcher.add(projectRoot);
|
|
102
|
+
}
|
|
100
103
|
// Watch workspace for package manager changes
|
|
101
104
|
const packageWatchFiles = [
|
|
102
105
|
// manifest can affect module resolution
|
|
@@ -19,6 +19,7 @@ const global_styles_1 = require("../../tools/esbuild/global-styles");
|
|
|
19
19
|
const license_extractor_1 = require("../../tools/esbuild/license-extractor");
|
|
20
20
|
const utils_1 = require("../../tools/esbuild/utils");
|
|
21
21
|
const bundle_calculator_1 = require("../../utils/bundle-calculator");
|
|
22
|
+
const color_1 = require("../../utils/color");
|
|
22
23
|
const copy_assets_1 = require("../../utils/copy-assets");
|
|
23
24
|
const supported_browsers_1 = require("../../utils/supported-browsers");
|
|
24
25
|
const execute_post_bundle_1 = require("./execute-post-bundle");
|
|
@@ -49,7 +50,7 @@ async function executeBuild(options, context, rebuildState) {
|
|
|
49
50
|
// Global Stylesheets
|
|
50
51
|
if (options.globalStyles.length > 0) {
|
|
51
52
|
for (const initial of [true, false]) {
|
|
52
|
-
const bundleOptions = (0, global_styles_1.createGlobalStylesBundleOptions)(options, target, initial
|
|
53
|
+
const bundleOptions = (0, global_styles_1.createGlobalStylesBundleOptions)(options, target, initial);
|
|
53
54
|
if (bundleOptions) {
|
|
54
55
|
bundlerContexts.push(new bundler_context_1.BundlerContext(workspaceRoot, !!options.watch, bundleOptions, () => initial));
|
|
55
56
|
}
|
|
@@ -76,7 +77,7 @@ async function executeBuild(options, context, rebuildState) {
|
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
|
-
const bundlingResult = await bundler_context_1.BundlerContext.bundleAll(bundlerContexts);
|
|
80
|
+
const bundlingResult = await bundler_context_1.BundlerContext.bundleAll(bundlerContexts, rebuildState?.fileChanges.all);
|
|
80
81
|
// Log all warnings and errors generated during bundling
|
|
81
82
|
await (0, utils_1.logMessages)(context, bundlingResult);
|
|
82
83
|
const executionResult = new bundler_execution_result_1.ExecutionResult(bundlerContexts, codeBundleCache);
|
|
@@ -112,13 +113,15 @@ async function executeBuild(options, context, rebuildState) {
|
|
|
112
113
|
if (options.budgets) {
|
|
113
114
|
const compatStats = (0, budget_stats_1.generateBudgetStats)(metafile, initialFiles);
|
|
114
115
|
budgetFailures = [...(0, bundle_calculator_1.checkBudgets)(options.budgets, compatStats, true)];
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
116
|
+
if (budgetFailures.length > 0) {
|
|
117
|
+
await (0, utils_1.logMessages)(context, {
|
|
118
|
+
errors: budgetFailures
|
|
119
|
+
.filter((failure) => failure.severity === 'error')
|
|
120
|
+
.map((failure) => ({ text: failure.message, location: null })),
|
|
121
|
+
warnings: budgetFailures
|
|
122
|
+
.filter((failure) => failure.severity !== 'error')
|
|
123
|
+
.map((failure) => ({ text: failure.message, location: null })),
|
|
124
|
+
});
|
|
122
125
|
}
|
|
123
126
|
}
|
|
124
127
|
// Calculate estimated transfer size if scripts are optimized
|
|
@@ -146,11 +149,20 @@ async function executeBuild(options, context, rebuildState) {
|
|
|
146
149
|
executionResult.outputFiles.push(...result.additionalOutputFiles);
|
|
147
150
|
executionResult.assetFiles.push(...result.additionalAssets);
|
|
148
151
|
}
|
|
152
|
+
await printWarningsAndErrorsToConsole(context, warnings, errors);
|
|
149
153
|
if (prerenderOptions) {
|
|
150
154
|
executionResult.addOutputFile('prerendered-routes.json', JSON.stringify({ routes: prerenderedRoutes.sort((a, b) => a.localeCompare(b)) }, null, 2), bundler_context_1.BuildOutputFileType.Root);
|
|
155
|
+
let prerenderMsg = `Prerendered ${prerenderedRoutes.length} static route`;
|
|
156
|
+
if (prerenderedRoutes.length > 1) {
|
|
157
|
+
prerenderMsg += 's.';
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
prerenderMsg += '.';
|
|
161
|
+
}
|
|
162
|
+
context.logger.info(color_1.colors.magenta(prerenderMsg) + '\n');
|
|
151
163
|
}
|
|
152
|
-
|
|
153
|
-
(0, utils_1.logBuildStats)(context, metafile, initialFiles, budgetFailures, estimatedTransferSizes);
|
|
164
|
+
const changedFiles = rebuildState && executionResult.findChangedFiles(rebuildState.previousOutputHashes);
|
|
165
|
+
(0, utils_1.logBuildStats)(context, metafile, initialFiles, budgetFailures, changedFiles, estimatedTransferSizes);
|
|
154
166
|
// Write metafile if stats option is enabled
|
|
155
167
|
if (options.stats) {
|
|
156
168
|
executionResult.addOutputFile('stats.json', JSON.stringify(metafile, null, 2), bundler_context_1.BuildOutputFileType.Root);
|
|
@@ -158,11 +170,9 @@ async function executeBuild(options, context, rebuildState) {
|
|
|
158
170
|
return executionResult;
|
|
159
171
|
}
|
|
160
172
|
exports.executeBuild = executeBuild;
|
|
161
|
-
function printWarningsAndErrorsToConsole(context, warnings, errors) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
context.logger.warn(warning);
|
|
167
|
-
}
|
|
173
|
+
async function printWarningsAndErrorsToConsole(context, warnings, errors) {
|
|
174
|
+
await (0, utils_1.logMessages)(context, {
|
|
175
|
+
errors: errors.map((text) => ({ text, location: null })),
|
|
176
|
+
warnings: warnings.map((text) => ({ text, location: null })),
|
|
177
|
+
});
|
|
168
178
|
}
|
|
@@ -37,7 +37,15 @@ async function* buildEsbuildBrowser(userOptions, context, infrastructureSettings
|
|
|
37
37
|
// Write output files
|
|
38
38
|
await writeResultFiles(result.outputFiles, result.assetFiles, fullOutputPath);
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
// The builder system (architect) currently attempts to treat all results as JSON and
|
|
41
|
+
// attempts to validate the object with a JSON schema validator. This can lead to slow
|
|
42
|
+
// build completion (even after the actual build is fully complete) or crashes if the
|
|
43
|
+
// size and/or quantity of output files is large. Architect only requires a `success`
|
|
44
|
+
// property so that is all that will be passed here if the infrastructure settings have
|
|
45
|
+
// not been explicitly set to avoid writes. Writing is only disabled when used directly
|
|
46
|
+
// by the dev server which bypasses the architect behavior.
|
|
47
|
+
const builderResult = infrastructureSettings?.write === false ? result : { success: result.success };
|
|
48
|
+
yield builderResult;
|
|
41
49
|
}
|
|
42
50
|
}
|
|
43
51
|
exports.buildEsbuildBrowser = buildEsbuildBrowser;
|
|
@@ -37,6 +37,7 @@ exports.setupServer = exports.serveWithVite = void 0;
|
|
|
37
37
|
const remapping_1 = __importDefault(require("@ampproject/remapping"));
|
|
38
38
|
const mrmime_1 = require("mrmime");
|
|
39
39
|
const node_assert_1 = __importDefault(require("node:assert"));
|
|
40
|
+
const node_crypto_1 = require("node:crypto");
|
|
40
41
|
const promises_1 = require("node:fs/promises");
|
|
41
42
|
const node_path_1 = __importDefault(require("node:path"));
|
|
42
43
|
const bundler_context_1 = require("../../tools/esbuild/bundler-context");
|
|
@@ -148,14 +149,16 @@ async function* serveWithVite(serverOptions, builderName, context, plugins) {
|
|
|
148
149
|
}
|
|
149
150
|
// To avoid disconnecting the array objects from the option, these arrays need to be mutated
|
|
150
151
|
// instead of replaced.
|
|
151
|
-
if (result.externalMetadata
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
if (result.externalMetadata) {
|
|
153
|
+
if (result.externalMetadata.explicit) {
|
|
154
|
+
externalMetadata.explicit.push(...result.externalMetadata.explicit);
|
|
155
|
+
}
|
|
156
|
+
if (result.externalMetadata.implicit) {
|
|
157
|
+
externalMetadata.implicit.push(...result.externalMetadata.implicit);
|
|
158
|
+
}
|
|
156
159
|
}
|
|
157
160
|
if (server) {
|
|
158
|
-
handleUpdate(generatedFiles, server, serverOptions, context.logger);
|
|
161
|
+
handleUpdate(normalizePath, generatedFiles, server, serverOptions, context.logger);
|
|
159
162
|
}
|
|
160
163
|
else {
|
|
161
164
|
const projectName = context.target?.project;
|
|
@@ -187,13 +190,13 @@ async function* serveWithVite(serverOptions, builderName, context, plugins) {
|
|
|
187
190
|
await new Promise((resolve) => (deferred = resolve));
|
|
188
191
|
}
|
|
189
192
|
exports.serveWithVite = serveWithVite;
|
|
190
|
-
function handleUpdate(generatedFiles, server, serverOptions, logger) {
|
|
193
|
+
function handleUpdate(normalizePath, generatedFiles, server, serverOptions, logger) {
|
|
191
194
|
const updatedFiles = [];
|
|
192
195
|
// Invalidate any updated files
|
|
193
196
|
for (const [file, record] of generatedFiles) {
|
|
194
197
|
if (record.updated) {
|
|
195
198
|
updatedFiles.push(file);
|
|
196
|
-
const updatedModules = server.moduleGraph.getModulesByFile(file);
|
|
199
|
+
const updatedModules = server.moduleGraph.getModulesByFile(normalizePath(node_path_1.default.join(server.config.root, file)));
|
|
197
200
|
updatedModules?.forEach((m) => server?.moduleGraph.invalidateModule(m));
|
|
198
201
|
}
|
|
199
202
|
}
|
|
@@ -205,8 +208,7 @@ function handleUpdate(generatedFiles, server, serverOptions, logger) {
|
|
|
205
208
|
const timestamp = Date.now();
|
|
206
209
|
server.ws.send({
|
|
207
210
|
type: 'update',
|
|
208
|
-
updates: updatedFiles.map((
|
|
209
|
-
const filePath = f.slice(1); // Remove leading slash.
|
|
211
|
+
updates: updatedFiles.map((filePath) => {
|
|
210
212
|
return {
|
|
211
213
|
type: 'css-update',
|
|
212
214
|
timestamp,
|
|
@@ -238,7 +240,7 @@ function analyzeResultFiles(normalizePath, htmlIndexPath, resultFiles, generated
|
|
|
238
240
|
filePath = '/index.html';
|
|
239
241
|
}
|
|
240
242
|
else {
|
|
241
|
-
filePath =
|
|
243
|
+
filePath = normalizePath(file.path);
|
|
242
244
|
}
|
|
243
245
|
seen.add(filePath);
|
|
244
246
|
// Skip analysis of sourcemaps
|
|
@@ -280,11 +282,13 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
|
|
|
280
282
|
const proxy = await (0, load_proxy_config_1.loadProxyConfiguration)(serverOptions.workspaceRoot, serverOptions.proxyConfig, true);
|
|
281
283
|
// dynamically import Vite for ESM compatibility
|
|
282
284
|
const { normalizePath } = await Promise.resolve().then(() => __importStar(require('vite')));
|
|
285
|
+
// Path will not exist on disk and only used to provide separate path for Vite requests
|
|
286
|
+
const virtualProjectRoot = normalizePath(node_path_1.default.join(serverOptions.workspaceRoot, `.angular/vite-root/${(0, node_crypto_1.randomUUID)()}/`));
|
|
283
287
|
const configuration = {
|
|
284
288
|
configFile: false,
|
|
285
289
|
envFile: false,
|
|
286
290
|
cacheDir: node_path_1.default.join(serverOptions.cacheOptions.path, 'vite'),
|
|
287
|
-
root:
|
|
291
|
+
root: virtualProjectRoot,
|
|
288
292
|
publicDir: false,
|
|
289
293
|
esbuild: false,
|
|
290
294
|
mode: 'development',
|
|
@@ -308,10 +312,13 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
|
|
|
308
312
|
watch: {
|
|
309
313
|
ignored: ['**/*'],
|
|
310
314
|
},
|
|
315
|
+
// This is needed when `externalDependencies` is used to prevent Vite load errors.
|
|
316
|
+
// NOTE: If Vite adds direct support for externals, this can be removed.
|
|
317
|
+
preTransformRequests: externalMetadata.explicit.length === 0,
|
|
311
318
|
},
|
|
312
319
|
ssr: {
|
|
313
320
|
// Exclude any provided dependencies (currently build defined externals)
|
|
314
|
-
external: externalMetadata.
|
|
321
|
+
external: externalMetadata.explicit,
|
|
315
322
|
},
|
|
316
323
|
plugins: [
|
|
317
324
|
(0, i18n_locale_plugin_1.createAngularLocaleDataPlugin)(),
|
|
@@ -320,24 +327,37 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
|
|
|
320
327
|
// Ensures plugin hooks run before built-in Vite hooks
|
|
321
328
|
enforce: 'pre',
|
|
322
329
|
async resolveId(source, importer) {
|
|
323
|
-
|
|
330
|
+
// Prevent vite from resolving an explicit external dependency (`externalDependencies` option)
|
|
331
|
+
if (externalMetadata.explicit.includes(source)) {
|
|
332
|
+
// This is still not ideal since Vite will still transform the import specifier to
|
|
333
|
+
// `/@id/${source}` but is currently closer to a raw external than a resolved file path.
|
|
334
|
+
return source;
|
|
335
|
+
}
|
|
336
|
+
if (importer && source[0] === '.' && importer.startsWith(virtualProjectRoot)) {
|
|
324
337
|
// Remove query if present
|
|
325
338
|
const [importerFile] = importer.split('?', 1);
|
|
326
|
-
source = normalizePath(node_path_1.default.join(node_path_1.default.dirname(importerFile), source));
|
|
339
|
+
source = normalizePath(node_path_1.default.join(node_path_1.default.dirname(node_path_1.default.relative(virtualProjectRoot, importerFile)), source));
|
|
340
|
+
}
|
|
341
|
+
if (source[0] === '/') {
|
|
342
|
+
source = source.slice(1);
|
|
327
343
|
}
|
|
328
344
|
const [file] = source.split('?', 1);
|
|
329
345
|
if (outputFiles.has(file)) {
|
|
330
|
-
return source;
|
|
346
|
+
return node_path_1.default.join(virtualProjectRoot, source);
|
|
331
347
|
}
|
|
332
348
|
},
|
|
333
349
|
load(id) {
|
|
334
350
|
const [file] = id.split('?', 1);
|
|
335
|
-
const
|
|
351
|
+
const relativeFile = normalizePath(node_path_1.default.relative(virtualProjectRoot, file));
|
|
352
|
+
const codeContents = outputFiles.get(relativeFile)?.contents;
|
|
336
353
|
if (codeContents === undefined) {
|
|
354
|
+
if (relativeFile.endsWith('/node_modules/vite/dist/client/client.mjs')) {
|
|
355
|
+
return loadViteClientCode(file);
|
|
356
|
+
}
|
|
337
357
|
return;
|
|
338
358
|
}
|
|
339
359
|
const code = Buffer.from(codeContents).toString('utf-8');
|
|
340
|
-
const mapContents = outputFiles.get(
|
|
360
|
+
const mapContents = outputFiles.get(relativeFile + '.map')?.contents;
|
|
341
361
|
return {
|
|
342
362
|
// Remove source map URL comments from the code if a sourcemap is present.
|
|
343
363
|
// Vite will inline and add an additional sourcemap URL for the sourcemap.
|
|
@@ -411,15 +431,17 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
|
|
|
411
431
|
next();
|
|
412
432
|
return;
|
|
413
433
|
}
|
|
414
|
-
const rawHtml = outputFiles.get('
|
|
434
|
+
const rawHtml = outputFiles.get('index.server.html')?.contents;
|
|
415
435
|
if (!rawHtml) {
|
|
416
436
|
next();
|
|
417
437
|
return;
|
|
418
438
|
}
|
|
419
439
|
transformIndexHtmlAndAddHeaders(url, rawHtml, res, next, async (html) => {
|
|
440
|
+
const protocol = serverOptions.ssl ? 'https' : 'http';
|
|
441
|
+
const route = `${protocol}://${req.headers.host}${req.originalUrl}`;
|
|
420
442
|
const { content } = await (0, render_page_1.renderPage)({
|
|
421
443
|
document: html,
|
|
422
|
-
route
|
|
444
|
+
route,
|
|
423
445
|
serverContext: 'ssr',
|
|
424
446
|
loadBundle: (path) =>
|
|
425
447
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -525,6 +547,23 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
|
|
|
525
547
|
return configuration;
|
|
526
548
|
}
|
|
527
549
|
exports.setupServer = setupServer;
|
|
550
|
+
/**
|
|
551
|
+
* Reads the resolved Vite client code from disk and updates the content to remove
|
|
552
|
+
* an unactionable suggestion to update the Vite configuration file to disable the
|
|
553
|
+
* error overlay. The Vite configuration file is not present when used in the Angular
|
|
554
|
+
* CLI.
|
|
555
|
+
* @param file The absolute path to the Vite client code.
|
|
556
|
+
* @returns
|
|
557
|
+
*/
|
|
558
|
+
async function loadViteClientCode(file) {
|
|
559
|
+
const originalContents = await (0, promises_1.readFile)(file, 'utf-8');
|
|
560
|
+
let contents = originalContents.replace('You can also disable this overlay by setting', '');
|
|
561
|
+
contents = contents.replace(
|
|
562
|
+
// eslint-disable-next-line max-len
|
|
563
|
+
'<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>', '');
|
|
564
|
+
(0, node_assert_1.default)(originalContents !== contents, 'Failed to update Vite client error overlay text.');
|
|
565
|
+
return contents;
|
|
566
|
+
}
|
|
528
567
|
function pathnameWithoutServePath(url, serverOptions) {
|
|
529
568
|
const parsedUrl = new URL(url, 'http://localhost');
|
|
530
569
|
let pathname = decodeURIComponent(parsedUrl.pathname);
|
|
@@ -22,6 +22,7 @@ async function extractMessages(options, builderName, context, extractorConstruct
|
|
|
22
22
|
buildOptions.optimization = false;
|
|
23
23
|
buildOptions.sourceMap = { scripts: true, vendor: true };
|
|
24
24
|
buildOptions.localize = false;
|
|
25
|
+
buildOptions.budgets = undefined;
|
|
25
26
|
let build;
|
|
26
27
|
if (builderName === '@angular-devkit/build-angular:application') {
|
|
27
28
|
build = application_1.buildApplicationInternal;
|
|
@@ -45,7 +45,7 @@ async function extract() {
|
|
|
45
45
|
const bootstrapAppFnOrModule = bootstrapAppFn || AppServerModule;
|
|
46
46
|
(0, node_assert_1.default)(bootstrapAppFnOrModule, `Neither an AppServerModule nor a bootstrapping function was exported from: ${serverBundlePath}.`);
|
|
47
47
|
const routes = [];
|
|
48
|
-
for await (const { route, success } of extractRoutes(bootstrapAppFnOrModule, document
|
|
48
|
+
for await (const { route, success } of extractRoutes(bootstrapAppFnOrModule, document)) {
|
|
49
49
|
if (success) {
|
|
50
50
|
routes.push(route);
|
|
51
51
|
}
|
|
@@ -17,6 +17,10 @@ const SET_CLASS_METADATA_NAME = 'ɵsetClassMetadata';
|
|
|
17
17
|
* Name of the asynchronous Angular class metadata function created by the Angular compiler.
|
|
18
18
|
*/
|
|
19
19
|
const SET_CLASS_METADATA_ASYNC_NAME = 'ɵsetClassMetadataAsync';
|
|
20
|
+
/**
|
|
21
|
+
* Name of the function that sets debug information on classes.
|
|
22
|
+
*/
|
|
23
|
+
const SET_CLASS_DEBUG_INFO_NAME = 'ɵsetClassDebugInfo';
|
|
20
24
|
/**
|
|
21
25
|
* Provides one or more keywords that if found within the content of a source file indicate
|
|
22
26
|
* that this plugin should be used with a source file.
|
|
@@ -24,7 +28,7 @@ const SET_CLASS_METADATA_ASYNC_NAME = 'ɵsetClassMetadataAsync';
|
|
|
24
28
|
* @returns An a string iterable containing one or more keywords.
|
|
25
29
|
*/
|
|
26
30
|
function getKeywords() {
|
|
27
|
-
return [SET_CLASS_METADATA_NAME, SET_CLASS_METADATA_ASYNC_NAME];
|
|
31
|
+
return [SET_CLASS_METADATA_NAME, SET_CLASS_METADATA_ASYNC_NAME, SET_CLASS_DEBUG_INFO_NAME];
|
|
28
32
|
}
|
|
29
33
|
exports.getKeywords = getKeywords;
|
|
30
34
|
/**
|
|
@@ -48,7 +52,8 @@ function default_1() {
|
|
|
48
52
|
}
|
|
49
53
|
if (calleeName !== undefined &&
|
|
50
54
|
(isRemoveClassMetadataCall(calleeName, callArguments) ||
|
|
51
|
-
isRemoveClassmetadataAsyncCall(calleeName, callArguments)
|
|
55
|
+
isRemoveClassmetadataAsyncCall(calleeName, callArguments) ||
|
|
56
|
+
isSetClassDebugInfoCall(calleeName, callArguments))) {
|
|
52
57
|
// The metadata function is always emitted inside a function expression
|
|
53
58
|
const parent = path.getFunctionParent();
|
|
54
59
|
if (parent && (parent.isFunctionExpression() || parent.isArrowFunctionExpression())) {
|
|
@@ -84,6 +89,13 @@ function isRemoveClassmetadataAsyncCall(name, args) {
|
|
|
84
89
|
isInlineFunction(args[1]) &&
|
|
85
90
|
isInlineFunction(args[2]));
|
|
86
91
|
}
|
|
92
|
+
/** Determines if a function call is a call to `setClassDebugInfo`. */
|
|
93
|
+
function isSetClassDebugInfoCall(name, args) {
|
|
94
|
+
return (name === SET_CLASS_DEBUG_INFO_NAME &&
|
|
95
|
+
args.length === 2 &&
|
|
96
|
+
core_1.types.isIdentifier(args[0]) &&
|
|
97
|
+
core_1.types.isObjectExpression(args[1]));
|
|
98
|
+
}
|
|
87
99
|
/** Determines if a node is an inline function expression. */
|
|
88
100
|
function isInlineFunction(node) {
|
|
89
101
|
return core_1.types.isFunctionExpression(node) || core_1.types.isArrowFunctionExpression(node);
|
|
@@ -172,7 +172,8 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
172
172
|
// Return bundled worker file entry name to be used in the built output
|
|
173
173
|
const workerCodeFile = workerResult.outputFiles.find((file) => file.path.endsWith('.js'));
|
|
174
174
|
(0, node_assert_1.default)(workerCodeFile, 'Web Worker bundled code file should always be present.');
|
|
175
|
-
|
|
175
|
+
const workerCodePath = path.relative(build.initialOptions.outdir ?? '', workerCodeFile.path);
|
|
176
|
+
return workerCodePath.replaceAll('\\', '/');
|
|
176
177
|
},
|
|
177
178
|
};
|
|
178
179
|
// Initialize the Angular compilation for the current build.
|
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
import type { BuildOptions } from 'esbuild';
|
|
9
9
|
import type { NormalizedApplicationBuildOptions } from '../../builders/application/options';
|
|
10
10
|
import { SourceFileCache } from './angular/source-file-cache';
|
|
11
|
+
import { BundlerOptionsFactory } from './bundler-context';
|
|
11
12
|
export declare function createBrowserCodeBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache?: SourceFileCache): BuildOptions;
|
|
12
|
-
export declare function createBrowserPolyfillBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache?: SourceFileCache): BuildOptions | undefined;
|
|
13
|
+
export declare function createBrowserPolyfillBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache?: SourceFileCache): BuildOptions | BundlerOptionsFactory | undefined;
|
|
13
14
|
/**
|
|
14
15
|
* Create an esbuild 'build' options object for the server bundle.
|
|
15
16
|
* @param options The builder's user-provider normalized options.
|
|
16
17
|
* @returns An esbuild BuildOptions object.
|
|
17
18
|
*/
|
|
18
19
|
export declare function createServerCodeBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache): BuildOptions;
|
|
19
|
-
export declare function createServerPolyfillBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache?: SourceFileCache):
|
|
20
|
+
export declare function createServerPolyfillBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache?: SourceFileCache): BundlerOptionsFactory | undefined;
|
|
@@ -19,7 +19,6 @@ const environment_options_1 = require("../../utils/environment-options");
|
|
|
19
19
|
const compiler_plugin_1 = require("./angular/compiler-plugin");
|
|
20
20
|
const compiler_plugin_options_1 = require("./compiler-plugin-options");
|
|
21
21
|
const i18n_locale_plugin_1 = require("./i18n-locale-plugin");
|
|
22
|
-
const javascript_transfomer_plugin_1 = require("./javascript-transfomer-plugin");
|
|
23
22
|
const rxjs_esm_resolution_plugin_1 = require("./rxjs-esm-resolution-plugin");
|
|
24
23
|
const sourcemap_ignorelist_plugin_1 = require("./sourcemap-ignorelist-plugin");
|
|
25
24
|
const utils_1 = require("./utils");
|
|
@@ -64,6 +63,7 @@ function createBrowserPolyfillBundleOptions(options, target, sourceFileCache) {
|
|
|
64
63
|
return;
|
|
65
64
|
}
|
|
66
65
|
const { outputNames, polyfills } = options;
|
|
66
|
+
const hasTypeScriptEntries = polyfills?.some((entry) => /\.[cm]?tsx?$/.test(entry));
|
|
67
67
|
const buildOptions = {
|
|
68
68
|
...polyfillBundleOptions,
|
|
69
69
|
platform: 'browser',
|
|
@@ -79,7 +79,6 @@ function createBrowserPolyfillBundleOptions(options, target, sourceFileCache) {
|
|
|
79
79
|
},
|
|
80
80
|
};
|
|
81
81
|
// Only add the Angular TypeScript compiler if TypeScript files are provided in the polyfills
|
|
82
|
-
const hasTypeScriptEntries = polyfills?.some((entry) => /\.[cm]?tsx?$/.test(entry));
|
|
83
82
|
if (hasTypeScriptEntries) {
|
|
84
83
|
buildOptions.plugins ??= [];
|
|
85
84
|
const { pluginOptions, styleOptions } = (0, compiler_plugin_options_1.createCompilerPluginOptions)(options, target, sourceFileCache);
|
|
@@ -89,7 +88,10 @@ function createBrowserPolyfillBundleOptions(options, target, sourceFileCache) {
|
|
|
89
88
|
// Component stylesheet options are unused for polyfills but required by the plugin
|
|
90
89
|
styleOptions));
|
|
91
90
|
}
|
|
92
|
-
|
|
91
|
+
// Use an options factory to allow fully incremental bundling when no TypeScript files are present.
|
|
92
|
+
// The TypeScript compilation is not currently integrated into the bundler invalidation so
|
|
93
|
+
// cannot be used with fully incremental bundling yet.
|
|
94
|
+
return hasTypeScriptEntries ? buildOptions : () => buildOptions;
|
|
93
95
|
}
|
|
94
96
|
exports.createBrowserPolyfillBundleOptions = createBrowserPolyfillBundleOptions;
|
|
95
97
|
/**
|
|
@@ -195,7 +197,7 @@ function createServerPolyfillBundleOptions(options, target, sourceFileCache) {
|
|
|
195
197
|
if (!polyfillBundleOptions) {
|
|
196
198
|
return;
|
|
197
199
|
}
|
|
198
|
-
const { workspaceRoot
|
|
200
|
+
const { workspaceRoot } = options;
|
|
199
201
|
const buildOptions = {
|
|
200
202
|
...polyfillBundleOptions,
|
|
201
203
|
platform: 'node',
|
|
@@ -232,14 +234,8 @@ function createServerPolyfillBundleOptions(options, target, sourceFileCache) {
|
|
|
232
234
|
}),
|
|
233
235
|
}));
|
|
234
236
|
}
|
|
235
|
-
buildOptions.plugins.push((0, rxjs_esm_resolution_plugin_1.createRxjsEsmResolutionPlugin)()
|
|
236
|
-
|
|
237
|
-
sourcemap: !!sourcemapOptions.scripts,
|
|
238
|
-
babelFileCache: sourceFileCache?.babelFileCache,
|
|
239
|
-
advancedOptimizations,
|
|
240
|
-
maxWorkers: 1,
|
|
241
|
-
}));
|
|
242
|
-
return buildOptions;
|
|
237
|
+
buildOptions.plugins.push((0, rxjs_esm_resolution_plugin_1.createRxjsEsmResolutionPlugin)());
|
|
238
|
+
return () => buildOptions;
|
|
243
239
|
}
|
|
244
240
|
exports.createServerPolyfillBundleOptions = createServerPolyfillBundleOptions;
|
|
245
241
|
function getEsBuildCommonOptions(options) {
|
|
@@ -43,7 +43,7 @@ export declare class BundlerContext {
|
|
|
43
43
|
private initialFilter?;
|
|
44
44
|
readonly watchFiles: Set<string>;
|
|
45
45
|
constructor(workspaceRoot: string, incremental: boolean, options: BuildOptions | BundlerOptionsFactory, initialFilter?: ((initial: Readonly<InitialFileRecord>) => boolean) | undefined);
|
|
46
|
-
static bundleAll(contexts: Iterable<BundlerContext>): Promise<BundleContextResult>;
|
|
46
|
+
static bundleAll(contexts: Iterable<BundlerContext>, changedFiles?: Iterable<string>): Promise<BundleContextResult>;
|
|
47
47
|
/**
|
|
48
48
|
* Executes the esbuild build function and normalizes the build result in the event of a
|
|
49
49
|
* build failure that results in no output being generated.
|
|
@@ -53,8 +53,13 @@ class BundlerContext {
|
|
|
53
53
|
};
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
|
-
static async bundleAll(contexts) {
|
|
57
|
-
const individualResults = await Promise.all([...contexts].map((context) =>
|
|
56
|
+
static async bundleAll(contexts, changedFiles) {
|
|
57
|
+
const individualResults = await Promise.all([...contexts].map((context) => {
|
|
58
|
+
if (changedFiles) {
|
|
59
|
+
context.invalidate(changedFiles);
|
|
60
|
+
}
|
|
61
|
+
return context.bundle();
|
|
62
|
+
}));
|
|
58
63
|
// Return directly if only one result
|
|
59
64
|
if (individualResults.length === 1) {
|
|
60
65
|
return individualResults[0];
|
|
@@ -17,6 +17,7 @@ export interface RebuildState {
|
|
|
17
17
|
rebuildContexts: BundlerContext[];
|
|
18
18
|
codeBundleCache?: SourceFileCache;
|
|
19
19
|
fileChanges: ChangedFiles;
|
|
20
|
+
previousOutputHashes: Map<string, string>;
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
22
23
|
* Represents the result of a single builder execute call.
|
|
@@ -57,5 +58,6 @@ export declare class ExecutionResult {
|
|
|
57
58
|
};
|
|
58
59
|
get watchFiles(): string[];
|
|
59
60
|
createRebuildState(fileChanges: ChangedFiles): RebuildState;
|
|
61
|
+
findChangedFiles(previousOutputHashes: Map<string, string>): Set<string>;
|
|
60
62
|
dispose(): Promise<void>;
|
|
61
63
|
}
|