11const fs = require ( 'fs' )
2+ const url = require ( 'url' )
23const os = require ( 'os' )
34const path = require ( 'path' )
45const crypto = require ( 'crypto' )
56const chokidar = require ( 'chokidar' )
67const postcss = require ( 'postcss' )
8+ const hash = require ( 'object-hash' )
79const dlv = require ( 'dlv' )
810const selectorParser = require ( 'postcss-selector-parser' )
911const LRU = require ( 'quick-lru' )
@@ -21,6 +23,8 @@ const { isPlainObject } = require('./utils')
2123const { isBuffer } = require ( 'util' )
2224
2325let contextMap = sharedState . contextMap
26+ let configContextMap = sharedState . configContextMap
27+ let contextSourcesMap = sharedState . contextSourcesMap
2428let env = sharedState . env
2529
2630// Earmarks a directory for our touch files.
@@ -148,27 +152,29 @@ function getTailwindConfig(configOrPath) {
148152 let userConfigPath = resolveConfigPath ( configOrPath )
149153
150154 if ( userConfigPath !== null ) {
151- let [ prevConfig , prevModified = - Infinity ] = configPathCache . get ( userConfigPath ) ?? [ ]
155+ let [ prevConfig , prevModified = - Infinity , prevConfigHash ] =
156+ configPathCache . get ( userConfigPath ) ?? [ ]
152157 let modified = fs . statSync ( userConfigPath ) . mtimeMs
153158
154159 // It hasn't changed (based on timestamp)
155160 if ( modified <= prevModified ) {
156- return [ prevConfig , userConfigPath ]
161+ return [ prevConfig , userConfigPath , prevConfigHash ]
157162 }
158163
159164 // It has changed (based on timestamp), or first run
160165 delete require . cache [ userConfigPath ]
161166 let newConfig = resolveConfig ( require ( userConfigPath ) )
162- configPathCache . set ( userConfigPath , [ newConfig , modified ] )
163- return [ newConfig , userConfigPath ]
167+ let newHash = hash ( newConfig )
168+ configPathCache . set ( userConfigPath , [ newConfig , modified , newHash ] )
169+ return [ newConfig , userConfigPath , newHash ]
164170 }
165171
166172 // It's a plain object, not a path
167173 let newConfig = resolveConfig (
168174 configOrPath . config === undefined ? configOrPath : configOrPath . config
169175 )
170176
171- return [ newConfig , null ]
177+ return [ newConfig , null , hash ( newConfig ) ]
172178}
173179
174180let fileModifiedMap = new Map ( )
@@ -177,13 +183,14 @@ function trackModified(files) {
177183 let changed = false
178184
179185 for ( let file of files ) {
180- let newModified = fs . statSync ( file ) . mtimeMs
186+ let pathname = url . parse ( file ) . pathname
187+ let newModified = fs . statSync ( pathname ) . mtimeMs
181188
182- if ( ! fileModifiedMap . has ( file ) || newModified > fileModifiedMap . get ( file ) ) {
189+ if ( ! fileModifiedMap . has ( pathname ) || newModified > fileModifiedMap . get ( pathname ) ) {
183190 changed = true
184191 }
185192
186- fileModifiedMap . set ( file , newModified )
193+ fileModifiedMap . set ( pathname , newModified )
187194 }
188195
189196 return changed
@@ -538,7 +545,7 @@ function cleanupContext(context) {
538545function setupContext ( configOrPath ) {
539546 return ( result , root ) => {
540547 let sourcePath = result . opts . from
541- let [ tailwindConfig , userConfigPath ] = getTailwindConfig ( configOrPath )
548+ let [ tailwindConfig , userConfigPath , tailwindConfigHash ] = getTailwindConfig ( configOrPath )
542549
543550 let contextDependencies = new Set ( )
544551 contextDependencies . add ( sourcePath )
@@ -557,12 +564,38 @@ function setupContext(configOrPath) {
557564 trackModified ( [ ...contextDependencies ] ) || userConfigPath === null
558565
559566 process . env . DEBUG && console . log ( 'Source path:' , sourcePath )
567+
568+ // If this file already has a context in the cache and we don't need to
569+ // reset the context, return the cached context.
560570 if ( contextMap . has ( sourcePath ) && ! contextDependenciesChanged ) {
561571 return contextMap . get ( sourcePath )
562572 }
563573
574+ // If the config file used already exists in the cache, return that.
575+ console . log ( 'dependencies changed: ' , contextDependenciesChanged )
576+ console . log ( tailwindConfigHash )
577+ console . log ( configContextMap . keys ( ) )
578+ console . log ( configContextMap . has ( tailwindConfigHash ) )
579+
580+ // DAMN YOU CONTEXTDEPENDENCIESCHANGED
581+ // Ideas:
582+ // - Can we incorporate the presence of @tailwind rules somehow? If it has no Tailwind rules, be
583+ // more lenient about the dependencies changing?
584+ if ( ! contextDependenciesChanged && configContextMap . has ( tailwindConfigHash ) ) {
585+ let context = configContextMap . get ( tailwindConfigHash )
586+ contextSourcesMap . get ( context ) . add ( sourcePath )
587+ contextMap . set ( sourcePath , context )
588+ return context
589+ }
590+
591+ // TODO: Update this to no longer associate this path with its old context
592+ // and clean up that context if no one else is using it.
564593 if ( contextMap . has ( sourcePath ) ) {
565- cleanupContext ( contextMap . get ( sourcePath ) )
594+ let oldContext = contextMap . get ( sourcePath )
595+ contextSourcesMap . get ( oldContext ) . remove ( sourcePath )
596+ if ( contextSourcesMap . get ( oldContext ) . size === 0 ) {
597+ cleanupContext ( oldContext )
598+ }
566599 }
567600
568601 process . env . DEBUG && console . log ( 'Setting up new context...' )
@@ -579,7 +612,6 @@ function setupContext(configOrPath) {
579612 newPostCssNodeCache : new Map ( ) ,
580613 candidateRuleMap : new Map ( ) ,
581614 configPath : userConfigPath ,
582- sourcePath : sourcePath ,
583615 tailwindConfig : tailwindConfig ,
584616 configDependencies : new Set ( ) ,
585617 candidateFiles : Array . isArray ( tailwindConfig . purge )
@@ -588,8 +620,22 @@ function setupContext(configOrPath) {
588620 variantMap : new Map ( ) ,
589621 stylesheetCache : null ,
590622 }
623+
624+ // ---
625+
626+ // Update all context tracking state
627+
628+ configContextMap . set ( tailwindConfigHash , context )
591629 contextMap . set ( sourcePath , context )
592630
631+ if ( ! contextSourcesMap . has ( context ) ) {
632+ contextSourcesMap . set ( context , new Set ( ) )
633+ }
634+
635+ contextSourcesMap . get ( context ) . add ( sourcePath )
636+
637+ // ---
638+
593639 if ( userConfigPath !== null ) {
594640 for ( let dependency of getModuleDependencies ( userConfigPath ) ) {
595641 if ( dependency . file === userConfigPath ) {
@@ -600,6 +646,12 @@ function setupContext(configOrPath) {
600646 }
601647 }
602648
649+ let prev = null
650+ for ( let [ key , value ] of contextSourcesMap ) {
651+ console . log ( key === prev )
652+ prev = key
653+ }
654+
603655 rebootWatcher ( context )
604656
605657 let corePluginList = Object . entries ( corePlugins )
0 commit comments