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)
86            .map_err(|e| {
87                anyhow::format_err!(
88                    "Could not minify css file {} error {}",
89                    src_file.to_string_lossy(),
90                    e
91                )
92            })?
93            .to_string();
94        std::fs::write(dest_file, minified)?;
95    } else {
96        files::copy_file(src_file, dest_file)?;
97    }
98    Ok(())
99}
100
101#[cfg(feature = "html-minifier")]
102fn copy_and_minify_js(src_file: &path::Path, dest_file: &path::Path, minify: bool) -> Result<()> {
103    if minify {
104        use html_minifier::js::minify;
105        // create target directories if any exist
106        if let Some(parent) = dest_file.parent() {
107            std::fs::create_dir_all(parent)
108                .with_context(|| anyhow::format_err!("Could not create {}", parent.display()))?;
109        }
110
111        debug!(
112            "Copying and minifying `{}` to `{}`",
113            src_file.display(),
114            dest_file.display()
115        );
116        let content = std::fs::read_to_string(src_file)?;
117        let minified = minify(&content).to_string();
118        std::fs::write(dest_file, minified)?;
119    } else {
120        files::copy_file(src_file, dest_file)?;
121    }
122    Ok(())
123}
124
125#[cfg(not(feature = "html-minifier"))]
126fn copy_and_minify_css(src_file: &path::Path, dest_file: &path::Path, _minify: bool) -> Result<()> {
127    files::copy_file(src_file, dest_file)?;
128    Ok(())
129}
130
131#[cfg(not(feature = "html-minifier"))]
132fn copy_and_minify_js(src_file: &path::Path, dest_file: &path::Path, _minify: bool) -> Result<()> {
133    files::copy_file(src_file, dest_file)?;
134    Ok(())
135}