-
-
Notifications
You must be signed in to change notification settings - Fork 12
Description
👋 again @schoero! I am using FlatConfig
and I believe that I have found an incompatibility of the presets. Here is an MWE (eslint.config.js
):
import eslintPluginBetterTailwindcss from "eslint-plugin-better-tailwindcss";
/** @type {import("eslint").Linter.Config[]} */
const configObjects = [
// ...other configs...
eslintPluginBetterTailwindcss.configs["recommended"] ?? {},
];
export default configObjects;
If type-checking is on, eslintPluginBetterTailwindcss.configs["recommended"]
produces this tsc error:
Type '{ plugins: string[]; rules: { [x: string]: "warn" | "error"; }; } | {}' is not assignable to type 'Config<RulesRecord>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Type '{ plugins: string[]; rules: { [x: string]: "warn" | "error"; }; }' is not assignable to type 'Config<RulesRecord>'.
Types of property 'plugins' are incompatible.
Type 'string[]' is not assignable to type 'Record<string, Plugin>'.
Index signature for type 'string' is missing in type 'string[]'.ts(2375)
Running eslint
with the above config gives a runtime error:
Oops! Something went wrong! :(
ESLint: 9.29.0
A config object has a "plugins" key defined as an array of strings. It looks something like this:
{
"plugins": ["better-tailwindcss"]
}
Flat config requires "plugins" to be an object, like this:
{
plugins: {
better-tailwindcss: pluginObject
}
}
Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#importing-plugins-and-custom-parsers
If you're using a shareable config that you cannot rewrite in flat config format, then use the compatibility utility:
https://eslint.org/docs/latest/use/configure/migration-guide#using-eslintrc-configs-in-flat-config
I was able to do this as a workaround for Tailwind v4:
import eslintPluginBetterTailwindcss from "eslint-plugin-better-tailwindcss";
/** @type {import("eslint").Linter.Config[]} */
const configObjects = [
// ...other configs...
{
plugins: {
"better-tailwindcss": eslintPluginBetterTailwindcss,
},
settings: {
"better-tailwindcss": {
entryPoint: `${import.meta.dirname}/path/to/entry-point.css`,
},
},
rules: {
"better-tailwindcss/enforce-consistent-class-order": "warn",
"better-tailwindcss/enforce-consistent-variable-syntax": "warn",
"better-tailwindcss/no-conflicting-classes": "error",
"better-tailwindcss/no-duplicate-classes": "warn",
"better-tailwindcss/no-restricted-classes": "error",
"better-tailwindcss/no-unnecessary-whitespace": "warn",
"better-tailwindcss/no-unregistered-classes": "error",
},
},
];
export default configObjects;
It was necessary to hand-pick the rules but everything worked in the end!
If you are looking for inspiration, take a look at eslint-plugin-react-hooks@6.0.0-rc.1. This plugin supports both FlatConfig and LegacyConfig and I can use it like this:
import eslintPluginReactHooks from "eslint-plugin-react-hooks";
/** @type {import("eslint").Linter.Config[]} */
const configObjects = [
// ...other configs...
eslintPluginReactHooks.configs.recommended,
];
export default configObjects;
PS: I’m really glad that I’ve discovered eslint-plugin-better-tailwindcss
, many thanks for working on it! It finally unblocks my migration to TailwindCSS v4 which was previously impossible because of francoismassart/eslint-plugin-tailwindcss#325 / francoismassart/eslint-plugin-tailwindcss#295.