#tailwind #css-class #编译时 #补全 #前端 #生成 #检查

app tailwindcss-to-rust

从编译后的Tailwind CSS生成Rust代码

9个版本

0.3.2 2023年2月19日
0.3.1 2023年2月19日
0.2.0 2023年2月5日
0.1.4 2022年4月24日
0.1.3 2022年2月17日

#456 in Web编程

Apache-2.0 OR MIT

390KB
8K SLoC

tailwindcss-to-rust”命令行工具生成Rust代码,允许您从Rust代码中引用Tailwind类。这意味着任何尝试使用不存在类的操作都将导致编译时错误,您可以使用代码补全来列出可用的类。

此工具已在Tailwind 3.2.x版本上进行了测试。

生成的代码允许您在Rust前端代码中使用Tailwind CSS类,对类名进行编译时检查并提供代码补全。这些类根据Tailwind文档中的标题分组。它还生成完整的Tailwind修饰符列表的代码,如lghover等。

查看tailwindcss-to-rust-macros crate,以获取使用此工具生成的代码的最便捷方式。

所以,您不需要这样做

let class = "pt-4 pb-2 text-whit";

您可以这样做

let class = C![C::spc::pt_4 C::pb_2 C::typ::text_white];

请注意,第一个示例中的错误拼写“text-whit”(缺少“e”)如果在您写入C::typ::text_whit时,将会变成编译时错误。

以下是快速入门指南

  1. 通过运行以下命令安装此工具

    cargo install tailwindcss-to-rust
    
  2. 安装tailwindcss命令行工具。您可以使用npmnpx安装它,或者您可以从tailwindcss仓库下载独立的二进制文件。

  3. 通过运行以下命令使用工具创建一个tailwind.config.js文件

    tailwindcss init
    
  4. 根据需要编辑此文件,以添加插件或自定义生成的CSS。

  5. 为Tailwind创建一个CSS输入文件。在本例中,我们将假设它位于css/tailwind.css。标准文件如下所示

    @tailwind base;
    @tailwind components;
    @tailwind utilities;
    
  6. 通过运行以下命令生成您的Rust代码

    tailwindcss-to-rust \
         --tailwind-config tailwind.config.js \
         --input tailwind.css \
         --output src/css/generated.rs \
         --rustfmt
    

    当您运行tailwindcss-to-rust时,tailwindcss可执行文件必须在您的PATH中,或者您必须通过--tailwindcss参数提供可执行文件的路径。

  7. 编辑您的tailwind.config.js文件,以便在Rust文件中查找Tailwind类名

    /** @type {import('tailwindcss').Config} */
    module.exports = {
      content: {
        files: ["index.html", "**/*.rs"],
        // You do need to copy this big block of code in, unfortunately.
        extract: {
          rs: (content) => {
            const rs_to_tw = (rs) => {
              if (rs.startsWith("two_")) {
                rs = rs.replace("two_", "2");
              }
              return rs
                .replaceAll("_of_", "/")
                .replaceAll("_p_", ".")
                .replaceAll("_", "-");
            };
    
            let one_class_re = "\\bC::[a-z0-9_]+::([a-z0-9_]+)\\b";
            let class_re = new RegExp(one_class_re, "g");
            let one_mod_re = "\\bM::([a-z0-9_]+)\\b";
            let mod_re = new RegExp(one_mod_re + ", " + one_class_re, "g");
    
            let classes = [];
            let matches = [...content.matchAll(mod_re)];
            if (matches.length > 0) {
              classes.push(
                ...matches.map((m) => {
                  let pieces = m.slice(1, m.length);
                  return pieces.map((p) => rs_to_tw(p)).join(":");
                })
              );
            }
            classes.push(
              ...[...content.matchAll(class_re)].map((m) => {
                return rs_to_tw(m[1]);
              })
            );
    
            return classes;
          },
        },
      },
      theme: {
        extend: {},
      },
      plugins: [],
    };
    

    请注意,您可能需要自定义 extract 函数中的正则表达式以匹配您的模板系统! 此示例中的正则表达式将匹配您在 tailwindcss-to-rust-macros 包中使用的语法。

    例如,如果您在未使用宏的情况下使用 askama,则可能需要匹配以下内容

    <div
      class="{{ M::hover }}:{{ C::bg::bg_rose_500 }} {{ C::bg::bg_rose_800 }}"
    >
      ...
    </div>
    

    相应的正则表达式可能如下所示

    let one_class_re = "{{\\s*C::[a-z0-9_]+::([a-z0-9_]+)\\s*}}";
    let class_re = new RegExp(one_class_re, "g");
    let one_mod_re = "{{\\s*M::([a-z0-9_]+)\\s*}}";
    let mod_re = new RegExp(one_mod_re + ":" + one_class_re, "g");
    
  8. 修修改改...

  9. 通过运行以下命令重新生成编译后的 Tailwind CSS 文件

    tailwindcss --input css/tailwind.css --output css/tailwind_compiled.css`
    
  10. 请确保在您的 HTML 中导入编译后的 CSS

    <link data-trunk rel="css" href="/css/tailwind_compiled.css" />
    

在此示例中,我使用的是 Trunk,这对于想要使用 Rust -> WASM 而不需要任何 node.js 工具的项目来说是一个出色的替代品。我的 Trunk.toml 看起来像这样

[build]
target = "index.html"
dist = "dist"

[[hooks]]
stage = "build"
# I'm not sure why we can't just invoke tailwindcss directly, but that doesn't
# seem to work for some reason.
command = "sh"
command_arguments = ["-c", "tailwindcss -i css/tailwind.css -o css/tailwind_compiled.css"]

当我运行 trunk 时,我必须确保忽略那个生成的文件

trunk --ignore ./css/tailwind_compiled.css ...

生成的名称包括 CSS 文件中出现的所有类名,但不包括以下名称:以连字符(-)开头的名称,包含伪元素的名称,例如 .placeholder-opacity-100::-moz-placeholder,以及包含修饰符(如 lghover)的名称。名称将通过以下算法转换为 Rust 标识符

  • 完全删除所有反斜杠转义,例如在 .inset-0\.5 中。
  • 所有连字符(-)变为下划线(_)。
  • 所有点(.)变为 _p_,因此 .inset-2\.5 变为 inset_2_p_5
  • 所有正斜杠(/)变为 _of_,因此 .inset-2\/4 变为 inset_2_of_4
  • 如果名称 以数字 2 开头,例如 2xl,则变为 two_,因此 2xl 修饰符变为 two_xl
  • 名称 static 变为 static_

生成的代码提供包含所有相关字符串的两个模块。

C 模块包含多个子模块,每个子模块对应 TailwindCSS 文档中记录的每个类组。组如下

pub(crate) mod C {
    // Accessibility
    pub(crate) mod acc { ... }

    // Animation
    pub(crate) mod anim { ... }

    // Backgrounds
    pub(crate) mod bg { ... }

    // Borders
    pub(crate) mod bor { ... }

    // Effects
    pub(crate) mod eff { ... }

    // Filter
    pub(crate) mod fil { ... }

    // Flexbox & Grid
    pub(crate) mod fg { ... }

    // Interactivity
    pub(crate) mod intr { ... }

    // Layout
    pub(crate) mod lay { ... }

    // Sizing
    pub(crate) mod siz { ... }

    // Spacing
    pub(crate) mod spc { ... }

    // SVG
    pub(crate) mod svg { ... }

    // Tables
    pub(crate) mod tbl { ... }

    // Transforms
    pub(crate) mod trn { ... }

    // Typography
    pub(crate) mod typ { ... }
}

在您的代码中,您可以使用 C::typ::text_lgC::lay::flex 来引用类。如果您有任何自定义类,这些类将以 "unknown" 组结束,该组可通过 C::unk 获取。将这些自定义类放入其他组的实现是一个待办事项。

修饰符有自己的模块,称为 M,其中每个修饰符对应一个字段,因此用作 M::lgM::hover。一些可参数化的修饰符未包含在内,例如 aria-*data-* 等。

了解生成的模块的最佳方式是在您的编辑器中打开生成的代码文件并查看它。

然后您可以在代码中导入这些常量,并使用它们来引用 Tailwind CSS 类名并进行编译时检查

element.set_class(C::lay::aspect_auto);

依赖项

~6–17MB
~227K SLoC