Skip to content

@source not: Cannot ignore symlinked directory because symlink is optimized away #17985

@doits

Description

@doits

What version of Tailwind CSS are you using?

tailwindcss v4.1.6

What build tool (or framework if it abstracts the build tool) are you using?

Cli

What version of Node.js are you using?

v22.15.0

What browser are you using?

N/A

What operating system are you using?

Ubuntu

Reproduction URL

N/A

Describe your issue

When a directory is symlinked, e.g. a directory_a is symlinked from symlink:

directory_a/a
directory_a/b
symlink           # symlink to ./directory_a
tailwind.css

... and I have a @source not "./symlink"; ...

@source not "./symlink";

... it does not ignore it:

2025-05-12T12:35:15.744825Z  INFO tailwindcss_oxide::scanner: Provided sources:
2025-05-12T12:35:15.744976Z  INFO tailwindcss_oxide::scanner: Source: PublicSourceEntry { base: "/Users/abc/tmp/tailwind", pattern: "**/*", negated: false }
2025-05-12T12:35:15.745016Z  INFO tailwindcss_oxide::scanner: Source: PublicSourceEntry { base: "/Users/abc/tmp/tailwind", pattern: "./symlink", negated: true }
2025-05-12T12:35:15.745132Z  INFO tailwindcss_oxide::scanner: Optimized sources:
2025-05-12T12:35:15.745139Z  INFO tailwindcss_oxide::scanner: Source: Auto { base: "/Users/abc/tmp/tailwind" }
2025-05-12T12:35:15.745159Z  INFO tailwindcss_oxide::scanner: Source: Ignored { base: "/Users/abc/tmp/tailwind/directory_a", pattern: "**/*" }
2025-05-12T12:35:15.746487Z  INFO get_normalized_sources: tailwindcss_oxide::scanner: enter
2025-05-12T12:35:15.746498Z  INFO get_normalized_sources: tailwindcss_oxide::scanner: exit
2025-05-12T12:35:15.753492Z  INFO scan_sources: tailwindcss_oxide::scanner: enter
2025-05-12T12:35:15.753775Z  INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/Users/abc/tmp/tailwind/symlink"
2025-05-12T12:35:15.753833Z  INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/Users/abc/tmp/tailwind/symlink/a"
2025-05-12T12:35:15.753884Z  INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/Users/abc/tmp/tailwind/symlink/b"
2025-05-12T12:35:15.753939Z  INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/Users/abc/tmp/tailwind/tailwind.css"
2025-05-12T12:35:15.753989Z  INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/Users/abc/tmp/tailwind/output.css"
2025-05-12T12:35:15.754033Z  INFO scan_sources: tailwindcss_oxide::scanner: exit

The pattern before optimisation is correct:

2025-05-12T12:35:15.745016Z  INFO tailwindcss_oxide::scanner: Source: PublicSourceEntry { base: "/Users/abc/tmp/tailwind", pattern: "./symlink", negated: true }

But after optimisation it ignores the directory the symlink points to (directory_a in this case):

2025-05-12T12:35:15.745159Z  INFO tailwindcss_oxide::scanner: Source: Ignored { base: "/Users/abc/tmp/tailwind/directory_a", pattern: "**/*" }

... and goes on scanning the symlink even though it should be ignored:

2025-05-12T12:35:15.753833Z  INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/Users/abc/tmp/tailwind/symlink/a"
2025-05-12T12:35:15.753884Z  INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/Users/abc/tmp/tailwind/symlink/b"

It should not scan a_symlink_to/* because it was explicitly ignored by a @source not statement.

Because otherwise what is at directory_a cannot be ignored at all:

@source not "./symlink";
@source not "./directory_a";

leads to:

2025-05-12T12:38:12.030696Z  INFO tailwindcss_oxide::scanner: Provided sources:
2025-05-12T12:38:12.030840Z  INFO tailwindcss_oxide::scanner: Source: PublicSourceEntry { base: "/Users/abc/tmp/tailwind", pattern: "**/*", negated: false }
2025-05-12T12:38:12.030876Z  INFO tailwindcss_oxide::scanner: Source: PublicSourceEntry { base: "/Users/abc/tmp/tailwind", pattern: "./symlink", negated: true }
2025-05-12T12:38:12.030882Z  INFO tailwindcss_oxide::scanner: Source: PublicSourceEntry { base: "/Users/abc/tmp/tailwind", pattern: "./directory_a", negated: true }
2025-05-12T12:38:12.031015Z  INFO tailwindcss_oxide::scanner: Optimized sources:
2025-05-12T12:38:12.031023Z  INFO tailwindcss_oxide::scanner: Source: Auto { base: "/Users/abc/tmp/tailwind" }
2025-05-12T12:38:12.031042Z  INFO tailwindcss_oxide::scanner: Source: Ignored { base: "/Users/abc/tmp/tailwind/directory_a", pattern: "**/*" }
2025-05-12T12:38:12.031046Z  INFO tailwindcss_oxide::scanner: Source: Ignored { base: "/Users/abc/tmp/tailwind/directory_a", pattern: "**/*" }
2025-05-12T12:38:12.032357Z  INFO get_normalized_sources: tailwindcss_oxide::scanner: enter
2025-05-12T12:38:12.032368Z  INFO get_normalized_sources: tailwindcss_oxide::scanner: exit
2025-05-12T12:38:12.039651Z  INFO scan_sources: tailwindcss_oxide::scanner: enter
2025-05-12T12:38:12.039973Z  INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/Users/abc/tmp/tailwind/symlink"
2025-05-12T12:38:12.040023Z  INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/Users/abc/tmp/tailwind/symlink/a"
2025-05-12T12:38:12.040084Z  INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/Users/abc/tmp/tailwind/symlink/b"
2025-05-12T12:38:12.040115Z  INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/Users/abc/tmp/tailwind/tailwind.css"
2025-05-12T12:38:12.040152Z  INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/Users/abc/tmp/tailwind/output.css"

It has the same directory twice after optimisation:

2025-05-12T12:38:12.031042Z  INFO tailwindcss_oxide::scanner: Source: Ignored { base: "/Users/abc/tmp/tailwind/directory_a", pattern: "**/*" }
2025-05-12T12:38:12.031046Z  INFO tailwindcss_oxide::scanner: Source: Ignored { base: "/Users/abc/tmp/tailwind/directory_a", pattern: "**/*" }

... and still scans ./symlink/*:

2025-05-12T12:38:12.040023Z  INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/Users/abc/tmp/tailwind/symlink/a"
2025-05-12T12:38:12.040084Z  INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/Users/abc/tmp/tailwind/symlink/b"

refs #15750

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions