#!/usr/bin/env rust-script //! This is a regular crate doc comment, but it also contains a partial //! Cargo manifest. Note the use of a *fenced* code block, and the //! `cargo` "language". //! //! ```cargo //! [dependencies] //! encre-css = "0.14" //! walkdir = "2" //! grass = { version = "0.13.4", features = ["macro", "nightly"] } //! lightningcss = { version = "1.0.0-alpha.65", features = ["bundler", "browserslist"] } //! anyhow = "1" //! async-compression = { version = "0.4", features = ["tokio", "zstd"] } //! tokio = { version = "1", features = [ "full" ] } //! ``` use std::{collections::BTreeSet, fs, path::Path}; use async_compression::tokio::write::ZstdEncoder; use encre_css::{Config, Scanner}; use lightningcss::{ bundler::{Bundler, FileProvider}, stylesheet::{ParserOptions, PrinterOptions}, targets::{Browsers, Targets}, }; use tokio::io::AsyncWriteExt as _; // for `write_all` and `shutdown` use walkdir::WalkDir; #[tokio::main] async fn main() -> anyhow::Result<()> { eprintln!("WEGL CSS 💅 © 2025=========================================="); eprintln!("look mum no js/npm"); eprintln!("Reading! Step 1/5 🚶 (Walking Dirs)"); // Walk through the directory structure let contents = WalkDir::new("./") .into_iter() .filter_map(|e| e.ok()) .filter(|e| { e.file_type().is_file() && e.path() .extension() .map_or(false, |ext| ["rs", "scss"].into_iter().any(|e| e == ext)) }) .map(|entry| { let path = entry.path(); // eprintln!("Processing file: {}", path.display()); let content = fs::read_to_string(path).expect("Failed to read"); let bx = Box::new(content); let static_ref: &'static str = Box::leak(bx); static_ref }); let config = { let mut config = Config::default(); // FIXME TODO Add moar colors config.scanner = Scanner::from_fn(|val| { let mut is_arbitrary = false; val.split(|ch| { // Escape all characters in arbitrary values prefixed by a dash (used to avoid // ignoring values in, for example, JS arrays, given that they are defined // using square brackets) match ch { '[' => { is_arbitrary = true; false } ']' => { is_arbitrary = false; false } _ => { ch == ' ' || (!is_arbitrary && ['.', '\'', '"', '`', '\n'].into_iter().any(|c| c == ch)) } } }) .collect::>() }); // config // .theme // .colors // .add("blue-500", "oklch(.623 .214 259.815)"); // config.theme.colors.add("blue", "rgb(.1, .1, .9)"); config }; eprintln!("Building Utilities Step 2/5 ⚙️ (EncrCSS)"); let generated = encre_css::generate(contents, &config); tokio::fs::write("./public/css/encr.css", &generated).await?; tokio::fs::write("./style/encr.css", &generated).await?; eprintln!("Compiling SCSS Step 3/5 🏗 (Grass Compile)"); let compiled = grass::from_path("./style/main.scss", &grass::Options::default())?; tokio::fs::write("./public/css/main.css", compiled.clone()).await?; eprintln!("Bundling & Minifying Step 4/5 ⚡️ (Lightning CSS)"); let fs: FileProvider = FileProvider::new(); let fs: &'static _ = Box::leak(Box::new(fs)); // yolo it's a script, and we need a 'static ref let mut bundler = Bundler::new(fs, None, ParserOptions::default()); let stylesheet = bundler.bundle(Path::new("./public/css/main.css"))?; // Serialize it to a string. let optimized_opts = PrinterOptions { minify: true, targets: Targets { browsers: Browsers::from_browserslist([ "> 0.5%, last 3 versions, Firefox ESR, not dead" ])?, ..Default::default() }, ..Default::default() }; let res = stylesheet.to_css(Default::default()).unwrap(); let opt_res = stylesheet.to_css(optimized_opts).unwrap(); // println!("{}", res.code); tokio::fs::write("./public/main.css", res.code.clone()).await?; tokio::fs::write("./public/main.min.css", opt_res.code).await?; eprintln!("Compressing... Step 5/5 🐁️ (Zstd)"); async fn compress(in_data: &[u8]) -> anyhow::Result> { let mut encoder = ZstdEncoder::new(Vec::new()); encoder.write_all(in_data).await?; encoder.shutdown().await?; Ok(encoder.into_inner()) } // tokio::fs::write( // "./public/main.min.css.zstd", // compress(res.code.as_bytes()).await?, // ) // .await?; eprintln!("Done ! ====================================================="); Ok(()) }