Skip to content

Commit 4f4f9c9

Browse files
clydindgp1130
authored andcommitted
refactor(@angular-devkit/build-angular): move esbuild builder global stylesheet bundling into separate function
The global stylesheet bundling and processing code has been moved out of the main builder execution function and into a separate function. This shortens the length of the main execution function for the builder and also allows for further refactoring to allow the code and global stylesheet bundling to be executed at the same time.
1 parent cf3222f commit 4f4f9c9

File tree

1 file changed

+90
-55
lines changed
  • packages/angular_devkit/build_angular/src/builders/browser-esbuild

1 file changed

+90
-55
lines changed

packages/angular_devkit/build_angular/src/builders/browser-esbuild/index.ts

+90-55
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect';
1010
import * as assert from 'assert';
11-
import type { OutputFile } from 'esbuild';
11+
import type { Message, OutputFile } from 'esbuild';
1212
import { promises as fs } from 'fs';
1313
import * as path from 'path';
1414
import { NormalizedOptimizationOptions, deleteOutputDir } from '../../utils';
@@ -144,62 +144,22 @@ export async function buildEsbuildBrowser(
144144
}
145145

146146
// Process global stylesheets
147-
if (options.styles) {
148-
// resolveGlobalStyles is temporarily reused from the Webpack builder code
149-
const { entryPoints: stylesheetEntrypoints, noInjectNames } = resolveGlobalStyles(
150-
options.styles,
151-
workspaceRoot,
152-
// preserveSymlinks is always true here to allow the bundler to handle the option
153-
true,
154-
// skipResolution to leverage the bundler's more comprehensive resolution
155-
true,
156-
);
157-
for (const [name, files] of Object.entries(stylesheetEntrypoints)) {
158-
const virtualEntryData = files
159-
.map((file) => `@import '${file.replace(/\\/g, '/')}';`)
160-
.join('\n');
161-
const sheetResult = await bundleStylesheetText(
162-
virtualEntryData,
163-
{ virtualName: `angular:style/global;${name}`, resolvePath: workspaceRoot },
164-
{
165-
workspaceRoot,
166-
optimization: !!optimizationOptions.styles.minify,
167-
sourcemap: !!sourcemapOptions.styles && (sourcemapOptions.hidden ? 'external' : true),
168-
outputNames: noInjectNames.includes(name) ? { media: outputNames.media } : outputNames,
169-
includePaths: options.stylePreprocessorOptions?.includePaths,
170-
preserveSymlinks: options.preserveSymlinks,
171-
externalDependencies: options.externalDependencies,
172-
},
173-
);
174-
175-
await logMessages(context, sheetResult);
176-
if (!sheetResult.path) {
177-
// Failed to process the stylesheet
178-
assert.ok(
179-
sheetResult.errors.length,
180-
`Global stylesheet processing for '${name}' failed with no errors.`,
181-
);
147+
const styleResults = await bundleGlobalStylesheets(
148+
workspaceRoot,
149+
outputNames,
150+
options,
151+
optimizationOptions,
152+
sourcemapOptions,
153+
);
154+
outputFiles.push(...styleResults.outputFiles);
155+
initialFiles.push(...styleResults.initialFiles);
182156

183-
return { success: false };
184-
}
157+
// Log all warnings and errors generated during bundling
158+
await logMessages(context, styleResults);
185159

186-
// The virtual stylesheets will be named `stdin` by esbuild. This must be replaced
187-
// with the actual name of the global style and the leading directory separator must
188-
// also be removed to make the path relative.
189-
const sheetPath = sheetResult.path.replace('stdin', name);
190-
outputFiles.push(createOutputFileFromText(sheetPath, sheetResult.contents));
191-
if (sheetResult.map) {
192-
outputFiles.push(createOutputFileFromText(sheetPath + '.map', sheetResult.map));
193-
}
194-
if (!noInjectNames.includes(name)) {
195-
initialFiles.push({
196-
file: sheetPath,
197-
name,
198-
extension: '.css',
199-
});
200-
}
201-
outputFiles.push(...sheetResult.resourceFiles);
202-
}
160+
// Return if the bundling has errors
161+
if (styleResults.errors.length) {
162+
return { success: false };
203163
}
204164

205165
// Generate index HTML file
@@ -366,4 +326,79 @@ async function bundleCode(
366326
});
367327
}
368328

329+
async function bundleGlobalStylesheets(
330+
workspaceRoot: string,
331+
outputNames: { bundles: string; media: string },
332+
options: BrowserBuilderOptions,
333+
optimizationOptions: NormalizedOptimizationOptions,
334+
sourcemapOptions: SourceMapClass,
335+
) {
336+
const outputFiles: OutputFile[] = [];
337+
const initialFiles: FileInfo[] = [];
338+
const errors: Message[] = [];
339+
const warnings: Message[] = [];
340+
341+
// resolveGlobalStyles is temporarily reused from the Webpack builder code
342+
const { entryPoints: stylesheetEntrypoints, noInjectNames } = resolveGlobalStyles(
343+
options.styles || [],
344+
workspaceRoot,
345+
// preserveSymlinks is always true here to allow the bundler to handle the option
346+
true,
347+
// skipResolution to leverage the bundler's more comprehensive resolution
348+
true,
349+
);
350+
351+
for (const [name, files] of Object.entries(stylesheetEntrypoints)) {
352+
const virtualEntryData = files
353+
.map((file) => `@import '${file.replace(/\\/g, '/')}';`)
354+
.join('\n');
355+
const sheetResult = await bundleStylesheetText(
356+
virtualEntryData,
357+
{ virtualName: `angular:style/global;${name}`, resolvePath: workspaceRoot },
358+
{
359+
workspaceRoot,
360+
optimization: !!optimizationOptions.styles.minify,
361+
sourcemap: !!sourcemapOptions.styles && (sourcemapOptions.hidden ? 'external' : true),
362+
outputNames: noInjectNames.includes(name) ? { media: outputNames.media } : outputNames,
363+
includePaths: options.stylePreprocessorOptions?.includePaths,
364+
preserveSymlinks: options.preserveSymlinks,
365+
externalDependencies: options.externalDependencies,
366+
},
367+
);
368+
369+
errors.push(...sheetResult.errors);
370+
warnings.push(...sheetResult.warnings);
371+
372+
if (!sheetResult.path) {
373+
// Failed to process the stylesheet
374+
assert.ok(
375+
sheetResult.errors.length,
376+
`Global stylesheet processing for '${name}' failed with no errors.`,
377+
);
378+
379+
continue;
380+
}
381+
382+
// The virtual stylesheets will be named `stdin` by esbuild. This must be replaced
383+
// with the actual name of the global style and the leading directory separator must
384+
// also be removed to make the path relative.
385+
const sheetPath = sheetResult.path.replace('stdin', name);
386+
outputFiles.push(createOutputFileFromText(sheetPath, sheetResult.contents));
387+
if (sheetResult.map) {
388+
outputFiles.push(createOutputFileFromText(sheetPath + '.map', sheetResult.map));
389+
}
390+
391+
if (!noInjectNames.includes(name)) {
392+
initialFiles.push({
393+
file: sheetPath,
394+
name,
395+
extension: '.css',
396+
});
397+
}
398+
outputFiles.push(...sheetResult.resourceFiles);
399+
}
400+
401+
return { outputFiles, initialFiles, errors, warnings };
402+
}
403+
369404
export default createBuilder(buildEsbuildBrowser);

0 commit comments

Comments
 (0)