Skip to content

Commit e73aead

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.
1 parent 2cf0061 commit e73aead

File tree

8 files changed

+554
-13
lines changed

8 files changed

+554
-13
lines changed

components/config/src/config/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ pub struct SerializedConfig<'a> {
111111
markdown: &'a markup::Markdown,
112112
}
113113

114+
#[derive(Serialize)]
115+
pub struct SassConfig<'a> {
116+
base_url: &'a str,
117+
theme: &'a Option<String>,
118+
extra: &'a HashMap<String, Toml>,
119+
}
120+
114121
impl Config {
115122
// any extra syntax and highlight themes have been loaded and validated already by the from_file method before parsing the config
116123
/// Parses a string containing TOML to our Config struct
@@ -333,6 +340,14 @@ impl Config {
333340
markdown: &self.markdown,
334341
}
335342
}
343+
344+
pub fn sass_config(&self) -> SassConfig {
345+
SassConfig {
346+
base_url: &self.base_url,
347+
theme: &self.theme,
348+
extra: &self.extra,
349+
}
350+
}
336351
}
337352

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

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: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
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, Result, Context};
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 = Options::default()
24+
.style(OutputStyle::Compressed)
25+
.load_path(dependencies_dir.path());
2226
let files = get_non_partial_scss(&sass_path);
2327
let mut compiled_paths = Vec::new();
2428

@@ -52,6 +56,28 @@ pub fn compile_sass(base_path: &Path, output_path: &Path) -> Result<()> {
5256
Ok(())
5357
}
5458

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

0 commit comments

Comments
 (0)