Skip to content

Commit 86532cd

Browse files
committed
inject site config during Sass compilation
it is helpful to be able to use site config during Sass compilation, for example to allow a site owner to set header color in a Sass template. in this change we serialize a subset of the site's config to a `.scss` file as a Sass map literal, allowing config content to be referenced in site Sass or theme Sass. this commit involves bumping the `grass` dependency to version `1.13.0`. we do this so that we can use nested map retrieval in Sass files, such as `map.get($config, extra, background_color)`.
1 parent 961d07d commit 86532cd

File tree

11 files changed

+563
-18
lines changed

11 files changed

+563
-18
lines changed

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/config/src/config/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,13 @@ pub struct SerializedConfig<'a> {
112112
search: search::SerializedSearch<'a>,
113113
}
114114

115+
#[derive(Serialize)]
116+
pub struct SassConfig<'a> {
117+
base_url: &'a str,
118+
theme: &'a Option<String>,
119+
extra: &'a HashMap<String, Toml>,
120+
}
121+
115122
impl Config {
116123
// any extra syntax and highlight themes have been loaded and validated already by the from_file method before parsing the config
117124
/// Parses a string containing TOML to our Config struct
@@ -335,6 +342,10 @@ impl Config {
335342
search: self.search.serialize(),
336343
}
337344
}
345+
346+
pub fn sass_config(&self) -> SassConfig {
347+
SassConfig { base_url: &self.base_url, theme: &self.theme, extra: &self.extra }
348+
}
338349
}
339350

340351
// merge TOML data that can be a table, or anything else

components/libs/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ rayon = "1"
2727
regex = "1"
2828
relative-path = "1"
2929
reqwest = { version = "0.11", default-features = false, features = ["blocking"] }
30-
grass = {version = "0.12.1", default-features = false, features = ["random"]}
30+
grass = {version = "0.13.0", default-features = false, features = ["random"]}
3131
serde_json = "1"
3232
serde_yaml = "0.9"
3333
sha2 = "0.10"

components/site/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ include = ["src/**/*"]
77

88
[dependencies]
99
serde = { version = "1.0", features = ["derive"] }
10+
tempfile = "3"
1011

1112
errors = { path = "../errors" }
1213
config = { path = "../config" }
@@ -20,5 +21,4 @@ libs = { path = "../libs" }
2021
content = { path = "../content" }
2122

2223
[dev-dependencies]
23-
tempfile = "3"
2424
path-slash = "0.2"

components/site/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -708,13 +708,13 @@ impl Site {
708708
if let Some(ref theme) = self.config.theme {
709709
let theme_path = self.base_path.join("themes").join(theme);
710710
if theme_path.join("sass").exists() {
711-
sass::compile_sass(&theme_path, &self.output_path)?;
711+
sass::compile_sass(&theme_path, &self.output_path, &self.config)?;
712712
start = log_time(start, "Compiled theme Sass");
713713
}
714714
}
715715

716716
if self.config.compile_sass {
717-
sass::compile_sass(&self.base_path, &self.output_path)?;
717+
sass::compile_sass(&self.base_path, &self.output_path, &self.config)?;
718718
start = log_time(start, "Compiled own Sass");
719719
}
720720

components/site/src/sass/mod.rs

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
11
use std::fs::create_dir_all;
22
use std::path::{Path, PathBuf};
33

4+
use config::Config;
45
use libs::globset::Glob;
56
use libs::grass::{from_path as compile_file, Options, OutputStyle};
67
use libs::walkdir::{DirEntry, WalkDir};
8+
use tempfile::{tempdir, TempDir};
79

810
use crate::anyhow;
9-
use errors::{bail, Result};
11+
use errors::{bail, Context, Result};
1012
use utils::fs::{create_file, ensure_directory_exists};
1113

12-
pub fn compile_sass(base_path: &Path, output_path: &Path) -> Result<()> {
14+
mod serde;
15+
16+
pub fn compile_sass(base_path: &Path, output_path: &Path, config: &Config) -> Result<()> {
1317
ensure_directory_exists(output_path)?;
1418

15-
let sass_path = {
16-
let mut sass_path = PathBuf::from(base_path);
17-
sass_path.push("sass");
18-
sass_path
19-
};
19+
let sass_path = PathBuf::from(base_path).join("sass");
20+
21+
let dependencies_dir = build_dependencies_dir_from_config(config)?;
2022

21-
let options = Options::default().style(OutputStyle::Compressed);
23+
let options =
24+
Options::default().style(OutputStyle::Compressed).load_path(dependencies_dir.path());
2225
let files = get_non_partial_scss(&sass_path);
2326
let mut compiled_paths = Vec::new();
2427

@@ -52,6 +55,24 @@ pub fn compile_sass(base_path: &Path, output_path: &Path) -> Result<()> {
5255
Ok(())
5356
}
5457

58+
/// write out a subset of the Zola config document to a temporary SCSS file
59+
/// as an SCSS map variable literal. this will allow parts of the site's
60+
/// config to be usable during Sass compilation. this enables theme configuration
61+
/// like allowing the site owner to change header color. this function returns
62+
/// a tempdir holding a single `.scss` file. the tempdir should then be used as
63+
/// a load directory above when compiling the site's Sass files. the tempdir
64+
/// and contained `.scss` file will be deleted on drop of the returned `TempDir`
65+
/// struct, which should happen after Sass compilation finishes.
66+
fn build_dependencies_dir_from_config(config: &Config) -> Result<TempDir> {
67+
let dir = tempdir().context("failed to create tempdir for SASS dependencies")?;
68+
69+
let config_serialized = serde::serialize_config(config)?;
70+
71+
std::fs::write(dir.path().join("zola.scss"), format!("$config: {}", config_serialized))?;
72+
73+
Ok(dir)
74+
}
75+
5576
fn is_partial_scss(entry: &DirEntry) -> bool {
5677
entry.file_name().to_str().map(|s| s.starts_with('_')).unwrap_or(false)
5778
}

0 commit comments

Comments
 (0)