mirror of
https://github.com/oxc-project/oxc.git
synced 2026-09-14 19:36:11 +08:00
26ed46bc02
Based on https://github.com/oxc-project/oxc/pull/16826 ## Summary Add experimental Tailwind CSS class sorting support to Oxfmt via integration with `prettier-plugin-tailwindcss`. This implementation uses a patch-based approach to export necessary functions from `prettier-plugin-tailwindcss`. We've requested better integration support from the Tailwind team at https://github.com/tailwindlabs/prettier-plugin-tailwindcss/issues/430, and can improve the integration when that's available. ## Features - ✅ Sorts Tailwind CSS classes in `className` and `class` attributes - ✅ Sorts classes in custom JSX attributes (configurable) - ✅ Sorts classes in function calls like `clsx()`, `cn()`, `tw()` (configurable) - ✅ Supports template literals with expressions - ✅ Supports Tailwind v3 config files and v4 stylesheets - ✅ Preserves whitespace and duplicates (configurable) - ✅ **Fixes [prettier-plugin-tailwindcss#426](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/issues/426)** - Correctly handles strings in nested non-Tailwind call expressions - ⏳ Non-JS file support (HTML, Vue, Svelte, etc.) - Coming in follow-up PR - ⏳ Tailwind CSS config migration in `oxfmt --migrate=prettier` - Coming in follow-up PR ## Example Usage ### Basic Usage Enable Tailwind CSS sorting with default options by setting `experimentalTailwindcss` to an empty object in your `.oxfmtrc.json`: ```json { "experimentalTailwindcss": {} } ``` ### With Configuration Options ```json { "experimentalTailwindcss": { "config": "./tailwind.config.js", "functions": ["clsx", "cn", "cva", "tw"], "attributes": ["myCustomClass"], "preserveWhitespace": false, "preserveDuplicates": false } } ``` ### Configuration Options All options from `prettier-plugin-tailwindcss` are supported (with `tailwind` prefix removed): | Option | Type | Description | Default | |--------|------|-------------|---------| | `config` | `string` | Path to your Tailwind CSS v3 configuration file. Paths are resolved relative to the Oxfmt configuration file. | `"./tailwind.config.js"` | | `stylesheet` | `string` | Path to your Tailwind CSS v4 stylesheet. Paths are resolved relative to the Oxfmt configuration file. | `undefined` | | `functions` | `string[]` | List of custom function names that contain Tailwind CSS classes (e.g., `["clsx", "cn", "cva", "tw"]`). | `[]` | | `attributes` | `string[]` | List of custom JSX attributes that should be sorted (e.g., `["myCustomClass"]`). Note: `class` and `className` are always sorted by default. | `[]` | | `preserveWhitespace` | `boolean` | Preserve whitespace around classes. | `false` | | `preserveDuplicates` | `boolean` | Preserve duplicate classes. | `false` | ## Migration from prettier-plugin-tailwindcss If you're currently using `prettier-plugin-tailwindcss`, you can migrate to Oxfmt's built-in support: ### Manual Migration (Current) #### Before (Prettier) ```json { "plugins": ["prettier-plugin-tailwindcss"], "tailwindConfig": "./tailwind.config.js", "tailwindFunctions": ["clsx", "cn"] } ``` #### After (Oxfmt) ```json { "experimentalTailwindcss": { "config": "./tailwind.config.js", "functions": ["clsx", "cn"] } } ``` **Key differences:** - Remove `tailwind` prefix from all option names (e.g., `tailwindConfig` → `config`) - No need to install `prettier-plugin-tailwindcss` separately, it is bundled within Oxfmt ### Automated Migration (Follow-up PR) Tailwind CSS configuration migration will be added to the existing `oxfmt --migrate=prettier` command in a follow-up PR. This will automatically convert your `prettier-plugin-tailwindcss` settings from `.prettierrc` to `.oxfmtrc.json`. ## Implementation Details ### Technical Approach - Uses `pnpm patch` to export necessary functions from `prettier-plugin-tailwindcss` - Implements Rust-side detection for Tailwind contexts (JSX attributes, function calls, template literals) - Passes class strings to the JS plugin for sorting via external callback - Optimized context tracking to avoid repeated AST traversal ### Improvements Over prettier-plugin-tailwindcss - **Context-based quasi position tracking** ([tailwindcss.rs:273-276](https://github.com/oxc-project/oxc/blob/main/crates/oxc_formatter/src/utils/tailwindcss.rs#L273-L276)) - Stores template literal position in context stack instead of traversing AST, improving performance - **Fixes [issue #426](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/issues/426)** - Correctly handles strings in nested non-Tailwind call expressions (e.g., `value.includes("\n")` no longer gets corrupted) - **Comprehensive edge case testing** - Added 58 tests covering edge cases, nested scenarios, error handling, and performance ## Changes - Changed `experimentalTailwindcss` option from `boolean` to `TailwindcssOptions` object - Added all configuration options from `prettier-plugin-tailwindcss` (without `tailwind` prefix) - Exported necessary functions from `prettier-plugin-tailwindcss` via patch - Added comprehensive test suite with 58 tests - Improved documentation for all configuration options ## Test Plan - [x] `pnpm test` passes (58 tests) - [x] `cargo clippy` passes - [x] `just fmt` passes - [x] Basic Tailwind class sorting works with `class` and `className` attributes - [x] `attributes` option sorts custom JSX attributes - [x] `functions` option sorts string arguments in function calls (e.g., `clsx()`, `cn()`) - [x] Template literals with expressions handle whitespace correctly - [x] Edge cases: empty strings, Unicode, emoji, special characters - [x] Nested scenarios: deeply nested template literals, function calls - [x] Strings in nested non-Tailwind calls are preserved (fixes [#426](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/issues/426)) - [x] Test in https://github.com/tailwindlabs/headlessui and https://github.com/dubinc/dub ## Follow-up Work - **Non-JS file support** - HTML, Vue, Svelte, etc. by enabling original plugin when `experimentalTailwindcss` is set - **Migration support** - Add Tailwind CSS config migration to existing `oxfmt --migrate=prettier` command - **Better integration** - Improve when https://github.com/tailwindlabs/prettier-plugin-tailwindcss/issues/430 is resolved 🤖 Generated with [Claude Code](https://claude.com/claude-code)
964 B
964 B