@@ -29,6 +29,10 @@ export interface StylesheetPluginOptions {
2929 */
3030 sourcemap : boolean ;
3131
32+ /**
33+ * An optional array of paths that will be searched for stylesheets if the default
34+ * resolution process for the stylesheet language does not succeed.
35+ */
3236 includePaths ?: string [ ] ;
3337
3438 /**
@@ -37,9 +41,21 @@ export interface StylesheetPluginOptions {
3741 */
3842 inlineComponentData ?: Record < string , string > ;
3943
44+ /**
45+ * Optional information used to load and configure Tailwind CSS. If present, the postcss
46+ * will be added to the stylesheet processing with the Tailwind plugin setup as provided
47+ * by the configuration file.
48+ */
4049 tailwindConfiguration ?: { file : string ; package : string } ;
4150}
4251
52+ /**
53+ * An array of keywords that indicate Tailwind CSS processing is required for a stylesheet.
54+ *
55+ * Based on https://tailwindcss.com/docs/functions-and-directives
56+ */
57+ const TAILWIND_KEYWORDS = [ '@tailwind' , '@layer' , '@apply' , '@config' , 'theme(' , 'screen(' ] ;
58+
4359export interface StylesheetLanguage {
4460 name : string ;
4561 componentFilter : RegExp ;
@@ -54,6 +70,8 @@ export interface StylesheetLanguage {
5470}
5571
5672export class StylesheetPluginFactory {
73+ private postcssProcessor ?: import ( 'postcss' ) . Processor ;
74+
5775 constructor (
5876 private readonly options : StylesheetPluginOptions ,
5977 private readonly cache ?: LoadResultCache ,
@@ -69,21 +87,28 @@ export class StylesheetPluginFactory {
6987 }
7088
7189 const { cache, options } = this ;
90+ const setupPostcss = async ( ) => {
91+ // Return already created processor if present
92+ if ( this . postcssProcessor ) {
93+ return this . postcssProcessor ;
94+ }
95+
96+ if ( options . tailwindConfiguration ) {
97+ postcss ??= ( await import ( 'postcss' ) ) . default ;
98+ const tailwind = await import ( options . tailwindConfiguration . package ) ;
99+ this . postcssProcessor = postcss ( ) . use (
100+ tailwind . default ( { config : options . tailwindConfiguration . file } ) ,
101+ ) ;
102+ }
103+
104+ return this . postcssProcessor ;
105+ } ;
72106
73107 return {
74108 name : 'angular-' + language . name ,
75109 async setup ( build ) {
76- // Setup postcss if needed by tailwind
77- // TODO: Move this into the plugin factory to avoid repeat setup per created plugin
78- let postcssProcessor : import ( 'postcss' ) . Processor | undefined ;
79- if ( options . tailwindConfiguration ) {
80- postcss ??= ( await import ( 'postcss' ) ) . default ;
81- postcssProcessor = postcss ( ) ;
82- if ( options . tailwindConfiguration ) {
83- const tailwind = await import ( options . tailwindConfiguration . package ) ;
84- postcssProcessor . use ( tailwind . default ( { config : options . tailwindConfiguration . file } ) ) ;
85- }
86- }
110+ // Setup postcss if needed
111+ const postcssProcessor = await setupPostcss ( ) ;
87112
88113 // Add a load callback to support inline Component styles
89114 build . onLoad (
@@ -96,6 +121,12 @@ export class StylesheetPluginFactory {
96121 ) ;
97122
98123 const [ format , , filename ] = args . path . split ( ';' , 3 ) ;
124+ // Only use postcss if Tailwind processing is required.
125+ // NOTE: If postcss is used for more than just Tailwind in the future this check MUST
126+ // be updated to account for the additional use.
127+ // TODO: use better search algorithm for keywords
128+ const needsPostcss =
129+ ! ! postcssProcessor && TAILWIND_KEYWORDS . some ( ( keyword ) => data . includes ( keyword ) ) ;
99130
100131 return processStylesheet (
101132 language ,
@@ -104,7 +135,7 @@ export class StylesheetPluginFactory {
104135 format ,
105136 options ,
106137 build ,
107- postcssProcessor ,
138+ needsPostcss ? postcssProcessor : undefined ,
108139 ) ;
109140 } ) ,
110141 ) ;
@@ -114,6 +145,8 @@ export class StylesheetPluginFactory {
114145 { filter : language . fileFilter } ,
115146 createCachedLoad ( cache , async ( args ) => {
116147 const data = await readFile ( args . path , 'utf-8' ) ;
148+ const needsPostcss =
149+ ! ! postcssProcessor && TAILWIND_KEYWORDS . some ( ( keyword ) => data . includes ( keyword ) ) ;
117150
118151 return processStylesheet (
119152 language ,
@@ -122,7 +155,7 @@ export class StylesheetPluginFactory {
122155 extname ( args . path ) . toLowerCase ( ) . slice ( 1 ) ,
123156 options ,
124157 build ,
125- postcssProcessor ,
158+ needsPostcss ? postcssProcessor : undefined ,
126159 ) ;
127160 } ) ,
128161 ) ;
0 commit comments