Español
Interop con oxfmt y prettier-plugin-tailwindcss
enforce-sort-order produce el orden oficial de clases de Tailwind — el mismo que produce prettier-plugin-tailwindcss, y el sortTailwindcss de oxfmt, que implementa el mismo algoritmo. El formateador y este plugin coinciden en cada string de clases que toca el formateador, cuando los dos leen el mismo CSS y el formateador conoce tus helpers de clases. Dos settings lo logran.
1. El mismo stylesheet
Por defecto el formateador lee el theme que trae el paquete tailwindcss instalado — no el CSS de tu proyecto — así que no conoce tus tokens de @theme y los ordena distinto: bg-brand y text-brand se ordenan como clases desconocidas. Apúntalo al archivo que lee este plugin.
2. Tus helpers de clases
El formateador ordena los atributos de clase (className, class) y solo las funciones que listes. cn("p-4 flex") queda sin ordenar salvo que cn esté en functions, mientras que este plugin ordena cada string de clases que extrae. Lista los helpers que uses:
jsonc
// .oxfmtrc.json
{
"sortTailwindcss": {
"stylesheet": "./src/styles.css",
"functions": ["cn", "clsx", "cva", "tv"]
}
}Los mismos dos settings para prettier:
jsonc
// .prettierrc
{
"plugins": ["prettier-plugin-tailwindcss"],
"tailwindStylesheet": "./src/styles.css",
"tailwindFunctions": ["cn", "clsx", "cva", "tv"]
}Quién hace qué
Con los dos settings, correr el formateador no le deja nada que reportar a enforce-sort-order en los atributos de clase ni en los helpers listados, y correr oxlint --fix no le deja nada que cambiar al formateador. Los strings de clases que el formateador nunca formatea — una variable const classes = "…", un template tw — siguen siendo del linter.
El formateador además elimina clases duplicadas y colapsa espacios en los strings que formatea, así que ahí se solapa con no-duplicate-classes y no-unnecessary-whitespace; las reglas de lint siguen cubriendo todo lo demás.
Eso incluye los saltos de línea de un string de clases que enforce-consistent-line-wrapping envolvió en un bloque, ya sea un atributo de clases (wrapStrings: "jsx") o un template en un helper que el formateador ordena (cn(…) con wrapStrings: "all"): el formateador lo vuelve a dejar en una línea, y cada uno deshace lo del otro. Pon preserveWhitespace: true en sortTailwindcss para conservar el bloque.
--fix más de una vez
Cuando varias reglas corrigen el mismo string de clases (un duplicado, espacios de más y el orden), oxlint aplica una de esas correcciones por corrida: no tiene fixes en varias pasadas. Corre oxlint --fix de nuevo, o deja que el formateador haga el orden, los duplicados y los espacios de una vez.
Por qué esto no se arregla upstream
El equipo de Tailwind intencionalmente requiere config explícita para el stylesheet en v4. No hay convención tipo tailwind.config.js para autodetectar en v4 — los archivos CSS pueden vivir en cualquier parte y llamarse como sea. El plugin cae al theme.css empaquetado en vez de adivinar.
oxlint-tailwindcss v1 sigue la misma filosofía (entryPoint explícito), así que el único paso necesario para la consistencia es decirle a cada herramienta la misma ruta.
¿Y tailwindcss-animate y @tailwindcss/typography?
Si usas plugins que registran clases (por ejemplo prose-*, animate-in), se importan vía tu @import en CSS — ambas herramientas las toman automáticamente siempre que lean el mismo stylesheet.
Múltiples stylesheets por proyecto
Si distintas partes de tu monorepo usan distintos archivos CSS, mira la guía de monorepo. Los mismos patrones aplican a oxfmt: sus overrides pueden apuntar distintos globs de archivos a distintos stylesheets.
jsonc
// .oxfmtrc.json
{
"sortTailwindcss": { "functions": ["cn"] },
"overrides": [
{
"files": ["packages/admin/**"],
"options": {
"sortTailwindcss": { "stylesheet": "./packages/admin/src/admin.css", "functions": ["cn"] }
}
}
]
}