Catch Tailwindcss Errors at Compile-Time Before They Catch You, without making any change to your code! Supports overriding, extending, custom classes, custom modifiers, Plugins and many more πŸš€πŸ”₯πŸ¦€

Overview

twust

Twust is a powerful static checker in rust for TailwindCSS class names at compile-time.

Screenshot 2023-10-11 at 1 40 26

Table of Contents

Overview

twust is a Rust procedural macro that provides compile-time validation for TailwindCSS class names. Leveraging the power of Rust's macro system, twust ensures that you only use valid TailwindCSS class names, preventing runtime errors and promoting a more robust development experience.

Installation

Add twust to your Cargo.toml:

[dependencies]
twust = "1.0.4"

Usage

Simply prefix your TailwindCSS class strings with the tw! macro:

use twust::tw;

let classes = tw!("bg-blue-500 hover:bg-blue-700");
    // You can override/extend color/background color in tailwind.config.json
tw!("bg-taxvhiti bg-tahiti-500 bg-tahiti bg-midnight bg-purple bg-red-50 bg-tahiti-800 border-s-tahiti-800");
tw!("md:text-red-50 text-slate-50 text-purple text-tahiti-500");
tw!("py-sm md:py-md tablet:py-sm lg:py-lg xl:py-xl");
tw!("group");
tw!("hover:-translate-y-0.5 transition motion-reduce:hover:translate-y-0 motion-reduce:transition-none");
tw!("group/edit block invisible md:hover:bg-slate-200 group-hover/item:visible");
tw!("group-[:nth-of-type(3)_&]:block group-hover/edit:text-gray-700 group-[:nth-of-type(3)_&]:block");
tw!("scroll-m-15 group-aria-[sort=ascending]:rotate-0");

// Even scroll margin can also be configured, here we add, sm and md under the Spacing/scrollMargin field in the config file
tw!("scroll-mx-sm scroll-mx-md");
tw!("px-[-45px] px-[-45cm] px-[-45rem] px-[-45em] px-[-45%] px-[-45vh]");
tw!("m-4 last:first:invalid:last:first:p-4 last:m-4 pb-[calc(100%-34px)] pb-[23px] [mask-type:luminance]
    [mask-type:luminance] hover:[mask-type:alpha] lg:[--scroll-offset:44px] oyelowo oyedayo break-after-avoid"
);
tw!("h-full border-2 border-opacity-60 rounded-lg overflow-hidden");

If an invalid class name is used, the compiler will raise an error, preventing it from being used in your application.

Statement of Problem

TailwindCSS offers developers a flexible utility-first approach to styling web applications. However, its flexibility can also lead to potential pitfalls:

  • Runtime Errors: Invalid TailwindCSS class names can cause unexpected styling issues that are only caught during runtime.

  • Developer Experience: Manually validating class names can be tedious and error-prone. Moreover, relying on runtime checks or external tools can disrupt the development workflow.

  • Incompatibility with Plugins: Some TailwindCSS utilities extend their functionality with plugins like daisyui. Traditional methods might not support these extensions seamlessly, leading to a fragmented development experience.

  • Code Reusability: Directly copying and reusing TailwindCSS code from one project to another can often require manual transformations or mappings, reducing developer efficiency.

  • Increased Build Size: Invalid class names that slip into the production code can increase the size of the final CSS bundle, affecting performance.

Solution

twust addresses these challenges by offering:

  • Compile-time Validation: By checking the validity of TailwindCSS class names at compile time, twust prevents invalid class names from making their way into the production code.

  • Seamless Integration: As a Rust macro, twust integrates seamlessly into your Rust workflow, offering immediate feedback without the need for external tools or manual validation.

  • Plugin Support: With twust, you can easily integrate popular plugins like daisyui by merely specifying them as a feature, ensuring a consistent and extended development experience.

  • Effortless Code Reusability: The ability to copy-paste and reuse your TailwindCSS code without any manual mappings or transformations. Just wrap your code with the macro, and you're set.

  • Optimized Builds: By ensuring only valid class names are used, twust helps in reducing the unnecessary bloat in the final CSS bundle.

Features

  • Comprehensive Coverage: Supports all standard TailwindCSS class names, including responsive variants, pseudo-class variants, and more.

  • Custom Configurations: Easily integrate with custom TailwindCSS configurations to support custom utility classes.

  • Plugin Integration: Enable support for popular plugins like daisyui by specifying them as a feature, offering an extended range of class names.

  • Easy Code Reusability: Directly copy-paste your TailwindCSS code across projects without any manual effort, ensuring rapid development.

  • Performance: Designed with performance in mind, ensuring minimal overhead during the compilation process.

How does this compare with Other Rust Libraries

tailwindcss-to-rust

tailwindcss-to-rust is a CLI tool that generates Rust code from compiled TailwindCSS. It allows developers to refer to Tailwind classes from Rust, offering compile-time error checks for nonexistent classes and code completion for available classes.

Shortcomings:

  1. Complex Setup: The setup process for tailwindcss-to-rust requires several steps, including:

    • Installing multiple tools.
    • Customizing tailwind.config.js for Rust file checks.
    • Generating Rust code and ensuring the tailwindcss executable is in the PATH.
    • Modifying regular expressions to match a specific templating system.

    This setup can be daunting, especially for developers unfamiliar with TailwindCSS or Rust.

  2. Generated Code Maintenance: tailwindcss-to-rust generates code based on the current state of the TailwindCSS configuration. Any changes to the configuration or updates to TailwindCSS itself may require regenerating the Rust code, making maintenance more challenging.

  3. Custom Class Grouping: While the tool groups classes based on the Tailwind documentation, custom classes end up in an "unknown" group (C::unk). Although there's a plan to improve this, it's not yet implemented.

  4. Limited Modifiers: Some parameterizable modifiers like aria-* and data-* are not included. Depending on the project, this can be a significant limitation.

  5. External Dependencies: The tool requires the presence of the tailwindcss CLI tool, either through npm or as a standalone binary. This adds an external dependency, which might not be suitable for all projects, especially those that want to minimize their dependency tree.

Approach with twust

Our solution with twust offers a more streamlined and integrated approach:

  • Simpler Setup: Just add the macro to your project and start using it. No need for external tools or additional configuration steps.

  • Real-time Validation: Instead of generating static Rust code from TailwindCSS, twust validates class names in real-time during the compilation process.

  • No External Dependencies: twust is self-contained, meaning you don't need any external tools like the tailwindcss CLI.

  • Extensive Coverage: We support all standard TailwindCSS class names, including responsive variants, pseudo-class variants, and more. With the macro's flexibility, supporting newer TailwindCSS features becomes easier.

tailwind.config.json Overview

Basic Structure:

{
  "corePlugins": {},
  "allowedLists": {
    "classes": [],
    "modifiers": []
  },
  "theme": {
    ...utilities...
    "extend": {
      ...extended utilities...
    }
  },
  "variants": {},
  "plugins": {}
}

Key Sections:

  1. corePlugins: Determines which utility plugins should be included in the generated CSS. Each key represents a utility, and its value (true/false) determines if it should be generated.

  2. allowedLists:

    • classes: Array of allowed class names.
    • modifiers: Array of allowed modifiers like hover, focus, etc.
  3. theme: Defines the default values and customizations for your design system.

    In the main section of theme, you have configurations for different utilities like screens, colors, spacing, etc. The extend section within theme allows you to add additional values to the default set.

Contribution

Contributions are always welcome! If you have suggestions, bug reports, or want to contribute to the code, please open an issue or pull request.

License

twust is licensed under the MIT license. See the LICENSE file for details.

You might also like...
Sero is a web server that allows you to easily host your static sites without pain. The idea was inspired by surge.sh but gives you full control.

sero Lightning-fast, static web publishing with zero configuration and full control πŸ“– Table Of Contents πŸ“– Table Of Contents πŸ”§ Tools ❓ About The Pro

Translation support for mdbook. The plugins here give you a structured way to maintain a translated book.

Gettext Translation Support for mdbook The plugins here makes it easy to translate documentation written in mdbook into multiple languages. Support fo

ChatGPT powered Rust proc macro that generates code at compile-time.

gpt-macro ChatGPT powered Rust proc macro that generates code at compile-time. Implemented Macros auto_impl!{} #[auto_test(...)] Usage Get ChatGPT API

Shellfirm - Intercept any risky patterns (default or defined by you) and prompt you a small challenge for double verification
Shellfirm - Intercept any risky patterns (default or defined by you) and prompt you a small challenge for double verification

shellfirm Opppppsss you did it again? 😱 😱 😰 Protect yourself from yourself! rm -rf * git reset --hard before saving? kubectl delete ns which going

Automate your business flows, support, change tickets with Automatdeck
Automate your business flows, support, change tickets with Automatdeck

Automatdeck agent Website: https://automatdeck.com Documentation: https://doc.automatdeck.com Automatdeck agent is a simple lightweight IT automation

Standard Graphics is a command-line tool for printing 2D graphics from any language to any screen.
Standard Graphics is a command-line tool for printing 2D graphics from any language to any screen.

2D graphics in any programming language with just print statements!

Enhance Rust errors with file and line details using the `#[wherr]` macro for clearer debugging.

wherr Crate Discuss wherr on Hacker News Enhance Rust's ? operator by appending file and line number details to errors, simplifying the debugging proc

A command line application which sets your wall paper with new image generating pollens once they arrive.

pollenwall Table of Contents pollenwall About Installation Binary releases Build from source Usage Command Line Arguments Running as a service MacOS L

Cloc - cloc counts blank lines, comment lines, and physical lines of source code in many programming languages.

cloc Count Lines of Code cloc counts blank lines, comment lines, and physical lines of source code in many programming languages. Latest release: v1.9

Comments
  • 5 Improve Robustness of Tailwind Class Parsing in Rust

    5 Improve Robustness of Tailwind Class Parsing in Rust

    Summary

    This pull request introduces a significant refactor of the text parsing mechanism in the project. The initial implementation used manual string manipulation for parsing the text strings, which while functional, wasn't very scalable and maintainable. This PR replaces the manual string manipulation with a more sophisticated and efficient approach using combinatorial parsing techniques.

    Able to parse this successfully with robust error checks:

    tw!(
            r#"[mask-type:alpha] [mask-type:alpha] before:content-['rerer  erer re rr r  \re  reFestivus']
        after:content-['I am a content'] after:content-['I am a content'] after:content-['I am a content']
            active:hover:text-[#bada55] active:hover:text-[#fa5] text-[#bada55] hover:aria-checked:text-[22px]
            text-[22.34e434cm]
            before:content-['hello\_world']
        grid grid-cols-[fit-content(theme(spacing.32))]
        bg-[--my-color]
            text-[var(--my-var)]
            text-[length:var(--my-var)]
            text-[color:var(--my-var)]
            [--scroll-offset:56px] lg:[--scroll-offset:44px]
            btn bg-[url('/img/down-arrow.svg')] ring-white/10   bg-black/25  bg-black/[80%] bg-black/[100] bg-black/[0.75]    active:hover:collapse-arrow
    
        [mask-image:linear-gradient(180deg,white,rgba(255,255,255,0))]
    
        pt-8 text-base font-semibold leading-7
    
        bg-[rgb(0,0,3)] absolute inset-0 bg-center 
    
        -mt-4
    
            lg:[&:nth-child(3)]:hover:underline
            group-[:nth-of-type(3)_&]:block
         [&_p]:mt-4
    
         flex [@supports(display:grid)]:grid
         flex active:hover:[@supports(display:grid)]:grid
    
         [@media(any-hover:hover){&:hover}]:opacity-100
    
             hidden group-[.is-published]:block
         group-[:nth-of-type(3)_&]:block
         peer-[.is-dirty]:peer-required:block hidden
         hidden peer-[:nth-of-type(3)_&]:block
    
             group/edit invisible hover:bg-slate-200 group-hover/item:visible
    
         peer-checked/published:text-sky-500
        
    after:content-['*'] after:ml-0.5 after:text-red-500 block text-sm font-medium text-slate-700
    
        before:content-[''] before:block
    content-[>]
    content-[<]
        
        bg-black/75 supports-[backdrop-filter]:bg-black/25 supports-[backdrop-filter]:backdrop-blur
    
    aria-[sort=ascending]:bg-[url('/img/down-arrow.svg')] aria-[sort=descending]:bg-[url('/img/up-arrow.svg')]
    
    
     group-aria-[sort=ascending]:rotate-0 group-aria-[sort=descending]:rotate-180
        
     data-[size=large]:p-8
    
        open:bg-white dark:open:bg-slate-900 open:ring-1 open:ring-black/5 dark:open:ring-white/10 open:shadow-lg p-6 rounded-lg
        
        lg:[&:nth-child(3)]:hover:underline
    
         min-[320rem]:text-center max-[600px]:bg-sky-300
    
     top-[117px] lg:top-[344px]
    
         bg-[#bada55] text-[22px] before:content-['Festivus']
    
    
         grid grid-cols-[fit-content(theme(spacing.32))]
    
         bg-[--my-color]
    
     [mask-type:luminance] hover:[mask-type:alpha]
    
     [--scroll-offset:56px] lg:[--scroll-offset:44px]
    
     lg:[&:nth-child(3)]:hover:underline
     bg-[url('/what_a_rush.png')]
     before:content-['hello\_world']
     text-[22px]
     text-[#bada55]
     text-[var(--my-var)]
     text-[length:var(--my-var)]
     text-[color:var(--my-var)]
    
    
         p-6 max-w-sm mx-auto bg-white rounded-xl shadow-lg flex items-center space-x-4
    
    
                  w-[calc(100%_-_theme("spacing[1.5]))"]
              shadow-[inset_0_-3em_3em_rgba(0,_0,_0,_0.1),_0_0_0_2px_rgb(255,_255,_255),_0.3em_0.3em_1em_rgba(0,_0,_0,_0.3)]
    
    
            "#
        );
    
    

    Changes

    • Replaced manual string manipulation functions with a combinatorial parser.
    • Added new utility functions for more readable and maintainable code.
    • Updated unit tests to reflect the changes in the parsing logic.
    • Improved error handling and validation checks.
    • Added extensive comments and documentation for the new implementation.

    Rationale

    The manual string manipulation was becoming complex, error-prone, and hard to maintain as the requirements evolved. The new combinatorial parsing approach offers the following advantages:

    1. Scalability: Easily extendable to accommodate new parsing rules.
    2. Maintainability: Easier to read and manage the codebase.
    3. Performance: Faster parsing times and optimized memory usage.
    4. Robustness: Improved error handling and validation.

    Testing

    • All existing unit tests pass.
    • Added new unit tests to cover additional edge cases.
    • Conducted performance benchmarks to verify the improvements.

    Future Work

    • Further optimization of the parsing algorithm.
    • Adding more features that could leverage the new parsing mechanism.

    Deployment

    • Ensure that you run the updated unit tests before merging this PR.
    • Follow the usual deployment steps as outlined in the project's README.

    This PR has been meticulously designed to provide a high-quality, scalable solution for our text parsing needs. It significantly improves upon the previous implementation and sets the stage for future extensions.

    Reviewers

    • Please review the changes and run the unit tests.
    • Any feedback on the new implementation is highly welcome.

    This Pull Request aims to maintain the high standards of code quality and performance that we aim for in this project.

    bug enhancement 
    opened by Oyelowo 0
Owner
Creator of Surreal-Orm, Twust
null
A filesystem driver that allows you to view your Blackboard course contents as if they were normal files and folders on your system!

BlackboardFS Blackboard: noun A website so bad that it might as well be a network drive. BlackboardFS is a filesystem driver that allows you to view y

null 22 Sep 4, 2023
Fermyon Spin + Dioxus - Client Side Rendering (CSR) template with TailwindCSS

spin-dioxus-csr Fermyon Spin + Dioxus - Client Side Rendering (CSR) template with Tailwind Setup Accomodate "chicken & egg" issue for https://github.c

null 4 Apr 9, 2024
Store your transfer.sh links, so you can remember them later and know when they will expire, but now written in Rust.

Transfer.sh helper Rusted The idea of the script is to store your transfer.sh links and simplify its usage, so you can remember them later and know wh

Reinaldo Rozato Junior 10 Nov 30, 2022
(Pre-Release Software) Secure, Encrypted, P2P chat written atop Warp, IPFS, LibP2P, Dioxus and many more awesome projects and protocols.

Uplink Privacy First, Modular, P2P messaging client built atop Warp. Uplink is written in pure Rust with a UI in Dioxus (which is also written in Rust

Satellite 13 Jan 25, 2023
Stockbook embeds 1-bit raster images in your code at compile time

stockbook Stockbook embeds 1-bit raster images in your code at compile time. Designed primarily for #![no_std] usage, in embedded or other program-mem

Karol Belina 3 Oct 27, 2022
Deadliner helps you keep track of the time left for your deadline by dynamically updating the wallpaper of your desktop with the time left.

Deadliner Watch the YouTube video What's Deadliner? Deadliner is a cross-platform desktop application for setting deadline for a project and keeping t

Deadliner 34 Dec 16, 2022
I will be attempting Advent of Code 2022 with Rust, a language I have never learned before.

Advent of Code 2022 This year, I will be attempting Advent of Code with Rust, a language I have never learned before. I will also be taking some notes

null 4 Jan 7, 2023
Warp is a blazingly fast, Rust-based terminal that makes you and your team more productive at running, debugging, and deploying code and infrastructure.

Warp is a blazingly fast, Rust-based terminal that makes you and your team more productive at running, debugging, and deploying code and infrastructure.

Warp 10.4k Jan 4, 2023
Command-line tool that provides a workflow for extending, editing, diffing, and writing to vim-style grep lines.

Grug Grug is a command-line tool that provides a workflow for expanding, editing, diffing, and writing edits to files using vim-styled grep lines (suc

null 4 Apr 25, 2023
Use your computer as a cosmic ray detector! One of the memory errors Rust does not protect against.

Your computer can double up as a cosmic ray detector. Yes, really! Cosmic rays hit your computer all the time. If they hit the RAM, this can sometimes

Johanna SΓΆrngΓ₯rd 110 Jun 16, 2023