@angular-devkit/build-angular 15.0.0-next.3 → 15.0.0-next.4
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 +12 -11
- package/src/builders/browser-esbuild/compiler-plugin.d.ts +9 -2
- package/src/builders/browser-esbuild/compiler-plugin.js +114 -90
- package/src/builders/browser-esbuild/esbuild.d.ts +4 -3
- package/src/builders/browser-esbuild/esbuild.js +12 -6
- package/src/builders/browser-esbuild/experimental-warnings.js +0 -3
- package/src/builders/browser-esbuild/index.d.ts +3 -3
- package/src/builders/browser-esbuild/index.js +143 -86
- package/src/builders/browser-esbuild/options.d.ts +26 -4
- package/src/builders/browser-esbuild/options.js +56 -5
- package/src/builders/browser-esbuild/watcher.d.ts +23 -0
- package/src/builders/browser-esbuild/watcher.js +93 -0
- package/src/builders/karma/index.d.ts +1 -1
- package/src/builders/karma/index.js +50 -9
- package/src/builders/karma/schema.d.ts +1 -1
- package/src/builders/karma/schema.json +1 -1
- package/src/utils/process-bundle.js +1 -1
- package/src/utils/service-worker.d.ts +3 -0
- package/src/utils/service-worker.js +29 -2
- package/src/webpack/configs/common.js +2 -2
- package/src/webpack/configs/styles.d.ts +1 -7
- package/src/webpack/configs/styles.js +53 -60
- package/src/webpack/plugins/scripts-webpack-plugin.js +24 -5
- package/src/webpack/plugins/styles-webpack-plugin.d.ts +19 -0
- package/src/webpack/plugins/styles-webpack-plugin.js +71 -0
- package/src/webpack/utils/helpers.d.ts +5 -1
- package/src/webpack/utils/helpers.js +24 -14
|
@@ -33,67 +33,62 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
33
33
|
exports.buildEsbuildBrowser = void 0;
|
|
34
34
|
const architect_1 = require("@angular-devkit/architect");
|
|
35
35
|
const assert = __importStar(require("assert"));
|
|
36
|
-
const
|
|
36
|
+
const fs = __importStar(require("fs/promises"));
|
|
37
37
|
const path = __importStar(require("path"));
|
|
38
38
|
const utils_1 = require("../../utils");
|
|
39
39
|
const copy_assets_1 = require("../../utils/copy-assets");
|
|
40
40
|
const error_1 = require("../../utils/error");
|
|
41
41
|
const esbuild_targets_1 = require("../../utils/esbuild-targets");
|
|
42
42
|
const index_html_generator_1 = require("../../utils/index-file/index-html-generator");
|
|
43
|
-
const package_chunk_sort_1 = require("../../utils/package-chunk-sort");
|
|
44
43
|
const service_worker_1 = require("../../utils/service-worker");
|
|
45
44
|
const supported_browsers_1 = require("../../utils/supported-browsers");
|
|
46
|
-
const webpack_browser_config_1 = require("../../utils/webpack-browser-config");
|
|
47
|
-
const configs_1 = require("../../webpack/configs");
|
|
48
45
|
const compiler_plugin_1 = require("./compiler-plugin");
|
|
49
46
|
const esbuild_1 = require("./esbuild");
|
|
50
47
|
const experimental_warnings_1 = require("./experimental-warnings");
|
|
51
48
|
const options_1 = require("./options");
|
|
52
49
|
const stylesheets_1 = require("./stylesheets");
|
|
50
|
+
const watcher_1 = require("./watcher");
|
|
53
51
|
/**
|
|
54
|
-
*
|
|
55
|
-
* The options are compatible with the Webpack-based builder.
|
|
56
|
-
* @param options The browser builder options to use when setting up the application build
|
|
57
|
-
* @param context The Architect builder context object
|
|
58
|
-
* @returns A promise with the builder result output
|
|
52
|
+
* Represents the result of a single builder execute call.
|
|
59
53
|
*/
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (options.aot !== true) {
|
|
66
|
-
context.logger.error('JIT mode is currently not supported by this experimental builder. AOT mode must be used.');
|
|
67
|
-
return { success: false };
|
|
68
|
-
}
|
|
69
|
-
// Inform user of experimental status of builder and options
|
|
70
|
-
(0, experimental_warnings_1.logExperimentalWarnings)(options, context);
|
|
71
|
-
// Determine project name from builder context target
|
|
72
|
-
const projectName = (_a = context.target) === null || _a === void 0 ? void 0 : _a.project;
|
|
73
|
-
if (!projectName) {
|
|
74
|
-
context.logger.error(`The 'browser-esbuild' builder requires a target to be specified.`);
|
|
75
|
-
return { success: false };
|
|
54
|
+
class ExecutionResult {
|
|
55
|
+
constructor(success, codeRebuild, codeBundleCache) {
|
|
56
|
+
this.success = success;
|
|
57
|
+
this.codeRebuild = codeRebuild;
|
|
58
|
+
this.codeBundleCache = codeBundleCache;
|
|
76
59
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
60
|
+
get output() {
|
|
61
|
+
return {
|
|
62
|
+
success: this.success,
|
|
63
|
+
};
|
|
81
64
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
65
|
+
createRebuildState(fileChanges) {
|
|
66
|
+
var _a;
|
|
67
|
+
(_a = this.codeBundleCache) === null || _a === void 0 ? void 0 : _a.invalidate([...fileChanges.modified, ...fileChanges.removed]);
|
|
68
|
+
return {
|
|
69
|
+
codeRebuild: this.codeRebuild,
|
|
70
|
+
codeBundleCache: this.codeBundleCache,
|
|
71
|
+
fileChanges,
|
|
72
|
+
};
|
|
85
73
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return { success: false };
|
|
74
|
+
dispose() {
|
|
75
|
+
var _a;
|
|
76
|
+
(_a = this.codeRebuild) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
90
77
|
}
|
|
78
|
+
}
|
|
79
|
+
async function execute(options, context, rebuildState) {
|
|
80
|
+
var _a, _b, _c, _d;
|
|
81
|
+
const startTime = Date.now();
|
|
82
|
+
const { projectRoot, workspaceRoot, optimizationOptions, outputPath, assets, serviceWorkerOptions, indexHtmlOptions, } = options;
|
|
91
83
|
const target = (0, esbuild_targets_1.transformSupportedBrowsersToTargets)((0, supported_browsers_1.getSupportedBrowsers)(projectRoot, context.logger));
|
|
84
|
+
const codeBundleCache = options.watch
|
|
85
|
+
? (_a = rebuildState === null || rebuildState === void 0 ? void 0 : rebuildState.codeBundleCache) !== null && _a !== void 0 ? _a : new compiler_plugin_1.SourceFileCache()
|
|
86
|
+
: undefined;
|
|
92
87
|
const [codeResults, styleResults] = await Promise.all([
|
|
93
88
|
// Execute esbuild to bundle the application code
|
|
94
|
-
|
|
89
|
+
(0, esbuild_1.bundle)((_b = rebuildState === null || rebuildState === void 0 ? void 0 : rebuildState.codeRebuild) !== null && _b !== void 0 ? _b : createCodeBundleOptions(options, target, codeBundleCache)),
|
|
95
90
|
// Execute esbuild to bundle the global stylesheets
|
|
96
|
-
bundleGlobalStylesheets(
|
|
91
|
+
bundleGlobalStylesheets(options, target),
|
|
97
92
|
]);
|
|
98
93
|
// Log all warnings and errors generated during bundling
|
|
99
94
|
await (0, esbuild_1.logMessages)(context, {
|
|
@@ -102,7 +97,7 @@ async function buildEsbuildBrowser(options, context) {
|
|
|
102
97
|
});
|
|
103
98
|
// Return if the bundling failed to generate output files or there are errors
|
|
104
99
|
if (!codeResults.outputFiles || codeResults.errors.length) {
|
|
105
|
-
return
|
|
100
|
+
return new ExecutionResult(false, rebuildState === null || rebuildState === void 0 ? void 0 : rebuildState.codeRebuild, codeBundleCache);
|
|
106
101
|
}
|
|
107
102
|
// Structure the code bundling output files
|
|
108
103
|
const initialFiles = [];
|
|
@@ -110,13 +105,14 @@ async function buildEsbuildBrowser(options, context) {
|
|
|
110
105
|
for (const outputFile of codeResults.outputFiles) {
|
|
111
106
|
// Entries in the metafile are relative to the `absWorkingDir` option which is set to the workspaceRoot
|
|
112
107
|
const relativeFilePath = path.relative(workspaceRoot, outputFile.path);
|
|
113
|
-
const entryPoint = (
|
|
108
|
+
const entryPoint = (_d = (_c = codeResults.metafile) === null || _c === void 0 ? void 0 : _c.outputs[relativeFilePath]) === null || _d === void 0 ? void 0 : _d.entryPoint;
|
|
114
109
|
outputFile.path = relativeFilePath;
|
|
115
110
|
if (entryPoint) {
|
|
116
111
|
// An entryPoint value indicates an initial file
|
|
117
112
|
initialFiles.push({
|
|
118
113
|
file: outputFile.path,
|
|
119
|
-
|
|
114
|
+
// The first part of the filename is the name of file (e.g., "polyfills" for "polyfills.7S5G3MDY.js")
|
|
115
|
+
name: path.basename(outputFile.path).split('.')[0],
|
|
120
116
|
extension: path.extname(outputFile.path),
|
|
121
117
|
});
|
|
122
118
|
}
|
|
@@ -127,18 +123,14 @@ async function buildEsbuildBrowser(options, context) {
|
|
|
127
123
|
initialFiles.push(...styleResults.initialFiles);
|
|
128
124
|
// Return if the global stylesheet bundling has errors
|
|
129
125
|
if (styleResults.errors.length) {
|
|
130
|
-
return
|
|
126
|
+
return new ExecutionResult(false, codeResults.rebuild, codeBundleCache);
|
|
131
127
|
}
|
|
132
128
|
// Generate index HTML file
|
|
133
|
-
if (
|
|
134
|
-
const entrypoints = (0, package_chunk_sort_1.generateEntryPoints)({
|
|
135
|
-
scripts: (_e = options.scripts) !== null && _e !== void 0 ? _e : [],
|
|
136
|
-
styles: (_f = options.styles) !== null && _f !== void 0 ? _f : [],
|
|
137
|
-
});
|
|
129
|
+
if (indexHtmlOptions) {
|
|
138
130
|
// Create an index HTML generator that reads from the in-memory output files
|
|
139
131
|
const indexHtmlGenerator = new index_html_generator_1.IndexHtmlGenerator({
|
|
140
|
-
indexPath:
|
|
141
|
-
entrypoints,
|
|
132
|
+
indexPath: indexHtmlOptions.input,
|
|
133
|
+
entrypoints: indexHtmlOptions.insertionOrder,
|
|
142
134
|
sri: options.subresourceIntegrity,
|
|
143
135
|
optimization: optimizationOptions,
|
|
144
136
|
crossOrigin: options.crossOrigin,
|
|
@@ -166,29 +158,28 @@ async function buildEsbuildBrowser(options, context) {
|
|
|
166
158
|
for (const warning of warnings) {
|
|
167
159
|
context.logger.warn(warning);
|
|
168
160
|
}
|
|
169
|
-
outputFiles.push(createOutputFileFromText(
|
|
161
|
+
outputFiles.push(createOutputFileFromText(indexHtmlOptions.output, content));
|
|
170
162
|
}
|
|
171
163
|
// Copy assets
|
|
172
164
|
if (assets) {
|
|
173
165
|
await (0, copy_assets_1.copyAssets)(assets, [outputPath], workspaceRoot);
|
|
174
166
|
}
|
|
175
167
|
// Write output files
|
|
176
|
-
await Promise.all(outputFiles.map((file) =>
|
|
168
|
+
await Promise.all(outputFiles.map((file) => fs.writeFile(path.join(outputPath, file.path), file.contents)));
|
|
177
169
|
// Augment the application with service worker support
|
|
178
170
|
// TODO: This should eventually operate on the in-memory files prior to writing the output files
|
|
179
|
-
if (
|
|
171
|
+
if (serviceWorkerOptions) {
|
|
180
172
|
try {
|
|
181
|
-
await (0, service_worker_1.
|
|
173
|
+
await (0, service_worker_1.augmentAppWithServiceWorkerEsbuild)(workspaceRoot, serviceWorkerOptions, outputPath, options.baseHref || '/');
|
|
182
174
|
}
|
|
183
175
|
catch (error) {
|
|
184
176
|
context.logger.error(error instanceof Error ? error.message : `${error}`);
|
|
185
|
-
return
|
|
177
|
+
return new ExecutionResult(false, codeResults.rebuild, codeBundleCache);
|
|
186
178
|
}
|
|
187
179
|
}
|
|
188
180
|
context.logger.info(`Complete. [${(Date.now() - startTime) / 1000} seconds]`);
|
|
189
|
-
return
|
|
181
|
+
return new ExecutionResult(true, codeResults.rebuild, codeBundleCache);
|
|
190
182
|
}
|
|
191
|
-
exports.buildEsbuildBrowser = buildEsbuildBrowser;
|
|
192
183
|
function createOutputFileFromText(path, text) {
|
|
193
184
|
return {
|
|
194
185
|
path,
|
|
@@ -198,18 +189,12 @@ function createOutputFileFromText(path, text) {
|
|
|
198
189
|
},
|
|
199
190
|
};
|
|
200
191
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (options.fileReplacements) {
|
|
205
|
-
for (const replacement of options.fileReplacements) {
|
|
206
|
-
fileReplacements !== null && fileReplacements !== void 0 ? fileReplacements : (fileReplacements = {});
|
|
207
|
-
fileReplacements[path.join(workspaceRoot, replacement.replace)] = path.join(workspaceRoot, replacement.with);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
return (0, esbuild_1.bundle)({
|
|
192
|
+
function createCodeBundleOptions(options, target, sourceFileCache) {
|
|
193
|
+
const { workspaceRoot, entryPoints, optimizationOptions, sourcemapOptions, tsconfig, outputNames, fileReplacements, externalDependencies, preserveSymlinks, stylePreprocessorOptions, advancedOptimizations, } = options;
|
|
194
|
+
return {
|
|
211
195
|
absWorkingDir: workspaceRoot,
|
|
212
196
|
bundle: true,
|
|
197
|
+
incremental: options.watch,
|
|
213
198
|
format: 'esm',
|
|
214
199
|
entryPoints,
|
|
215
200
|
entryNames: outputNames.bundles,
|
|
@@ -234,10 +219,10 @@ async function bundleCode(workspaceRoot, entryPoints, outputNames, options, opti
|
|
|
234
219
|
sourcemap: sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true),
|
|
235
220
|
splitting: true,
|
|
236
221
|
tsconfig,
|
|
237
|
-
external:
|
|
222
|
+
external: externalDependencies,
|
|
238
223
|
write: false,
|
|
239
224
|
platform: 'browser',
|
|
240
|
-
preserveSymlinks
|
|
225
|
+
preserveSymlinks,
|
|
241
226
|
plugins: [
|
|
242
227
|
(0, compiler_plugin_1.createCompilerPlugin)(
|
|
243
228
|
// JS/TS options
|
|
@@ -245,8 +230,9 @@ async function bundleCode(workspaceRoot, entryPoints, outputNames, options, opti
|
|
|
245
230
|
sourcemap: !!sourcemapOptions.scripts,
|
|
246
231
|
thirdPartySourcemaps: sourcemapOptions.vendor,
|
|
247
232
|
tsconfig,
|
|
248
|
-
advancedOptimizations
|
|
233
|
+
advancedOptimizations,
|
|
249
234
|
fileReplacements,
|
|
235
|
+
sourceFileCache,
|
|
250
236
|
},
|
|
251
237
|
// Component stylesheet options
|
|
252
238
|
{
|
|
@@ -258,8 +244,8 @@ async function bundleCode(workspaceRoot, entryPoints, outputNames, options, opti
|
|
|
258
244
|
// of sourcemap processing.
|
|
259
245
|
!!sourcemapOptions.styles && (sourcemapOptions.hidden ? false : 'inline'),
|
|
260
246
|
outputNames,
|
|
261
|
-
includePaths:
|
|
262
|
-
externalDependencies
|
|
247
|
+
includePaths: stylePreprocessorOptions === null || stylePreprocessorOptions === void 0 ? void 0 : stylePreprocessorOptions.includePaths,
|
|
248
|
+
externalDependencies,
|
|
263
249
|
target,
|
|
264
250
|
}),
|
|
265
251
|
],
|
|
@@ -267,21 +253,15 @@ async function bundleCode(workspaceRoot, entryPoints, outputNames, options, opti
|
|
|
267
253
|
...(optimizationOptions.scripts ? { 'ngDevMode': 'false' } : undefined),
|
|
268
254
|
'ngJitMode': 'false',
|
|
269
255
|
},
|
|
270
|
-
}
|
|
256
|
+
};
|
|
271
257
|
}
|
|
272
|
-
async function bundleGlobalStylesheets(
|
|
273
|
-
|
|
258
|
+
async function bundleGlobalStylesheets(options, target) {
|
|
259
|
+
const { workspaceRoot, optimizationOptions, sourcemapOptions, outputNames, globalStyles, preserveSymlinks, externalDependencies, stylePreprocessorOptions, } = options;
|
|
274
260
|
const outputFiles = [];
|
|
275
261
|
const initialFiles = [];
|
|
276
262
|
const errors = [];
|
|
277
263
|
const warnings = [];
|
|
278
|
-
|
|
279
|
-
const { entryPoints: stylesheetEntrypoints, noInjectNames } = (0, configs_1.resolveGlobalStyles)(options.styles || [], workspaceRoot,
|
|
280
|
-
// preserveSymlinks is always true here to allow the bundler to handle the option
|
|
281
|
-
true,
|
|
282
|
-
// skipResolution to leverage the bundler's more comprehensive resolution
|
|
283
|
-
true);
|
|
284
|
-
for (const [name, files] of Object.entries(stylesheetEntrypoints)) {
|
|
264
|
+
for (const { name, files, initial } of globalStyles) {
|
|
285
265
|
const virtualEntryData = files
|
|
286
266
|
.map((file) => `@import '${file.replace(/\\/g, '/')}';`)
|
|
287
267
|
.join('\n');
|
|
@@ -289,10 +269,10 @@ async function bundleGlobalStylesheets(workspaceRoot, outputNames, options, opti
|
|
|
289
269
|
workspaceRoot,
|
|
290
270
|
optimization: !!optimizationOptions.styles.minify,
|
|
291
271
|
sourcemap: !!sourcemapOptions.styles && (sourcemapOptions.hidden ? 'external' : true),
|
|
292
|
-
outputNames:
|
|
293
|
-
includePaths:
|
|
294
|
-
preserveSymlinks
|
|
295
|
-
externalDependencies
|
|
272
|
+
outputNames: initial ? outputNames : { media: outputNames.media },
|
|
273
|
+
includePaths: stylePreprocessorOptions === null || stylePreprocessorOptions === void 0 ? void 0 : stylePreprocessorOptions.includePaths,
|
|
274
|
+
preserveSymlinks,
|
|
275
|
+
externalDependencies,
|
|
296
276
|
target,
|
|
297
277
|
});
|
|
298
278
|
errors.push(...sheetResult.errors);
|
|
@@ -312,7 +292,7 @@ async function bundleGlobalStylesheets(workspaceRoot, outputNames, options, opti
|
|
|
312
292
|
sheetContents = sheetContents.replace('sourceMappingURL=stdin.css.map', `sourceMappingURL=${name}.css.map`);
|
|
313
293
|
}
|
|
314
294
|
outputFiles.push(createOutputFileFromText(sheetPath, sheetContents));
|
|
315
|
-
if (
|
|
295
|
+
if (initial) {
|
|
316
296
|
initialFiles.push({
|
|
317
297
|
file: sheetPath,
|
|
318
298
|
name,
|
|
@@ -323,4 +303,81 @@ async function bundleGlobalStylesheets(workspaceRoot, outputNames, options, opti
|
|
|
323
303
|
}
|
|
324
304
|
return { outputFiles, initialFiles, errors, warnings };
|
|
325
305
|
}
|
|
306
|
+
/**
|
|
307
|
+
* Main execution function for the esbuild-based application builder.
|
|
308
|
+
* The options are compatible with the Webpack-based builder.
|
|
309
|
+
* @param initialOptions The browser builder options to use when setting up the application build
|
|
310
|
+
* @param context The Architect builder context object
|
|
311
|
+
* @returns An async iterable with the builder result output
|
|
312
|
+
*/
|
|
313
|
+
async function* buildEsbuildBrowser(initialOptions, context) {
|
|
314
|
+
var _a;
|
|
315
|
+
// Only AOT is currently supported
|
|
316
|
+
if (initialOptions.aot !== true) {
|
|
317
|
+
context.logger.error('JIT mode is currently not supported by this experimental builder. AOT mode must be used.');
|
|
318
|
+
return { success: false };
|
|
319
|
+
}
|
|
320
|
+
// Inform user of experimental status of builder and options
|
|
321
|
+
(0, experimental_warnings_1.logExperimentalWarnings)(initialOptions, context);
|
|
322
|
+
// Determine project name from builder context target
|
|
323
|
+
const projectName = (_a = context.target) === null || _a === void 0 ? void 0 : _a.project;
|
|
324
|
+
if (!projectName) {
|
|
325
|
+
context.logger.error(`The 'browser-esbuild' builder requires a target to be specified.`);
|
|
326
|
+
return { success: false };
|
|
327
|
+
}
|
|
328
|
+
const normalizedOptions = await (0, options_1.normalizeOptions)(context, projectName, initialOptions);
|
|
329
|
+
// Clean output path if enabled
|
|
330
|
+
if (initialOptions.deleteOutputPath) {
|
|
331
|
+
(0, utils_1.deleteOutputDir)(normalizedOptions.workspaceRoot, initialOptions.outputPath);
|
|
332
|
+
}
|
|
333
|
+
// Create output directory if needed
|
|
334
|
+
try {
|
|
335
|
+
await fs.mkdir(normalizedOptions.outputPath, { recursive: true });
|
|
336
|
+
}
|
|
337
|
+
catch (e) {
|
|
338
|
+
(0, error_1.assertIsError)(e);
|
|
339
|
+
context.logger.error('Unable to create output directory: ' + e.message);
|
|
340
|
+
return { success: false };
|
|
341
|
+
}
|
|
342
|
+
// Initial build
|
|
343
|
+
let result = await execute(normalizedOptions, context);
|
|
344
|
+
yield result.output;
|
|
345
|
+
// Finish if watch mode is not enabled
|
|
346
|
+
if (!initialOptions.watch) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
context.logger.info('Watch mode enabled. Watching for file changes...');
|
|
350
|
+
// Setup a watcher
|
|
351
|
+
const watcher = (0, watcher_1.createWatcher)({
|
|
352
|
+
polling: typeof initialOptions.poll === 'number',
|
|
353
|
+
interval: initialOptions.poll,
|
|
354
|
+
// Ignore the output path to avoid infinite rebuild cycles
|
|
355
|
+
ignored: [normalizedOptions.outputPath],
|
|
356
|
+
});
|
|
357
|
+
// Temporarily watch the entire project
|
|
358
|
+
watcher.add(normalizedOptions.projectRoot);
|
|
359
|
+
// Watch workspace root node modules
|
|
360
|
+
// Includes Yarn PnP manifest files (https://yarnpkg.com/advanced/pnp-spec/)
|
|
361
|
+
watcher.add(path.join(normalizedOptions.workspaceRoot, 'node_modules'));
|
|
362
|
+
watcher.add(path.join(normalizedOptions.workspaceRoot, '.pnp.cjs'));
|
|
363
|
+
watcher.add(path.join(normalizedOptions.workspaceRoot, '.pnp.data.json'));
|
|
364
|
+
// Wait for changes and rebuild as needed
|
|
365
|
+
try {
|
|
366
|
+
for await (const changes of watcher) {
|
|
367
|
+
context.logger.info('Changes detected. Rebuilding...');
|
|
368
|
+
if (initialOptions.verbose) {
|
|
369
|
+
context.logger.info(changes.toDebugString());
|
|
370
|
+
}
|
|
371
|
+
result = await execute(normalizedOptions, context, result.createRebuildState(changes));
|
|
372
|
+
yield result.output;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
finally {
|
|
376
|
+
// Stop the watcher
|
|
377
|
+
await watcher.close();
|
|
378
|
+
// Cleanup incremental rebuild state
|
|
379
|
+
result.dispose();
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
exports.buildEsbuildBrowser = buildEsbuildBrowser;
|
|
326
383
|
exports.default = (0, architect_1.createBuilder)(buildEsbuildBrowser);
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* found in the LICENSE file at https://angular.io/license
|
|
7
7
|
*/
|
|
8
8
|
import { BuilderContext } from '@angular-devkit/architect';
|
|
9
|
-
import { Schema as BrowserBuilderOptions } from '
|
|
9
|
+
import { Schema as BrowserBuilderOptions } from './schema';
|
|
10
|
+
export declare type NormalizedBrowserOptions = Awaited<ReturnType<typeof normalizeOptions>>;
|
|
10
11
|
/**
|
|
11
12
|
* Normalize the user provided options by creating full paths for all path based options
|
|
12
13
|
* and converting multi-form options into a single form that can be directly used
|
|
@@ -18,17 +19,38 @@ import { Schema as BrowserBuilderOptions } from '../browser/schema';
|
|
|
18
19
|
* @returns An object containing normalized options required to perform the build.
|
|
19
20
|
*/
|
|
20
21
|
export declare function normalizeOptions(context: BuilderContext, projectName: string, options: BrowserBuilderOptions): Promise<{
|
|
22
|
+
advancedOptimizations: boolean | undefined;
|
|
23
|
+
baseHref: string | undefined;
|
|
24
|
+
crossOrigin: import("./schema").CrossOrigin | undefined;
|
|
25
|
+
externalDependencies: string[] | undefined;
|
|
26
|
+
poll: number | undefined;
|
|
27
|
+
preserveSymlinks: boolean | undefined;
|
|
28
|
+
stylePreprocessorOptions: import("./schema").StylePreprocessorOptions | undefined;
|
|
29
|
+
subresourceIntegrity: boolean | undefined;
|
|
30
|
+
verbose: boolean | undefined;
|
|
31
|
+
watch: boolean | undefined;
|
|
21
32
|
workspaceRoot: string;
|
|
22
33
|
entryPoints: Record<string, string>;
|
|
23
|
-
entryPointNameLookup: ReadonlyMap<string, string>;
|
|
24
34
|
optimizationOptions: import("../../utils").NormalizedOptimizationOptions;
|
|
25
35
|
outputPath: string;
|
|
26
|
-
sourcemapOptions: import("
|
|
36
|
+
sourcemapOptions: import("../..").SourceMapObject;
|
|
27
37
|
tsconfig: string;
|
|
28
38
|
projectRoot: string;
|
|
29
|
-
assets: import("
|
|
39
|
+
assets: import("../..").AssetPatternObject[] | undefined;
|
|
30
40
|
outputNames: {
|
|
31
41
|
bundles: string;
|
|
32
42
|
media: string;
|
|
33
43
|
};
|
|
44
|
+
fileReplacements: Record<string, string> | undefined;
|
|
45
|
+
globalStyles: {
|
|
46
|
+
name: string;
|
|
47
|
+
files: string[];
|
|
48
|
+
initial: boolean;
|
|
49
|
+
}[];
|
|
50
|
+
serviceWorkerOptions: string | undefined;
|
|
51
|
+
indexHtmlOptions: {
|
|
52
|
+
input: string;
|
|
53
|
+
output: string;
|
|
54
|
+
insertionOrder: import("../../utils/package-chunk-sort").EntryPointsType[];
|
|
55
|
+
} | undefined;
|
|
34
56
|
}>;
|
|
@@ -34,7 +34,10 @@ exports.normalizeOptions = void 0;
|
|
|
34
34
|
const path = __importStar(require("path"));
|
|
35
35
|
const utils_1 = require("../../utils");
|
|
36
36
|
const normalize_polyfills_1 = require("../../utils/normalize-polyfills");
|
|
37
|
-
const
|
|
37
|
+
const package_chunk_sort_1 = require("../../utils/package-chunk-sort");
|
|
38
|
+
const webpack_browser_config_1 = require("../../utils/webpack-browser-config");
|
|
39
|
+
const helpers_1 = require("../../webpack/utils/helpers");
|
|
40
|
+
const schema_1 = require("./schema");
|
|
38
41
|
/**
|
|
39
42
|
* Normalize the user provided options by creating full paths for all path based options
|
|
40
43
|
* and converting multi-form options into a single form that can be directly used
|
|
@@ -46,7 +49,7 @@ const schema_1 = require("../browser/schema");
|
|
|
46
49
|
* @returns An object containing normalized options required to perform the build.
|
|
47
50
|
*/
|
|
48
51
|
async function normalizeOptions(context, projectName, options) {
|
|
49
|
-
var _a, _b, _c, _d;
|
|
52
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
50
53
|
const workspaceRoot = context.workspaceRoot;
|
|
51
54
|
const projectMetadata = await context.getProjectMetadata(projectName);
|
|
52
55
|
const projectRoot = path.join(workspaceRoot, (_a = projectMetadata.root) !== null && _a !== void 0 ? _a : '');
|
|
@@ -76,6 +79,27 @@ async function normalizeOptions(context, projectName, options) {
|
|
|
76
79
|
if (options.resourcesOutputPath) {
|
|
77
80
|
outputNames.media = path.join(options.resourcesOutputPath, outputNames.media);
|
|
78
81
|
}
|
|
82
|
+
let fileReplacements;
|
|
83
|
+
if (options.fileReplacements) {
|
|
84
|
+
for (const replacement of options.fileReplacements) {
|
|
85
|
+
fileReplacements !== null && fileReplacements !== void 0 ? fileReplacements : (fileReplacements = {});
|
|
86
|
+
fileReplacements[path.join(workspaceRoot, replacement.replace)] = path.join(workspaceRoot, replacement.with);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const globalStyles = [];
|
|
90
|
+
if ((_e = options.styles) === null || _e === void 0 ? void 0 : _e.length) {
|
|
91
|
+
const { entryPoints: stylesheetEntrypoints, noInjectNames } = (0, helpers_1.normalizeGlobalStyles)(options.styles || []);
|
|
92
|
+
for (const [name, files] of Object.entries(stylesheetEntrypoints)) {
|
|
93
|
+
globalStyles.push({ name, files, initial: !noInjectNames.includes(name) });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
let serviceWorkerOptions;
|
|
97
|
+
if (options.serviceWorker) {
|
|
98
|
+
// If ngswConfigPath is not specified, the default is 'ngsw-config.json' within the project root
|
|
99
|
+
serviceWorkerOptions = options.ngswConfigPath
|
|
100
|
+
? path.join(workspaceRoot, options.ngswConfigPath)
|
|
101
|
+
: path.join(projectRoot, 'ngsw-config.json');
|
|
102
|
+
}
|
|
79
103
|
// Setup bundler entry points
|
|
80
104
|
const entryPoints = {
|
|
81
105
|
main: mainEntryPoint,
|
|
@@ -83,12 +107,35 @@ async function normalizeOptions(context, projectName, options) {
|
|
|
83
107
|
if (polyfillsEntryPoint) {
|
|
84
108
|
entryPoints['polyfills'] = polyfillsEntryPoint;
|
|
85
109
|
}
|
|
86
|
-
|
|
87
|
-
|
|
110
|
+
let indexHtmlOptions;
|
|
111
|
+
if (options.index) {
|
|
112
|
+
indexHtmlOptions = {
|
|
113
|
+
input: path.join(workspaceRoot, (0, webpack_browser_config_1.getIndexInputFile)(options.index)),
|
|
114
|
+
// The output file will be created within the configured output path
|
|
115
|
+
output: (0, webpack_browser_config_1.getIndexOutputFile)(options.index),
|
|
116
|
+
// TODO: Use existing information from above to create the insertion order
|
|
117
|
+
insertionOrder: (0, package_chunk_sort_1.generateEntryPoints)({
|
|
118
|
+
scripts: (_f = options.scripts) !== null && _f !== void 0 ? _f : [],
|
|
119
|
+
styles: (_g = options.styles) !== null && _g !== void 0 ? _g : [],
|
|
120
|
+
}),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
// Initial options to keep
|
|
124
|
+
const { baseHref, buildOptimizer, crossOrigin, externalDependencies, poll, preserveSymlinks, stylePreprocessorOptions, subresourceIntegrity, verbose, watch, } = options;
|
|
125
|
+
// Return all the normalized options
|
|
88
126
|
return {
|
|
127
|
+
advancedOptimizations: buildOptimizer,
|
|
128
|
+
baseHref,
|
|
129
|
+
crossOrigin,
|
|
130
|
+
externalDependencies,
|
|
131
|
+
poll,
|
|
132
|
+
preserveSymlinks,
|
|
133
|
+
stylePreprocessorOptions,
|
|
134
|
+
subresourceIntegrity,
|
|
135
|
+
verbose,
|
|
136
|
+
watch,
|
|
89
137
|
workspaceRoot,
|
|
90
138
|
entryPoints,
|
|
91
|
-
entryPointNameLookup,
|
|
92
139
|
optimizationOptions,
|
|
93
140
|
outputPath,
|
|
94
141
|
sourcemapOptions,
|
|
@@ -96,6 +143,10 @@ async function normalizeOptions(context, projectName, options) {
|
|
|
96
143
|
projectRoot,
|
|
97
144
|
assets,
|
|
98
145
|
outputNames,
|
|
146
|
+
fileReplacements,
|
|
147
|
+
globalStyles,
|
|
148
|
+
serviceWorkerOptions,
|
|
149
|
+
indexHtmlOptions,
|
|
99
150
|
};
|
|
100
151
|
}
|
|
101
152
|
exports.normalizeOptions = normalizeOptions;
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
export declare class ChangedFiles {
|
|
9
|
+
readonly added: Set<string>;
|
|
10
|
+
readonly modified: Set<string>;
|
|
11
|
+
readonly removed: Set<string>;
|
|
12
|
+
toDebugString(): string;
|
|
13
|
+
}
|
|
14
|
+
export interface BuildWatcher extends AsyncIterableIterator<ChangedFiles> {
|
|
15
|
+
add(paths: string | string[]): void;
|
|
16
|
+
remove(paths: string | string[]): void;
|
|
17
|
+
close(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export declare function createWatcher(options?: {
|
|
20
|
+
polling?: boolean;
|
|
21
|
+
interval?: number;
|
|
22
|
+
ignored?: string[];
|
|
23
|
+
}): BuildWatcher;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright Google LLC All Rights Reserved.
|
|
5
|
+
*
|
|
6
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
7
|
+
* found in the LICENSE file at https://angular.io/license
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.createWatcher = exports.ChangedFiles = void 0;
|
|
11
|
+
const chokidar_1 = require("chokidar");
|
|
12
|
+
class ChangedFiles {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.added = new Set();
|
|
15
|
+
this.modified = new Set();
|
|
16
|
+
this.removed = new Set();
|
|
17
|
+
}
|
|
18
|
+
toDebugString() {
|
|
19
|
+
const content = {
|
|
20
|
+
added: Array.from(this.added),
|
|
21
|
+
modified: Array.from(this.modified),
|
|
22
|
+
removed: Array.from(this.removed),
|
|
23
|
+
};
|
|
24
|
+
return JSON.stringify(content, null, 2);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.ChangedFiles = ChangedFiles;
|
|
28
|
+
function createWatcher(options) {
|
|
29
|
+
const watcher = new chokidar_1.FSWatcher({
|
|
30
|
+
...options,
|
|
31
|
+
disableGlobbing: true,
|
|
32
|
+
ignoreInitial: true,
|
|
33
|
+
});
|
|
34
|
+
const nextQueue = [];
|
|
35
|
+
let currentChanges;
|
|
36
|
+
watcher.on('all', (event, path) => {
|
|
37
|
+
switch (event) {
|
|
38
|
+
case 'add':
|
|
39
|
+
currentChanges !== null && currentChanges !== void 0 ? currentChanges : (currentChanges = new ChangedFiles());
|
|
40
|
+
currentChanges.added.add(path);
|
|
41
|
+
break;
|
|
42
|
+
case 'change':
|
|
43
|
+
currentChanges !== null && currentChanges !== void 0 ? currentChanges : (currentChanges = new ChangedFiles());
|
|
44
|
+
currentChanges.modified.add(path);
|
|
45
|
+
break;
|
|
46
|
+
case 'unlink':
|
|
47
|
+
currentChanges !== null && currentChanges !== void 0 ? currentChanges : (currentChanges = new ChangedFiles());
|
|
48
|
+
currentChanges.removed.add(path);
|
|
49
|
+
break;
|
|
50
|
+
default:
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const next = nextQueue.shift();
|
|
54
|
+
if (next) {
|
|
55
|
+
const value = currentChanges;
|
|
56
|
+
currentChanges = undefined;
|
|
57
|
+
next(value);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
return {
|
|
61
|
+
[Symbol.asyncIterator]() {
|
|
62
|
+
return this;
|
|
63
|
+
},
|
|
64
|
+
async next() {
|
|
65
|
+
if (currentChanges && nextQueue.length === 0) {
|
|
66
|
+
const result = { value: currentChanges };
|
|
67
|
+
currentChanges = undefined;
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
return new Promise((resolve) => {
|
|
71
|
+
nextQueue.push((value) => resolve(value ? { value } : { done: true, value }));
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
add(paths) {
|
|
75
|
+
watcher.add(paths);
|
|
76
|
+
},
|
|
77
|
+
remove(paths) {
|
|
78
|
+
watcher.unwatch(paths);
|
|
79
|
+
},
|
|
80
|
+
async close() {
|
|
81
|
+
try {
|
|
82
|
+
await watcher.close();
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
let next;
|
|
86
|
+
while ((next = nextQueue.shift()) !== undefined) {
|
|
87
|
+
next();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
exports.createWatcher = createWatcher;
|
|
@@ -23,5 +23,5 @@ export declare function execute(options: KarmaBuilderOptions, context: BuilderCo
|
|
|
23
23
|
karmaOptions?: (options: KarmaConfigOptions) => KarmaConfigOptions;
|
|
24
24
|
}): Observable<BuilderOutput>;
|
|
25
25
|
export { KarmaBuilderOptions };
|
|
26
|
-
declare const _default: import("@angular-devkit/architect/src/internal").Builder<Record<string, string> & KarmaBuilderOptions & import("
|
|
26
|
+
declare const _default: import("@angular-devkit/architect/src/internal").Builder<Record<string, string> & KarmaBuilderOptions & import("@angular-devkit/core").JsonObject>;
|
|
27
27
|
export default _default;
|