nextui-org / tailwind-variants

🦄 Tailwindcss first-class variant API
https://tailwind-variants.org
MIT License
2.17k stars 61 forks source link

intellisense in tv config hangs on project when running process on large tv file #127

Open binaryartifex opened 8 months ago

binaryartifex commented 8 months ago

Describe the bug When using a tailwind-variants tv config with a moderate amount of compound variations, the tailwind-intellisense extension hangs indefinitely for the whole project.

To Reproduce The best way i can think of to simulate the issue is the following

  1. enable the vscode extensions Prettier and Tailwind CSS Intellisense
  2. have the prettier-plugin-tailwindcss prettier plugin installed with following configuration
    {
    "arrowParens": "always",
    "bracketSameLine": false,
    "bracketSpacing": true,
    "endOfLine": "auto",
    "printWidth": 100,
    "singleQuote": false,
    "trailingComma": "all",
    "tabWidth": 2,
    "plugins": ["prettier-plugin-tailwindcss"],
    "tailwindConfig": "tailwind-workspace-preset.js",
    "tailwindFunctions": ["tv"]
    }
  3. edit vscode settings with the following configuration (relative to your package manager). I work within an NX monorepo, the tailwind-workspace-preset.js is the root config all other tailwind configs inherit from, i think its safe to omit this for the purpose of repeating the issue.
    {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
    "source.organizeImports": true,
    "source.fixAll": false
    },
    "editor.inlineSuggest.enabled": true,
    "editor.quickSuggestions": {
    "strings": true
    },
    "eslint.validate": ["json"],
    "tailwindCSS.validate": false,
    "tailwindCSS.codeActions": true,
    "tailwindCSS.experimental.configFile": "tailwind-workspace-preset.js",
    "tailwindCSS.experimental.classRegex": [
    ["tv\\((([^()]*|\\([^()]*\\))*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
    ],
    "tailwindCSS.files.exclude": [
    "**/.git/**",
    "**/node_modules/**",
    "**/.hg/**",
    "**/.nx/**",
    "**/.svn/**",
    "**/.husky/**",
    "**/pnpm-lock.yaml",
    "**/@generated/**"
    ]
    }
  4. I can predictably repeat the issue with the following tv config. This first snippet should still provide fully functional intellisense and formatting. I lean heavily on CSS variables in my theming so i think some of the css classes will need to be replaced with default tailwind classes
import { tv } from "tailwind-variants";

export const baseButtonStyles = tv({
  slots: {
    base: [
      "group relative flex shrink-0 select-none items-center rounded-base outline-none transition-all ease-in-out",
      "data-[focus-visible]:outline-2",
    ],
    spinner: "absolute inset-0 m-auto animate-spin text-current",
  },
  variants: {
    color: {
      brand: {},
      danger: {},
      neutral: {},
      success: {},
    },
    isLoading: {
      true: {},
      false: {},
    },
    variant: {
      primary: {},
      secondary: {},
      tertiary: {},
    },
  },
  compoundVariants: [
    {
      variant: "primary",
      color: "brand",
      className: {
        base: [
          "bg-brand text-white",
          "data-[hovered]:bg-brand-dark",
          "data-[pressed]:bg-brand-darker",
        ],
      },
    },
    {
      variant: "primary",
      color: "danger",
      className: {
        base: [
          "bg-danger text-white",
          "data-[hovered]:bg-danger-dark",
          "data-[pressed]:bg-danger-darker",
        ],
      },
    },
    {
      variant: "primary",
      color: "neutral",
      className: {
        base: [
          "bg-neutral text-white",
          "data-[hovered]:bg-neutral-dark",
          "data-[pressed]:bg-neutral-darker",
        ],
      },
    },
    {
      variant: "primary",
      color: "success",
      className: {
        base: [
          "bg-success text-white",
          "data-[hovered]:bg-success-dark",
          "data-[pressed]:bg-success-darker",
        ],
      },
    },
  ],
});

4a. Now add the following two compoundVariants to the above config. When i try to get intellisense working on any classNames momentarily, the loading tooltip appears and hangs indefinately. furthermore the entire intellisense process seems to hang indefinately on the whole project.

 {
      variant: "secondary",
      color: "brand",
      className: {
        base: [
          "border border-current text-brand",
          "data-[hovered]:bg-brand/10",
          "data-[pressed]:bg-brand/20",
        ],
      },
    },
    {
      variant: "secondary",
      color: "danger",
      className: {
        base: [
          "border border-current text-danger",
          "data-[hovered]:bg-danger/10",
          "data-[pressed]:bg-danger/20",
        ],
      },
    },

Expected behavior Intellisense should continue to work without hanging - i thought at first this was an intellisense issue however having narrowed it down to the tv config i strongly suspect the way that typescript types are generated internally within tailwind-variants is possibly producing a huge amount of variations causing the workspace wide freeze.

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

Smartphone (please complete the following information):

Additional context

mskelton commented 8 months ago

I'm experimenting with a new regex that is more performant and will update the docs after some more testing and usage.

"tailwindCSS.experimental.classRegex": [
  ["tv\\(([^)(]*(?:\\([^)(]*(?:\\([^)(]*(?:\\([^)(]*\\)[^)(]*)*\\)[^)(]*)*\\)[^)(]*)*)\\)", "\"(.*?)\""]
]
akomm commented 5 months ago

The issue is just the regex. I have it in any project. Add the regex, formatting chain hangs, remove the regex, formatting chain works again.

There is no perfect solution, because some weird cases are possible, like brackets in a string, but this one will at least balance the brackets to some depths and is fast:

[
  "tv\\((?<=\\()(?:[^()]*|\\([^)]*\\))+(?=\\))\\)",
  "[\"'`]([^\"'`]*).*?[\"'`]"
]

I didn't change the second regex that extracts the actual class names, because it doesn't ensure opening and closing string matching, but in normal case where you don't have syntax error in your code it will work, so good enough.

Here example regex101:

Newbie012 commented 2 months ago

related https://github.com/tailwindlabs/tailwindcss-intellisense/issues/973

bitabs commented 2 months ago

Any update on this?

mskelton commented 2 months ago

@bitabs If there were updates, they would be posted. Please don't post "are there any updates" type of comments. They are not helpful to maintainers.

ViktorPontinen commented 1 month ago

@binaryartifex @akomm Try the new pattern that was just merged: https://github.com/nextui-org/tailwind-variants-docs/pull/34 https://www.tailwind-variants.org/docs/getting-started#intellisense-setup-optional

FFGFlash commented 1 month ago

@ViktorPontinen this does seem a world of difference more performant, but now it registers everything as tailwind strings, which is frustrating when you define a literal and instead of getting suggested the literals, it suggests class names.

image

I've also noticed some weird cases, such as object destructuring, it sometimes suggests class names when I'm trying to autocomplete the key of an object, though this is inconsistent and I can't for the life of me remember where this occurred in my codebase.

Glad to know this is being looked at, hopefully some of this was found helpful.