Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(@angular/build): create component stylesheet bundler at start of build #28659

Merged
merged 2 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions goldens/circular-deps/packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
"packages/angular_devkit/build_angular/src/builders/dev-server/builder.ts",
"packages/angular_devkit/build_angular/src/builders/dev-server/options.ts"
],
[
"packages/angular/build/src/tools/esbuild/angular/component-stylesheets.ts",
"packages/angular/build/src/tools/esbuild/bundler-context.ts",
"packages/angular/build/src/tools/esbuild/utils.ts",
"packages/angular/build/src/utils/server-rendering/manifest.ts",
"packages/angular/build/src/tools/esbuild/bundler-execution-result.ts"
],
[
"packages/angular/build/src/tools/esbuild/bundler-context.ts",
"packages/angular/build/src/tools/esbuild/utils.ts"
Expand Down
32 changes: 23 additions & 9 deletions packages/angular/build/src/builders/application/execute-build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ import { ExecutionResult, RebuildState } from '../../tools/esbuild/bundler-execu
import { checkCommonJSModules } from '../../tools/esbuild/commonjs-checker';
import { extractLicenses } from '../../tools/esbuild/license-extractor';
import { profileAsync } from '../../tools/esbuild/profiling';
import { calculateEstimatedTransferSizes, logBuildStats } from '../../tools/esbuild/utils';
import {
calculateEstimatedTransferSizes,
logBuildStats,
transformSupportedBrowsersToTargets,
} from '../../tools/esbuild/utils';
import { BudgetCalculatorResult, checkBudgets } from '../../utils/bundle-calculator';
import { shouldOptimizeChunks } from '../../utils/environment-options';
import { resolveAssets } from '../../utils/resolve-assets';
Expand All @@ -29,7 +33,7 @@ import { executePostBundleSteps } from './execute-post-bundle';
import { inlineI18n, loadActiveTranslations } from './i18n';
import { NormalizedApplicationBuildOptions } from './options';
import { OutputMode } from './schema';
import { setupBundlerContexts } from './setup-bundling';
import { createComponentStyleBundler, setupBundlerContexts } from './setup-bundling';

// eslint-disable-next-line max-lines-per-function
export async function executeBuild(
Expand Down Expand Up @@ -63,12 +67,18 @@ export async function executeBuild(
}

// Reuse rebuild state or create new bundle contexts for code and global stylesheets
let bundlerContexts = rebuildState?.rebuildContexts;
const codeBundleCache =
rebuildState?.codeBundleCache ??
new SourceFileCache(cacheOptions.enabled ? cacheOptions.path : undefined);
if (bundlerContexts === undefined) {
bundlerContexts = setupBundlerContexts(options, browsers, codeBundleCache);
let bundlerContexts;
let componentStyleBundler;
let codeBundleCache;
if (rebuildState) {
bundlerContexts = rebuildState.rebuildContexts;
componentStyleBundler = rebuildState.componentStyleBundler;
codeBundleCache = rebuildState.codeBundleCache;
} else {
const target = transformSupportedBrowsersToTargets(browsers);
codeBundleCache = new SourceFileCache(cacheOptions.enabled ? cacheOptions.path : undefined);
componentStyleBundler = createComponentStyleBundler(options, target);
bundlerContexts = setupBundlerContexts(options, target, codeBundleCache, componentStyleBundler);
}

let bundlingResult = await BundlerContext.bundleAll(
Expand All @@ -85,7 +95,11 @@ export async function executeBuild(
);
}

const executionResult = new ExecutionResult(bundlerContexts, codeBundleCache);
const executionResult = new ExecutionResult(
bundlerContexts,
componentStyleBundler,
codeBundleCache,
);
executionResult.addWarnings(bundlingResult.warnings);

// Return if the bundling has errors
Expand Down
65 changes: 56 additions & 9 deletions packages/angular/build/src/builders/application/setup-bundling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/

import { ComponentStylesheetBundler } from '../../tools/esbuild/angular/component-stylesheets';
import { SourceFileCache } from '../../tools/esbuild/angular/source-file-cache';
import {
createBrowserCodeBundleOptions,
Expand All @@ -17,10 +18,7 @@ import {
import { BundlerContext } from '../../tools/esbuild/bundler-context';
import { createGlobalScriptsBundleOptions } from '../../tools/esbuild/global-scripts';
import { createGlobalStylesBundleOptions } from '../../tools/esbuild/global-styles';
import {
getSupportedNodeTargets,
transformSupportedBrowsersToTargets,
} from '../../tools/esbuild/utils';
import { getSupportedNodeTargets } from '../../tools/esbuild/utils';
import { NormalizedApplicationBuildOptions } from './options';

/**
Expand All @@ -33,8 +31,9 @@ import { NormalizedApplicationBuildOptions } from './options';
*/
export function setupBundlerContexts(
options: NormalizedApplicationBuildOptions,
browsers: string[],
target: string[],
codeBundleCache: SourceFileCache,
stylesheetBundler: ComponentStylesheetBundler,
): BundlerContext[] {
const {
outputMode,
Expand All @@ -45,15 +44,14 @@ export function setupBundlerContexts(
workspaceRoot,
watch = false,
} = options;
const target = transformSupportedBrowsersToTargets(browsers);
const bundlerContexts = [];

// Browser application code
bundlerContexts.push(
new BundlerContext(
workspaceRoot,
watch,
createBrowserCodeBundleOptions(options, target, codeBundleCache),
createBrowserCodeBundleOptions(options, target, codeBundleCache, stylesheetBundler),
),
);

Expand All @@ -62,6 +60,7 @@ export function setupBundlerContexts(
options,
target,
codeBundleCache,
stylesheetBundler,
);
if (browserPolyfillBundleOptions) {
bundlerContexts.push(new BundlerContext(workspaceRoot, watch, browserPolyfillBundleOptions));
Expand Down Expand Up @@ -99,7 +98,7 @@ export function setupBundlerContexts(
new BundlerContext(
workspaceRoot,
watch,
createServerMainCodeBundleOptions(options, nodeTargets, codeBundleCache),
createServerMainCodeBundleOptions(options, nodeTargets, codeBundleCache, stylesheetBundler),
),
);

Expand All @@ -109,7 +108,7 @@ export function setupBundlerContexts(
new BundlerContext(
workspaceRoot,
watch,
createSsrEntryCodeBundleOptions(options, nodeTargets, codeBundleCache),
createSsrEntryCodeBundleOptions(options, nodeTargets, codeBundleCache, stylesheetBundler),
),
);
}
Expand All @@ -128,3 +127,51 @@ export function setupBundlerContexts(

return bundlerContexts;
}

export function createComponentStyleBundler(
options: NormalizedApplicationBuildOptions,
target: string[],
): ComponentStylesheetBundler {
const {
workspaceRoot,
optimizationOptions,
sourcemapOptions,
outputNames,
externalDependencies,
preserveSymlinks,
stylePreprocessorOptions,
inlineStyleLanguage,
cacheOptions,
tailwindConfiguration,
postcssConfiguration,
publicPath,
} = options;
const incremental = !!options.watch;

return new ComponentStylesheetBundler(
{
workspaceRoot,
inlineFonts: !!optimizationOptions.fonts.inline,
optimization: !!optimizationOptions.styles.minify,
sourcemap:
// Hidden component stylesheet sourcemaps are inaccessible which is effectively
// the same as being disabled. Disabling has the advantage of avoiding the overhead
// of sourcemap processing.
sourcemapOptions.styles && !sourcemapOptions.hidden ? 'linked' : false,
outputNames,
includePaths: stylePreprocessorOptions?.includePaths,
// string[] | undefined' is not assignable to type '(Version | DeprecationOrId)[] | undefined'.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
sass: stylePreprocessorOptions?.sass as any,
externalDependencies,
target,
preserveSymlinks,
tailwindConfiguration,
postcssConfiguration,
cacheOptions,
publicPath,
},
inlineStyleLanguage,
incremental,
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import {
import { JavaScriptTransformer } from '../javascript-transformer';
import { LoadResultCache, createCachedLoad } from '../load-result-cache';
import { logCumulativeDurations, profileAsync, resetCumulativeDurations } from '../profiling';
import { BundleStylesheetOptions } from '../stylesheets/bundle-options';
import { SharedTSCompilationState, getSharedCompilationState } from './compilation-state';
import { ComponentStylesheetBundler } from './component-stylesheets';
import { FileReferenceTracker } from './file-reference-tracker';
Expand All @@ -57,7 +56,7 @@ export interface CompilerPluginOptions {
// eslint-disable-next-line max-lines-per-function
export function createCompilerPlugin(
pluginOptions: CompilerPluginOptions,
styleOptions: BundleStylesheetOptions & { inlineStyleLanguage: string },
stylesheetBundler: ComponentStylesheetBundler,
): Plugin {
return {
name: 'angular-compiler',
Expand Down Expand Up @@ -128,12 +127,6 @@ export function createCompilerPlugin(
// Determines if transpilation should be handle by TypeScript or esbuild
let useTypeScriptTranspilation = true;

// Track incremental component stylesheet builds
const stylesheetBundler = new ComponentStylesheetBundler(
styleOptions,
styleOptions.inlineStyleLanguage,
pluginOptions.incremental,
);
let sharedTSCompilationState: SharedTSCompilationState | undefined;

// To fully invalidate files, track resource referenced files and their referencing source
Expand Down Expand Up @@ -539,7 +532,6 @@ export function createCompilerPlugin(

build.onDispose(() => {
sharedTSCompilationState?.dispose();
void stylesheetBundler.dispose();
void compilation.close?.();
void cacheStore?.close();
});
Expand Down
45 changes: 19 additions & 26 deletions packages/angular/build/src/tools/esbuild/application-code-bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
SERVER_APP_MANIFEST_FILENAME,
} from '../../utils/server-rendering/manifest';
import { createCompilerPlugin } from './angular/compiler-plugin';
import { ComponentStylesheetBundler } from './angular/component-stylesheets';
import { SourceFileCache } from './angular/source-file-cache';
import { BundlerOptionsFactory } from './bundler-context';
import { createCompilerPluginOptions } from './compiler-plugin-options';
Expand All @@ -34,15 +35,12 @@ import { createWasmPlugin } from './wasm-plugin';
export function createBrowserCodeBundleOptions(
options: NormalizedApplicationBuildOptions,
target: string[],
sourceFileCache?: SourceFileCache,
sourceFileCache: SourceFileCache,
stylesheetBundler: ComponentStylesheetBundler,
): BuildOptions {
const { entryPoints, outputNames, polyfills } = options;

const { pluginOptions, styleOptions } = createCompilerPluginOptions(
options,
target,
sourceFileCache,
);
const pluginOptions = createCompilerPluginOptions(options, sourceFileCache);

const zoneless = isZonelessApp(polyfills);

Expand All @@ -65,8 +63,8 @@ export function createBrowserCodeBundleOptions(
createCompilerPlugin(
// JS/TS options
pluginOptions,
// Component stylesheet options
styleOptions,
// Component stylesheet bundler
stylesheetBundler,
),
],
};
Expand Down Expand Up @@ -100,7 +98,8 @@ export function createBrowserCodeBundleOptions(
export function createBrowserPolyfillBundleOptions(
options: NormalizedApplicationBuildOptions,
target: string[],
sourceFileCache?: SourceFileCache,
sourceFileCache: SourceFileCache,
stylesheetBundler: ComponentStylesheetBundler,
): BuildOptions | BundlerOptionsFactory | undefined {
const namespace = 'angular:polyfills';
const polyfillBundleOptions = getEsBuildCommonPolyfillsOptions(
Expand Down Expand Up @@ -134,17 +133,17 @@ export function createBrowserPolyfillBundleOptions(
// Only add the Angular TypeScript compiler if TypeScript files are provided in the polyfills
if (hasTypeScriptEntries) {
buildOptions.plugins ??= [];
const { pluginOptions, styleOptions } = createCompilerPluginOptions(
const pluginOptions = createCompilerPluginOptions(
options,
target,

sourceFileCache,
);
buildOptions.plugins.push(
createCompilerPlugin(
// JS/TS options
{ ...pluginOptions, noopTypeScriptCompilation: true },
// Component stylesheet options are unused for polyfills but required by the plugin
styleOptions,
stylesheetBundler,
),
);
}
Expand Down Expand Up @@ -228,6 +227,7 @@ export function createServerMainCodeBundleOptions(
options: NormalizedApplicationBuildOptions,
target: string[],
sourceFileCache: SourceFileCache,
stylesheetBundler: ComponentStylesheetBundler,
): BuildOptions {
const {
serverEntryPoint: mainServerEntryPoint,
Expand All @@ -243,11 +243,7 @@ export function createServerMainCodeBundleOptions(
'createServerCodeBundleOptions should not be called without a defined serverEntryPoint.',
);

const { pluginOptions, styleOptions } = createCompilerPluginOptions(
options,
target,
sourceFileCache,
);
const pluginOptions = createCompilerPluginOptions(options, sourceFileCache);

const mainServerNamespace = 'angular:main-server';
const mainServerInjectPolyfillsNamespace = 'angular:main-server-inject-polyfills';
Expand Down Expand Up @@ -278,8 +274,8 @@ export function createServerMainCodeBundleOptions(
createCompilerPlugin(
// JS/TS options
{ ...pluginOptions, noopTypeScriptCompilation: true },
// Component stylesheet options
styleOptions,
// Component stylesheet bundler
stylesheetBundler,
),
],
};
Expand Down Expand Up @@ -374,6 +370,7 @@ export function createSsrEntryCodeBundleOptions(
options: NormalizedApplicationBuildOptions,
target: string[],
sourceFileCache: SourceFileCache,
stylesheetBundler: ComponentStylesheetBundler,
): BuildOptions {
const { workspaceRoot, ssrOptions, externalPackages } = options;
const serverEntryPoint = ssrOptions?.entry;
Expand All @@ -382,11 +379,7 @@ export function createSsrEntryCodeBundleOptions(
'createSsrEntryCodeBundleOptions should not be called without a defined serverEntryPoint.',
);

const { pluginOptions, styleOptions } = createCompilerPluginOptions(
options,
target,
sourceFileCache,
);
const pluginOptions = createCompilerPluginOptions(options, sourceFileCache);

const ssrEntryNamespace = 'angular:ssr-entry';
const ssrInjectManifestNamespace = 'angular:ssr-entry-inject-manifest';
Expand All @@ -411,8 +404,8 @@ export function createSsrEntryCodeBundleOptions(
createCompilerPlugin(
// JS/TS options
{ ...pluginOptions, noopTypeScriptCompilation: true },
// Component stylesheet options
styleOptions,
// Component stylesheet bundler
stylesheetBundler,
),
],
inject,
Expand Down
Loading