@@ -242,20 +242,31 @@ export class ProjectLocator {
242242 concurrency : Math . max ( os . cpus ( ) . length , 1 ) ,
243243 } )
244244
245- files = await Promise . all (
246- files . map ( async ( file ) => {
247- // Resolve symlinks for all found files
248- let actualPath = await fs . realpath ( file )
249-
250- // Ignore network paths on Windows. Resolving relative paths on a
251- // netshare throws in `enhanced-resolve` :/
252- if ( actualPath . startsWith ( '\\' ) && process . platform === 'win32' ) {
253- return normalizePath ( file )
254- }
245+ let realpaths = await Promise . all ( files . map ( ( file ) => fs . realpath ( file ) ) )
255246
256- return normalizePath ( actualPath )
257- } ) ,
258- )
247+ // Remove files that are symlinked yet have an existing file in the list
248+ files = files . filter ( ( normalPath , idx ) => {
249+ let realPath = realpaths [ idx ]
250+
251+ if ( normalPath === realPath ) {
252+ return true
253+ }
254+
255+ // If the file is a symlink, aliased path, network share, etc…; AND
256+ // the realpath is not already in the list of files, then we can add
257+ // the file to the list of files
258+ //
259+ // For example, node_modules in a monorepo setup would be symlinked
260+ // and list both unless you opened one of the directories directly
261+ else if ( ! files . includes ( realPath ) ) {
262+ return true
263+ }
264+
265+ return false
266+ } )
267+
268+ // Make sure Windows-style paths are normalized
269+ files = files . map ( ( file ) => normalizePath ( file ) )
259270
260271 // Deduplicate the list of files and sort them for deterministic results
261272 // across environments
@@ -327,6 +338,9 @@ export class ProjectLocator {
327338 // Resolve imports in all the CSS files
328339 await Promise . all ( imports . map ( ( file ) => file . resolveImports ( ) ) )
329340
341+ // Resolve real paths for all the files in the CSS import graph
342+ await Promise . all ( imports . map ( ( file ) => file . resolveRealpaths ( ) ) )
343+
330344 // Create a graph of all the CSS files that might (indirectly) use Tailwind
331345 let graph = new Graph < FileEntry > ( )
332346
@@ -335,24 +349,21 @@ export class ProjectLocator {
335349 let utilitiesPath : string | null = null
336350
337351 for ( let file of imports ) {
338- graph . add ( file . path , file )
339-
340- for ( let msg of file . deps ) {
341- let importedPath : string = normalizePath ( msg . file )
342-
343- // Record that `file.path` imports `msg.file`
344- graph . add ( importedPath , new FileEntry ( 'css' , importedPath ) )
352+ graph . add ( file . realpath , file )
345353
346- graph . connect ( file . path , importedPath )
354+ // Record that `file.path` imports `msg.file`
355+ for ( let entry of file . deps ) {
356+ graph . add ( entry . realpath , entry )
357+ graph . connect ( file . realpath , entry . realpath )
347358 }
348359
349360 // Collect the index, theme, and utilities files for manual connection
350- if ( file . path . includes ( 'node_modules/tailwindcss/index.css' ) ) {
351- indexPath = file . path
352- } else if ( file . path . includes ( 'node_modules/tailwindcss/theme.css' ) ) {
353- themePath = file . path
354- } else if ( file . path . includes ( 'node_modules/tailwindcss/utilities.css' ) ) {
355- utilitiesPath = file . path
361+ if ( file . realpath . includes ( 'node_modules/tailwindcss/index.css' ) ) {
362+ indexPath = file . realpath
363+ } else if ( file . realpath . includes ( 'node_modules/tailwindcss/theme.css' ) ) {
364+ themePath = file . realpath
365+ } else if ( file . realpath . includes ( 'node_modules/tailwindcss/utilities.css' ) ) {
366+ utilitiesPath = file . realpath
356367 }
357368 }
358369
@@ -383,7 +394,7 @@ export class ProjectLocator {
383394
384395 // And add the config to all their descendants as we need to track updates
385396 // that might affect the config / project
386- for ( let child of graph . descendants ( root . path ) ) {
397+ for ( let child of graph . descendants ( root . realpath ) ) {
387398 child . configs . push ( config )
388399 }
389400 }
@@ -540,7 +551,8 @@ type ConfigEntry = {
540551
541552class FileEntry {
542553 content : string | null
543- deps : Message [ ] = [ ]
554+ deps : FileEntry [ ] = [ ]
555+ realpath : string | null
544556
545557 constructor (
546558 public type : 'js' | 'css' ,
@@ -559,7 +571,10 @@ class FileEntry {
559571 async resolveImports ( ) {
560572 try {
561573 let result = await resolveCssImports ( ) . process ( this . content , { from : this . path } )
562- this . deps = result . messages . filter ( ( msg ) => msg . type === 'dependency' )
574+ let deps = result . messages . filter ( ( msg ) => msg . type === 'dependency' )
575+
576+ // Record entries for each of the dependencies
577+ this . deps = deps . map ( ( msg ) => new FileEntry ( 'css' , normalizePath ( msg . file ) ) )
563578
564579 // Replace the file content with the processed CSS
565580 this . content = result . css
@@ -568,6 +583,12 @@ class FileEntry {
568583 }
569584 }
570585
586+ async resolveRealpaths ( ) {
587+ this . realpath = normalizePath ( await fs . realpath ( this . path ) )
588+
589+ await Promise . all ( this . deps . map ( ( entry ) => entry . resolveRealpaths ( ) ) )
590+ }
591+
571592 /**
572593 * Look for `@config` directives in a CSS file and return the path to the config
573594 * file that it points to. This path is (possibly) relative to the CSS file so
0 commit comments