@@ -29,6 +29,10 @@ export interface StylesheetPluginOptions {
29
29
*/
30
30
sourcemap : boolean ;
31
31
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
+ */
32
36
includePaths ?: string [ ] ;
33
37
34
38
/**
@@ -37,9 +41,21 @@ export interface StylesheetPluginOptions {
37
41
*/
38
42
inlineComponentData ?: Record < string , string > ;
39
43
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
+ */
40
49
tailwindConfiguration ?: { file : string ; package : string } ;
41
50
}
42
51
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
+
43
59
export interface StylesheetLanguage {
44
60
name : string ;
45
61
componentFilter : RegExp ;
@@ -54,6 +70,8 @@ export interface StylesheetLanguage {
54
70
}
55
71
56
72
export class StylesheetPluginFactory {
73
+ private postcssProcessor ?: import ( 'postcss' ) . Processor ;
74
+
57
75
constructor (
58
76
private readonly options : StylesheetPluginOptions ,
59
77
private readonly cache ?: LoadResultCache ,
@@ -69,21 +87,28 @@ export class StylesheetPluginFactory {
69
87
}
70
88
71
89
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
+ } ;
72
106
73
107
return {
74
108
name : 'angular-' + language . name ,
75
109
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 ( ) ;
87
112
88
113
// Add a load callback to support inline Component styles
89
114
build . onLoad (
@@ -96,6 +121,12 @@ export class StylesheetPluginFactory {
96
121
) ;
97
122
98
123
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 ) ) ;
99
130
100
131
return processStylesheet (
101
132
language ,
@@ -104,7 +135,7 @@ export class StylesheetPluginFactory {
104
135
format ,
105
136
options ,
106
137
build ,
107
- postcssProcessor ,
138
+ needsPostcss ? postcssProcessor : undefined ,
108
139
) ;
109
140
} ) ,
110
141
) ;
@@ -114,6 +145,8 @@ export class StylesheetPluginFactory {
114
145
{ filter : language . fileFilter } ,
115
146
createCachedLoad ( cache , async ( args ) => {
116
147
const data = await readFile ( args . path , 'utf-8' ) ;
148
+ const needsPostcss =
149
+ ! ! postcssProcessor && TAILWIND_KEYWORDS . some ( ( keyword ) => data . includes ( keyword ) ) ;
117
150
118
151
return processStylesheet (
119
152
language ,
@@ -122,7 +155,7 @@ export class StylesheetPluginFactory {
122
155
extname ( args . path ) . toLowerCase ( ) . slice ( 1 ) ,
123
156
options ,
124
157
build ,
125
- postcssProcessor ,
158
+ needsPostcss ? postcssProcessor : undefined ,
126
159
) ;
127
160
} ) ,
128
161
) ;
0 commit comments