You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于使用Rust宏在编译时聚合CSS样式数据的技术问询

实现编译时CSS聚合与输出的方案

一、编译时全局聚合为单个字符串

你当前用phf实现了编译时哈希表,但phf是静态不可变的,无法直接动态合并多个宏生成的哈希表。可以借助编译时切片收集+全局静态变量的方式实现:

1. 使用linkme crate收集样式片段

linkme的#[distributed_slice]可以让你在多个宏展开点将样式数据注入到同一个全局切片中,编译时完成收集。先添加依赖:

[dependencies]
linkme = "0.3"
phf = { version = "0.11", features = ["macros"] }
once_cell = "1.18" # 用于全局静态变量的懒初始化

定义全局切片和聚合逻辑:

use linkme::distributed_slice;
use once_cell::sync::Lazy;
use phf::Map;

// 定义分布式切片,收集所有样式表的PHF映射
#[distributed_slice]
pub static CSS_STYLESHEETS: [&'static Map<&'static str, &'static str>; _];

// 全局聚合后的CSS字符串,懒初始化
pub static GLOBAL_CSS: Lazy<String> = Lazy::new(|| {
    CSS_STYLESHEETS.iter()
        .flat_map(|sheet| sheet.iter())
        .map(|(selector, props)| {
            format!("{} {{{}}}", selector, props.replace(',', "; "))
        })
        .collect::<Vec<_>>()
        .join("\n")
});

2. 修改宏生成代码,注册样式到切片

调整css_stylesheet!宏,让生成的PHF映射自动加入全局切片:

macro_rules! css_stylesheet {
    ($($selector:ident : { $($prop:ident: $val:literal),* },)*) => {
        // 生成当前样式表的PHF映射
        static LOCAL_STYLES: phf::Map<&'static str, &'static str> = phf_map! {
            $(stringify!($selector) => concat!($(stringify!($prop), ": ", $val, ","),*)),*
        };

        // 将当前映射注册到分布式切片
        #[linkme::distributed_slice(CSS_STYLESHEETS)]
        static _ENTRY: &'static phf::Map<&'static str, &'static str> = &LOCAL_STYLES;
    };
}

所有通过css_stylesheet!定义的样式会在编译时被收集,程序启动后访问*GLOBAL_CSS即可得到合并后的完整CSS字符串。

二、编译时将CSS写入文件

如果需要直接在编译阶段生成独立CSS文件,可借助build script配合宏生成的元数据实现:

1. 宏生成编译时元数据

让宏将样式信息以字符串格式输出到编译元数据中:

#[cfg(feature = "build-time-css")]
use linkme::distributed_slice;

#[cfg(feature = "build-time-css")]
#[distributed_slice]
pub static CSS_BUILD_SLICES: [&'static str; _];

macro_rules! css_stylesheet {
    ($($selector:ident : { $($prop:ident: $val:literal),* },)*) => {
        // 生成样式的字符串表示,供build script读取
        #[cfg(feature = "build-time-css")]
        #[linkme::distributed_slice(CSS_BUILD_SLICES)]
        static _CSS_ENTRY: &'static str = concat!(
            $(stringify!($selector), " { ", $(stringify!($prop), ": ", $val, "; "),* " }\n"),*
        );
    };
}

2. Build Script收集并写入文件

在build.rs中读取元数据,合并后写入CSS文件:

use linkme::distributed_slice;

#[distributed_slice]
extern "Rust" static CSS_BUILD_SLICES: [&'static str; _];

fn main() {
    let css_content = CSS_BUILD_SLICES.iter().map(|s| *s).collect::<String>();
    std::fs::write("target/debug/generated.css", css_content).unwrap();
    
    // 告知rustc文件变化时重新编译
    println!("cargo:rerun-if-changed=src/**/*.rs");
}

在Cargo.toml中启用build script和对应feature:

[package]
build = "build.rs"

[features]
build-time-css = []

三、替代方案参考

如果不想自行实现,可以参考现有成熟库的思路:

  • yew的css!宏:通过proc-macro配合静态变量实现编译时样式处理与聚合,支持内联或独立CSS输出。
  • leptos的style!宏:内置编译时CSS语法检查,通过静态数据注入实现全局样式管理。

内容的提问来源于stack exchange,提问作者max-wickham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 03:12:08