Feat: Manganis SCSS Support (#3294)
* feat: scss manganis support * revision: make ScssLogger private
This commit is contained in:
1 parent
e6f76c7e75
commit
bff5478fdf
5 files changed
+133
-1
No files matched your search
Generated
+42
@@ -2385,6 +2385,12 @@ dependencies = [
|
|||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "codemap"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespan-reporting"
|
name = "codespan-reporting"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@@ -3540,7 +3546,9 @@ version = "0.6.0-rc.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"browserslist-rs",
|
"browserslist-rs",
|
||||||
|
"codemap",
|
||||||
"const-serialize",
|
"const-serialize",
|
||||||
|
"grass",
|
||||||
"image",
|
"image",
|
||||||
"imagequant",
|
"imagequant",
|
||||||
"lightningcss",
|
"lightningcss",
|
||||||
@@ -5948,6 +5956,31 @@ dependencies = [
|
|||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "grass"
|
||||||
|
version = "0.13.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7a68216437ef68f0738e48d6c7bb9e6e6a92237e001b03d838314b068f33c94"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"getrandom 0.2.15",
|
||||||
|
"grass_compiler",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "grass_compiler"
|
||||||
|
version = "0.13.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d9e3df7f0222ce5184154973d247c591d9aadc28ce7a73c6cd31100c9facff6"
|
||||||
|
dependencies = [
|
||||||
|
"codemap",
|
||||||
|
"indexmap 2.7.0",
|
||||||
|
"lasso",
|
||||||
|
"once_cell",
|
||||||
|
"phf 0.11.2",
|
||||||
|
"rand 0.8.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "group"
|
name = "group"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
@@ -7346,6 +7379,15 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lasso"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e14eda50a3494b3bf7b9ce51c52434a761e383d7238ce1dd5dcec2fbc13e9fb"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown 0.14.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy-js-bundle"
|
name = "lazy-js-bundle"
|
||||||
version = "0.6.0-rc.0"
|
version = "0.6.0-rc.0"
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ image = { version = "0.25", features = ["avif"] }
|
|||||||
# CSS Minification
|
# CSS Minification
|
||||||
lightningcss = "1.0.0-alpha.60"
|
lightningcss = "1.0.0-alpha.60"
|
||||||
|
|
||||||
|
# SCSS Processing
|
||||||
|
grass = "0.13.4"
|
||||||
|
codemap = "0.1.3"
|
||||||
|
|
||||||
# Js minification - swc has introduces minor versions with breaking changes in the past so we pin all of their crates
|
# Js minification - swc has introduces minor versions with breaking changes in the past so we pin all of their crates
|
||||||
swc = "=0.283.0"
|
swc = "=0.283.0"
|
||||||
swc_allocator = { version = "=0.1.8", default-features = false }
|
swc_allocator = { version = "=0.1.8", default-features = false }
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
use codemap::SpanLoc;
|
||||||
|
use grass::OutputStyle;
|
||||||
use lightningcss::{
|
use lightningcss::{
|
||||||
printer::PrinterOptions,
|
printer::PrinterOptions,
|
||||||
stylesheet::{MinifyOptions, ParserOptions, StyleSheet},
|
stylesheet::{MinifyOptions, ParserOptions, StyleSheet},
|
||||||
};
|
};
|
||||||
use manganis_core::CssAssetOptions;
|
use manganis_core::CssAssetOptions;
|
||||||
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
pub(crate) fn process_css(
|
pub(crate) fn process_css(
|
||||||
css_options: &CssAssetOptions,
|
css_options: &CssAssetOptions,
|
||||||
@@ -40,3 +43,57 @@ pub(crate) fn minify_css(css: &str) -> String {
|
|||||||
let res = stylesheet.to_css(printer).unwrap();
|
let res = stylesheet.to_css(printer).unwrap();
|
||||||
res.code
|
res.code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Process an scss/sass file into css.
|
||||||
|
pub(crate) fn process_scss(
|
||||||
|
scss_options: &CssAssetOptions,
|
||||||
|
source: &Path,
|
||||||
|
output_path: &Path,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let style = match scss_options.minified() {
|
||||||
|
true => OutputStyle::Compressed,
|
||||||
|
false => OutputStyle::Expanded,
|
||||||
|
};
|
||||||
|
|
||||||
|
let options = grass::Options::default()
|
||||||
|
.style(style)
|
||||||
|
.quiet(false)
|
||||||
|
.logger(&ScssLogger {});
|
||||||
|
|
||||||
|
let css = grass::from_path(source, &options)?;
|
||||||
|
let minified = minify_css(&css);
|
||||||
|
|
||||||
|
std::fs::write(output_path, minified).with_context(|| {
|
||||||
|
format!(
|
||||||
|
"Failed to write css to output location: {}",
|
||||||
|
output_path.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Logger for Grass that re-uses their StdLogger formatting but with tracing.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct ScssLogger {}
|
||||||
|
|
||||||
|
impl grass::Logger for ScssLogger {
|
||||||
|
fn debug(&self, location: SpanLoc, message: &str) {
|
||||||
|
debug!(
|
||||||
|
"{}:{} DEBUG: {}",
|
||||||
|
location.file.name(),
|
||||||
|
location.begin.line + 1,
|
||||||
|
message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn warn(&self, location: SpanLoc, message: &str) {
|
||||||
|
warn!(
|
||||||
|
"Warning: {}\n ./{}:{}:{}",
|
||||||
|
message,
|
||||||
|
location.file.name(),
|
||||||
|
location.begin.line + 1,
|
||||||
|
location.begin.column + 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@ use anyhow::Context;
|
|||||||
use manganis_core::{AssetOptions, CssAssetOptions, ImageAssetOptions, JsAssetOptions};
|
use manganis_core::{AssetOptions, CssAssetOptions, ImageAssetOptions, JsAssetOptions};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
use crate::css::process_scss;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
css::process_css, folder::process_folder, image::process_image, js::process_js,
|
css::process_css, folder::process_folder, image::process_image, js::process_js,
|
||||||
json::process_json,
|
json::process_json,
|
||||||
@@ -29,6 +31,9 @@ pub fn process_file_to(
|
|||||||
Some("css") => {
|
Some("css") => {
|
||||||
process_css(&CssAssetOptions::new(), source, output_path)?;
|
process_css(&CssAssetOptions::new(), source, output_path)?;
|
||||||
}
|
}
|
||||||
|
Some("scss" | "sass") => {
|
||||||
|
process_scss(&CssAssetOptions::new(), source, output_path)?;
|
||||||
|
}
|
||||||
Some("js") => {
|
Some("js") => {
|
||||||
process_js(&JsAssetOptions::new(), source, output_path)?;
|
process_js(&JsAssetOptions::new(), source, output_path)?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,15 @@ pub const fn generate_unique_path(
|
|||||||
None => {
|
None => {
|
||||||
if let Some(extension) = extension {
|
if let Some(extension) = extension {
|
||||||
macro_output_path = macro_output_path.push('.');
|
macro_output_path = macro_output_path.push('.');
|
||||||
macro_output_path = macro_output_path.push_str(extension.as_str())
|
|
||||||
|
let ext_bytes = extension.as_str().as_bytes();
|
||||||
|
|
||||||
|
// Rewrite scss as css
|
||||||
|
if bytes_equal(ext_bytes, b"scss") || bytes_equal(ext_bytes, b"sass") {
|
||||||
|
macro_output_path = macro_output_path.push_str("css")
|
||||||
|
} else {
|
||||||
|
macro_output_path = macro_output_path.push_str(extension.as_str())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,6 +90,22 @@ pub const fn generate_unique_path(
|
|||||||
macro_output_path
|
macro_output_path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fn bytes_equal(left: &[u8], right: &[u8]) -> bool {
|
||||||
|
if left.len() != right.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
while i < left.len() {
|
||||||
|
if left[i] != right[i] {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unique_path() {
|
fn test_unique_path() {
|
||||||
use manganis_core::{ImageAssetOptions, ImageFormat};
|
use manganis_core::{ImageAssetOptions, ImageFormat};
|
||||||
|
|||||||
Reference in new issue
Block a user