Skip to content

Commit

Permalink
perf(@angular-devkit/build-angular): filter postcss usage based on co…
Browse files Browse the repository at this point in the history
…ntent in esbuild builder

When using the esbuild-based browser application builder, stylesheets that do not need any
postcss processing will now skip the postcss step of the stylesheet build pipeline. Currently,
only Tailwind CSS leverages postcss and Tailwind CSS is an opt-in feature. As a result, postcss
will only be used if Tailwind CSS is configured for the project and a stylesheet contains one or
more of the directives/functions specific to Tailwind as provided by https://tailwindcss.com/docs/functions-and-directives.
This change should be most beneficial for component stylesheets which will rarely contain Tailwind
specific rules that need additional processing.
  • Loading branch information
clydin committed Jul 10, 2023
1 parent b0d6b87 commit 974748c
Showing 1 changed file with 46 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ export interface StylesheetPluginOptions {
*/
sourcemap: boolean;

/**
* An optional array of paths that will be searched for stylesheets if the default
* resolution process for the stylesheet language does not succeed.
*/
includePaths?: string[];

/**
Expand All @@ -37,9 +41,21 @@ export interface StylesheetPluginOptions {
*/
inlineComponentData?: Record<string, string>;

/**
* Optional information used to load and configure Tailwind CSS. If present, the postcss
* will be added to the stylesheet processing with the Tailwind plugin setup as provided
* by the configuration file.
*/
tailwindConfiguration?: { file: string; package: string };
}

/**
* An array of keywords that indicate Tailwind CSS processing is required for a stylesheet.
*
* Based on https://tailwindcss.com/docs/functions-and-directives
*/
const TAILWIND_KEYWORDS = ['@tailwind', '@layer', '@apply', '@config', 'theme(', 'screen('];

export interface StylesheetLanguage {
name: string;
componentFilter: RegExp;
Expand All @@ -54,6 +70,8 @@ export interface StylesheetLanguage {
}

export class StylesheetPluginFactory {
private postcssProcessor?: import('postcss').Processor;

constructor(
private readonly options: StylesheetPluginOptions,
private readonly cache?: LoadResultCache,
Expand All @@ -69,21 +87,28 @@ export class StylesheetPluginFactory {
}

const { cache, options } = this;
const setupPostcss = async () => {
// Return already created processor if present
if (this.postcssProcessor) {
return this.postcssProcessor;
}

if (options.tailwindConfiguration) {
postcss ??= (await import('postcss')).default;
const tailwind = await import(options.tailwindConfiguration.package);
this.postcssProcessor = postcss().use(
tailwind.default({ config: options.tailwindConfiguration.file }),
);
}

return this.postcssProcessor;
};

return {
name: 'angular-' + language.name,
async setup(build) {
// Setup postcss if needed by tailwind
// TODO: Move this into the plugin factory to avoid repeat setup per created plugin
let postcssProcessor: import('postcss').Processor | undefined;
if (options.tailwindConfiguration) {
postcss ??= (await import('postcss')).default;
postcssProcessor = postcss();
if (options.tailwindConfiguration) {
const tailwind = await import(options.tailwindConfiguration.package);
postcssProcessor.use(tailwind.default({ config: options.tailwindConfiguration.file }));
}
}
// Setup postcss if needed
const postcssProcessor = await setupPostcss();

// Add a load callback to support inline Component styles
build.onLoad(
Expand All @@ -96,6 +121,12 @@ export class StylesheetPluginFactory {
);

const [format, , filename] = args.path.split(';', 3);
// Only use postcss if Tailwind processing is required.
// NOTE: If postcss is used for more than just Tailwind in the future this check MUST
// be updated to account for the additional use.
// TODO: use better search algorithm for keywords
const needsPostcss =
!!postcssProcessor && TAILWIND_KEYWORDS.some((keyword) => data.includes(keyword));

return processStylesheet(
language,
Expand All @@ -104,7 +135,7 @@ export class StylesheetPluginFactory {
format,
options,
build,
postcssProcessor,
needsPostcss ? postcssProcessor : undefined,
);
}),
);
Expand All @@ -114,6 +145,8 @@ export class StylesheetPluginFactory {
{ filter: language.fileFilter },
createCachedLoad(cache, async (args) => {
const data = await readFile(args.path, 'utf-8');
const needsPostcss =
!!postcssProcessor && TAILWIND_KEYWORDS.some((keyword) => data.includes(keyword));

return processStylesheet(
language,
Expand All @@ -122,7 +155,7 @@ export class StylesheetPluginFactory {
extname(args.path).toLowerCase().slice(1),
options,
build,
postcssProcessor,
needsPostcss ? postcssProcessor : undefined,
);
}),
);
Expand Down

0 comments on commit 974748c

Please sign in to comment.