feat!: introduce SASS prelude as well. Its more convenient then making build.rs sassy macro.
This commit is contained in:
parent
e53bafd2ce
commit
dc3c3bac11
7 changed files with 88 additions and 16 deletions
13
README.md
13
README.md
|
|
@ -342,13 +342,14 @@ Full example, close to defaults:
|
||||||
|
|
||||||
[package.metadata.sabry]
|
[package.metadata.sabry]
|
||||||
css.bundle = "target/static/style.css"
|
css.bundle = "target/static/style.css"
|
||||||
css.bundle_prelude = ["assets/prelude.css"]
|
css.prelude = ["assets/prelude.css"]
|
||||||
css.scopes = "target/statis/scopes/"
|
css.scopes = "target/statis/scopes/"
|
||||||
css.minify = true
|
css.minify = true
|
||||||
|
|
||||||
sass.intermediate_dir = "target/.sabry/sass"
|
sass.intermediate_dir = "target/.sabry/sass"
|
||||||
sass.module_name_collision = "merge"
|
sass.module_name_collision = "merge"
|
||||||
sass.modules = ["assets/sass/mod1.scss"]
|
sass.modules = ["assets/sass/mod1.scss"]
|
||||||
|
sass.prelude = ["assets/sass/prelude.scss"]
|
||||||
sass.scanroot = "src"
|
sass.scanroot = "src"
|
||||||
|
|
||||||
hash.size = 6
|
hash.size = 6
|
||||||
|
|
@ -366,11 +367,11 @@ ie = "6"
|
||||||
|
|
||||||
### `sabry.css`
|
### `sabry.css`
|
||||||
|
|
||||||
**bundle** *(no default)* - file path ro write CSS bundle into relative to project root
|
**bundle** *(no default)* - file path ro write CSS bundle into, relative to crate root
|
||||||
|
|
||||||
**bundle_prelude** *(no default)* - collection of CSS files, relative to the project root, which content will be inserted before the compiled style into the *bundle* file if any
|
**prelude** *(no default)* - collection of CSS files, relative to the crate root, which content will be inserted before the compiled style into the *bundle* file if any. Does not affect generated CSS scopes if any.
|
||||||
|
|
||||||
**scopes** *(no default)* - dir path to put separate CSS for every scope into relative to project root
|
**scopes** *(no default)* - dir path to put separate CSS for every scope into, relative to crate root
|
||||||
|
|
||||||
**minify** *(default true)* - print compressed CSS output and do the lightningcss thing
|
**minify** *(default true)* - print compressed CSS output and do the lightningcss thing
|
||||||
|
|
||||||
|
|
@ -380,7 +381,9 @@ ie = "6"
|
||||||
|
|
||||||
**scanroot** *(default "src")* - root directory to start scanning "rs" files from. Used in build function
|
**scanroot** *(default "src")* - root directory to start scanning "rs" files from. Used in build function
|
||||||
|
|
||||||
**modules** *(no default)* - collection of SASS/SCSS files, relative to the project root, which should be available as modules as well
|
**modules** *(no default)* - collection of SASS/SCSS files, relative to the crate root, which should be available as modules as well
|
||||||
|
|
||||||
|
**prelude** *(no default)* - collection of SASS/SCSS files, relative to the crate root, which content will be compiled into CSS and then inserted into the CSS *bundle* if any. Does not affect generated CSS scopes if any.
|
||||||
|
|
||||||
**module_name_collision** *(default "merge")* - how to handle similary named modules.
|
**module_name_collision** *(default "merge")* - how to handle similary named modules.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,8 @@ ssr = [
|
||||||
css.minify = true
|
css.minify = true
|
||||||
# We'll use bundle for leptos
|
# We'll use bundle for leptos
|
||||||
css.bundle = "target/.sabry/target/bundle.css"
|
css.bundle = "target/.sabry/target/bundle.css"
|
||||||
|
css.prelude = ["styles/prelude.css"]
|
||||||
|
sass.prelude = ["styles/app.scss"]
|
||||||
|
|
||||||
[package.metadata.leptos]
|
[package.metadata.leptos]
|
||||||
# Sabry-specific quality of life config
|
# Sabry-specific quality of life config
|
||||||
|
|
|
||||||
5
examples/leptos-axum/styles/app.scss
Normal file
5
examples/leptos-axum/styles/app.scss
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
@use 'theme';
|
||||||
|
|
||||||
|
html {
|
||||||
|
@include theme.surface(primary);
|
||||||
|
}
|
||||||
4
examples/leptos-axum/styles/prelude.css
Normal file
4
examples/leptos-axum/styles/prelude.css
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
@ -13,7 +13,7 @@ use sabry_intrnl::{
|
||||||
config::{manifest::ManifestError, BehavHashCollision, BehavSassModCollision, SabryConfig},
|
config::{manifest::ManifestError, BehavHashCollision, BehavSassModCollision, SabryConfig},
|
||||||
scoper::{hash::ScopeHash, ArbitraryScope, ScopeError},
|
scoper::{hash::ScopeHash, ArbitraryScope, ScopeError},
|
||||||
};
|
};
|
||||||
use sabry_procmacro_impl::impls::styly;
|
use sabry_procmacro_impl::impls::{styly, ArbitraryStyleSyntax};
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::filevisit::{self, FileVisitError};
|
use crate::filevisit::{self, FileVisitError};
|
||||||
|
|
@ -164,6 +164,7 @@ impl SabryBuilder {
|
||||||
println!("🧙 sabry didn't load any usable styles");
|
println!("🧙 sabry didn't load any usable styles");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// compile styly! macro parsed styles
|
||||||
for styly in &self.state.loaded_stylyses {
|
for styly in &self.state.loaded_stylyses {
|
||||||
let scope = ArbitraryScope::from_source(
|
let scope = ArbitraryScope::from_source(
|
||||||
styly.syntax.into(),
|
styly.syntax.into(),
|
||||||
|
|
@ -193,6 +194,12 @@ impl SabryBuilder {
|
||||||
.push((scope.original_scope.name.to_string(), css));
|
.push((scope.original_scope.name.to_string(), css));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// compile sass preludes into the CSS prelude
|
||||||
|
for pre in &self.state.sass_prelude {
|
||||||
|
let css = self.css_compiler.compile_module(pre.syntax.into(), &pre.code)?;
|
||||||
|
self.state.css_prelude.push_str(&css);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,12 +237,12 @@ impl SabryBuilder {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load up configured preludes as side modules
|
/// Load up configured preludes and side modules
|
||||||
pub fn load_preludes(&mut self) -> BuilderResult {
|
pub fn load_preludes(&mut self) -> BuilderResult {
|
||||||
// load sass modules from config
|
// load sass modules from config
|
||||||
let mut modules: Vec<StyleModule> = vec![];
|
let mut modules: Vec<StyleModule> = vec![];
|
||||||
if let Some(sass_pre) = &self.config.sass.modules {
|
if let Some(sass_mods) = &self.config.sass.modules {
|
||||||
for pre in sass_pre {
|
for pre in sass_mods {
|
||||||
let pre_path = PathBuf::from_str(pre)?;
|
let pre_path = PathBuf::from_str(pre)?;
|
||||||
let pre_name = pre_path
|
let pre_name = pre_path
|
||||||
.file_name()
|
.file_name()
|
||||||
|
|
@ -250,8 +257,26 @@ impl SabryBuilder {
|
||||||
self.load_side_module(name, code)?;
|
self.load_side_module(name, code)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load SASS preludes
|
||||||
|
if let Some(sass_pres) = &self.config.sass.prelude {
|
||||||
|
let mut sass_preludes: Vec<SassPreludeModule> = vec![];
|
||||||
|
for pre in sass_pres {
|
||||||
|
let pre_path = PathBuf::from_str(pre)?;
|
||||||
|
|
||||||
|
let syntax = pre_path.extension().unwrap_or_default().to_str().unwrap_or_default();
|
||||||
|
let syntax = match ArbitraryStyleSyntax::try_from(syntax) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => return Err(SabryBuildError::Another(format!("Unknown syntax for sass prelude {pre}")))
|
||||||
|
};
|
||||||
|
|
||||||
|
let code = fs::read_to_string(pre_path)?;
|
||||||
|
sass_preludes.push(SassPreludeModule {syntax, code});
|
||||||
|
}
|
||||||
|
self.state.sass_prelude.extend(sass_preludes);
|
||||||
|
}
|
||||||
|
|
||||||
// load css preludes
|
// load css preludes
|
||||||
if let Some(css_pre) = &self.config.css.bundle_prelude {
|
if let Some(css_pre) = &self.config.css.prelude {
|
||||||
for pre in css_pre {
|
for pre in css_pre {
|
||||||
let code = fs::read_to_string(pre)?;
|
let code = fs::read_to_string(pre)?;
|
||||||
self.state.css_prelude.push_str(&code);
|
self.state.css_prelude.push_str(&code);
|
||||||
|
|
@ -309,11 +334,30 @@ impl SabryBuilder {
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct SabryBuildState {
|
pub struct SabryBuildState {
|
||||||
|
/// HashSet of scope hashes known by builder
|
||||||
|
/// Used to determine hash collision
|
||||||
known_scope_hashes: HashSet<ScopeHash>,
|
known_scope_hashes: HashSet<ScopeHash>,
|
||||||
|
/// HashSet of module names known by builder
|
||||||
|
/// Used to determine module name collision
|
||||||
known_side_modules: HashSet<ModuleName>,
|
known_side_modules: HashSet<ModuleName>,
|
||||||
|
/// styly! macro uses, parsed
|
||||||
loaded_stylyses: Vec<styly::MacroSyntax>,
|
loaded_stylyses: Vec<styly::MacroSyntax>,
|
||||||
|
/// CSS modules to form bundle/write separately
|
||||||
loaded_css_modules: Vec<StyleModule>,
|
loaded_css_modules: Vec<StyleModule>,
|
||||||
|
/// CSS prelude to write into bundle
|
||||||
|
/// Lives separately from [loaded_css_modules] to avoid name collision
|
||||||
css_prelude: String,
|
css_prelude: String,
|
||||||
|
/// SASS preludes loaded from config
|
||||||
|
/// Should be compiled into loaded_css_modules as well
|
||||||
|
sass_prelude: Vec<SassPreludeModule>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience struct for [SabryBuildState::sass_prelude]
|
||||||
|
pub struct SassPreludeModule {
|
||||||
|
/// syntax for the prelude
|
||||||
|
syntax: ArbitraryStyleSyntax,
|
||||||
|
/// code of the prelude
|
||||||
|
code: String
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
|
@ -342,4 +386,6 @@ pub enum SabryBuildError {
|
||||||
CssCompile(#[from] SabryCompilerError),
|
CssCompile(#[from] SabryCompilerError),
|
||||||
#[error("Failed to load config/manifest")]
|
#[error("Failed to load config/manifest")]
|
||||||
Manifest(#[from] ManifestError),
|
Manifest(#[from] ManifestError),
|
||||||
|
#[error("Another error")]
|
||||||
|
Another(String)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ impl From<&ValuableManifest> for SabryConfig {
|
||||||
pub struct SabryCssConfig {
|
pub struct SabryCssConfig {
|
||||||
pub bundle: Option<String>,
|
pub bundle: Option<String>,
|
||||||
pub scopes: Option<String>,
|
pub scopes: Option<String>,
|
||||||
pub bundle_prelude: Option<Vec<String>>,
|
pub prelude: Option<Vec<String>>,
|
||||||
#[serde(default = "SabryCssConfig::default_minify")]
|
#[serde(default = "SabryCssConfig::default_minify")]
|
||||||
pub minify: bool,
|
pub minify: bool,
|
||||||
}
|
}
|
||||||
|
|
@ -57,7 +57,7 @@ impl Default for SabryCssConfig {
|
||||||
Self {
|
Self {
|
||||||
bundle: None,
|
bundle: None,
|
||||||
scopes: None,
|
scopes: None,
|
||||||
bundle_prelude: None,
|
prelude: None,
|
||||||
minify: Self::default_minify(),
|
minify: Self::default_minify(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -71,6 +71,7 @@ pub struct SabrySassConfig {
|
||||||
#[serde(default = "SabrySassConfig::default_scanroot")]
|
#[serde(default = "SabrySassConfig::default_scanroot")]
|
||||||
pub scanroot: String,
|
pub scanroot: String,
|
||||||
pub modules: Option<Vec<String>>,
|
pub modules: Option<Vec<String>>,
|
||||||
|
pub prelude: Option<Vec<String>>,
|
||||||
#[serde(default = "SabrySassConfig::default_intermediate_dir")]
|
#[serde(default = "SabrySassConfig::default_intermediate_dir")]
|
||||||
pub intermediate_dir: String,
|
pub intermediate_dir: String,
|
||||||
#[serde(default = "SabrySassConfig::default_module_name_collision")]
|
#[serde(default = "SabrySassConfig::default_module_name_collision")]
|
||||||
|
|
@ -94,6 +95,7 @@ impl Default for SabrySassConfig {
|
||||||
Self {
|
Self {
|
||||||
scanroot: Self::default_scanroot(),
|
scanroot: Self::default_scanroot(),
|
||||||
modules: None,
|
modules: None,
|
||||||
|
prelude: None,
|
||||||
intermediate_dir: Self::default_intermediate_dir(),
|
intermediate_dir: Self::default_intermediate_dir(),
|
||||||
module_name_collision: Self::default_module_name_collision(),
|
module_name_collision: Self::default_module_name_collision(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,17 @@ impl ToTokens for ArbitraryStyleSyntax {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for ArbitraryStyleSyntax {
|
||||||
|
type Error = ();
|
||||||
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
"sass" => Ok(Self::Sass),
|
||||||
|
"scss" => Ok(Self::Scss),
|
||||||
|
_ => Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Parse for ArbitraryStyleSyntax {
|
impl Parse for ArbitraryStyleSyntax {
|
||||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||||
match input.parse::<Token![:]>() {
|
match input.parse::<Token![:]>() {
|
||||||
|
|
@ -128,10 +139,9 @@ impl Parse for ArbitraryStyleSyntax {
|
||||||
}
|
}
|
||||||
let ident = input.parse::<Ident>()?;
|
let ident = input.parse::<Ident>()?;
|
||||||
|
|
||||||
match ident.to_string().as_str() {
|
match Self::try_from(ident.to_string().as_str()) {
|
||||||
"sass" => Ok(Self::Sass),
|
Ok(v) => Ok(v),
|
||||||
"scss" => Ok(Self::Scss),
|
Err(_) => Err(syn::Error::new(
|
||||||
_ => Err(syn::Error::new(
|
|
||||||
ident.span(),
|
ident.span(),
|
||||||
format!(
|
format!(
|
||||||
"Available syntax are `sass` and `scss`, omit to use default {:?} syntax",
|
"Available syntax are `sass` and `scss`, omit to use default {:?} syntax",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue