1
1
const fs = require ( 'fs' )
2
+ const path = require ( 'path' )
2
3
const fastGlob = require ( 'fast-glob' )
3
4
const sharedState = require ( './sharedState' )
4
5
const { generateRules } = require ( './generateRules' )
@@ -7,10 +8,39 @@ const { bigSign } = require('./utils')
7
8
let env = sharedState . env
8
9
let contentMatchCache = sharedState . contentMatchCache
9
10
11
+ const BROAD_MATCH_GLOBAL_REGEXP = / [ ^ < > " ' ` \s ] * [ ^ < > " ' ` \s : ] / g
12
+ const INNER_MATCH_GLOBAL_REGEXP = / [ ^ < > " ' ` \s . ( ) { } [ \] # = % ] * [ ^ < > " ' ` \s . ( ) { } [ \] # = % : ] / g
13
+
14
+ function defaultJitExtractor ( content ) {
15
+ let broadMatches = content . match ( BROAD_MATCH_GLOBAL_REGEXP ) || [ ]
16
+ let innerMatches = content . match ( INNER_MATCH_GLOBAL_REGEXP ) || [ ]
17
+
18
+ return [ ...broadMatches , ...innerMatches ]
19
+ }
20
+
21
+ function getExtractor ( fileName , tailwindConfig ) {
22
+ const purgeOptions = tailwindConfig && tailwindConfig . purge && tailwindConfig . purge . options
23
+
24
+ if ( ! purgeOptions ) {
25
+ return defaultJitExtractor
26
+ }
27
+
28
+ const fileExtension = path . extname ( fileName ) . slice ( 1 )
29
+ const fileSpecificExtractor = ( purgeOptions . extractors || [ ] ) . find ( ( extractor ) =>
30
+ extractor . extensions . includes ( fileExtension )
31
+ )
32
+
33
+ if ( fileSpecificExtractor ) {
34
+ return fileSpecificExtractor . extractor
35
+ }
36
+
37
+ return purgeOptions . defaultExtractor || defaultJitExtractor
38
+ }
39
+
10
40
// Scans template contents for possible classes. This is a hot path on initial build but
11
41
// not too important for subsequent builds. The faster the better though — if we can speed
12
42
// up these regexes by 50% that could cut initial build time by like 20%.
13
- function getClassCandidates ( content , contentMatchCache , candidates , seen ) {
43
+ function getClassCandidates ( content , extractor , contentMatchCache , candidates , seen ) {
14
44
for ( let line of content . split ( '\n' ) ) {
15
45
line = line . trim ( )
16
46
@@ -24,20 +54,14 @@ function getClassCandidates(content, contentMatchCache, candidates, seen) {
24
54
candidates . add ( match )
25
55
}
26
56
} else {
27
- let allMatches = new Set ( )
28
- let broadMatches = line . match ( / [ ^ < > " ' ` \s ] * [ ^ < > " ' ` \s : ] / g) || [ ]
29
- let innerMatches = line . match ( / [ ^ < > " ' ` \s . ( ) { } [ \] # = % ] * [ ^ < > " ' ` \s . ( ) { } [ \] # = % : ] / g) || [ ]
57
+ let extractorMatches = extractor ( line )
58
+ let lineMatchesSet = new Set ( extractorMatches )
30
59
31
- for ( let match of broadMatches ) {
32
- allMatches . add ( match )
33
- candidates . add ( match )
34
- }
35
- for ( let match of innerMatches ) {
36
- allMatches . add ( match )
60
+ for ( let match of lineMatchesSet ) {
37
61
candidates . add ( match )
38
62
}
39
63
40
- contentMatchCache . set ( line , allMatches )
64
+ contentMatchCache . set ( line , lineMatchesSet )
41
65
}
42
66
}
43
67
}
@@ -143,7 +167,8 @@ function expandTailwindAtRules(context, registerDependency) {
143
167
env . DEBUG && console . time ( 'Reading changed files' )
144
168
for ( let file of context . changedFiles ) {
145
169
let content = fs . readFileSync ( file , 'utf8' )
146
- getClassCandidates ( content , contentMatchCache , candidates , seen )
170
+ let extractor = getExtractor ( file , context . tailwindConfig )
171
+ getClassCandidates ( content , extractor , contentMatchCache , candidates , seen )
147
172
}
148
173
env . DEBUG && console . timeEnd ( 'Reading changed files' )
149
174
0 commit comments