cobalt/cobalt_model/
assets.rs

1use std::ffi::OsStr;
2use std::path;
3
4use anyhow::Context as _;
5use log::debug;
6use serde::{Deserialize, Serialize};
7
8use super::sass;
9use super::{Minify, files};
10
11use crate::error::Result;
12
13#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
14#[serde(deny_unknown_fields, default)]
15pub struct AssetsBuilder {
16    pub sass: sass::SassBuilder,
17    pub source: path::PathBuf,
18}
19
20impl AssetsBuilder {
21    pub fn from_config(config: cobalt_config::Assets, source: &path::Path) -> Self {
22        Self {
23            sass: sass::SassBuilder::from_config(config.sass, source),
24            source: source.to_owned(),
25        }
26    }
27
28    pub fn build(self) -> Result<Assets> {
29        let AssetsBuilder { sass, source } = self;
30
31        let sass = sass.build();
32
33        let assets = Assets { sass, source };
34        Ok(assets)
35    }
36}
37
38#[derive(Debug)]
39pub struct Assets {
40    sass: sass::SassCompiler,
41    source: path::PathBuf,
42}
43
44impl Assets {
45    pub fn process(
46        &self,
47        path: &path::Path,
48        dest_root: &path::Path,
49        minify: &Minify,
50    ) -> Result<()> {
51        let rel_src = path
52            .strip_prefix(&self.source)
53            .expect("file was found under the root");
54        let dest_path = dest_root.join(rel_src);
55        if sass::is_sass_file(path) {
56            self.sass
57                .compile_file(&self.source, dest_root, path, minify)?;
58        } else if path.extension() == Some(OsStr::new("js")) {
59            copy_and_minify_js(path, &dest_path, minify.js)?;
60        } else if path.extension() == Some(OsStr::new("css")) {
61            copy_and_minify_css(path, &dest_path, minify.css)?;
62        } else {
63            files::copy_file(path, &dest_path)?;
64        }
65        Ok(())
66    }
67}
68
69#[cfg(feature = "html-minifier")]
70fn copy_and_minify_css(src_file: &path::Path, dest_file: &path::Path, minify: bool) -> Result<()> {
71    if minify {
72        use html_minifier::css::minify;
73        // create target directories if any exist
74        if let Some(parent) = dest_file.parent() {
75            std::fs::create_dir_all(parent)
76                .with_context(|| anyhow::format_err!("Could not create {}", parent.display()))?;
77        }
78
79        debug!(
80            "Copying and minifying `{}` to `{}`",
81            src_file.display(),
82            dest_file.display()
83        );
84        let content = std::fs::read_to_string(src_file)?;
85        let minified = minify(&content).map_err(|e| {
86            anyhow::format_err!(
87                "Could not minify css file {} error {}",
88                src_file.to_string_lossy(),
89                e
90            )
91        })?;
92        std::fs::write(dest_file, minified)?;
93    } else {
94        files::copy_file(src_file, dest_file)?;
95    }
96    Ok(())
97}
98
99#[cfg(feature = "html-minifier")]
100fn copy_and_minify_js(src_file: &path::Path, dest_file: &path::Path, minify: bool) -> Result<()> {
101    if minify {
102        use html_minifier::js::minify;
103        // create target directories if any exist
104        if let Some(parent) = dest_file.parent() {
105            std::fs::create_dir_all(parent)
106                .with_context(|| anyhow::format_err!("Could not create {}", parent.display()))?;
107        }
108
109        debug!(
110            "Copying and minifying `{}` to `{}`",
111            src_file.display(),
112            dest_file.display()
113        );
114        let content = std::fs::read_to_string(src_file)?;
115        std::fs::write(dest_file, minify(&content))?;
116    } else {
117        files::copy_file(src_file, dest_file)?;
118    }
119    Ok(())
120}
121
122#[cfg(not(feature = "html-minifier"))]
123fn copy_and_minify_css(src_file: &path::Path, dest_file: &path::Path, _minify: bool) -> Result<()> {
124    files::copy_file(src_file, dest_file)?;
125    Ok(())
126}
127
128#[cfg(not(feature = "html-minifier"))]
129fn copy_and_minify_js(src_file: &path::Path, dest_file: &path::Path, _minify: bool) -> Result<()> {
130    files::copy_file(src_file, dest_file)?;
131    Ok(())
132}