sass_rocket_fairing/
lib.rs1mod context;
2
3use rocket::{
4 fairing::{Fairing, Info, Kind},
5 log::PaintExt,
6 yansi::Paint,
7 Build, Orbit, Rocket,
8};
9
10use std::path::PathBuf;
11
12pub use context::{Context, ContextManager};
15pub use rsass;
16
17const DEFAULT_SASS_DIR: &str = "static/sass";
18const DEFAULT_CSS_DIR: &str = "static/css";
19
20pub fn compile_file(path_buf: PathBuf, format: rsass::output::Format) -> Result<String, String> {
23 match rsass::compile_scss_path(path_buf.as_path(), format) {
24 Ok(res) => Ok(String::from_utf8(res).unwrap()),
25 Err(e) => Err(e.to_string()),
26 }
27}
28
29pub struct SassFairing {
31 rsass_format: rsass::output::Format,
32}
33
34impl SassFairing {
35 pub fn new(format: rsass::output::Format) -> Self {
37 Self {
38 rsass_format: format,
39 }
40 }
41}
42
43impl Default for SassFairing {
44 fn default() -> Self {
45 Self {
46 rsass_format: rsass::output::Format::default(),
47 }
48 }
49}
50
51#[rocket::async_trait]
52impl Fairing for SassFairing {
53 fn info(&self) -> Info {
54 let kind = Kind::Ignite | Kind::Liftoff | Kind::Singleton;
55
56 #[cfg(debug_assertions)]
58 let kind = kind | Kind::Request;
59
60 Info {
61 name: "Sass Compiler",
62 kind,
63 }
64 }
65
66 async fn on_ignite(&self, rocket: Rocket<Build>) -> rocket::fairing::Result {
67 use rocket::figment::value::magic::RelativePathBuf;
68
69 let sass_dir = rocket
71 .figment()
72 .extract_inner::<RelativePathBuf>("sass_dir")
73 .map(|path| path.relative());
74
75 let sass_path = match sass_dir {
76 Ok(dir) => dir,
77 Err(e) if e.missing() => DEFAULT_SASS_DIR.into(),
78 Err(e) => {
79 rocket::config::pretty_print_error(e);
80 return Err(rocket);
81 }
82 };
83
84 let css_dir = rocket
86 .figment()
87 .extract_inner::<RelativePathBuf>("css_dir")
88 .map(|path| path.relative());
89
90 let css_path = match css_dir {
91 Ok(dir) => dir,
92 Err(e) if e.missing() => DEFAULT_CSS_DIR.into(),
93 Err(e) => {
94 rocket::config::pretty_print_error(e);
95 return Err(rocket);
96 }
97 };
98
99 if let Some(ctx) = Context::initialize(&sass_path, &css_path, self.rsass_format) {
100 Ok(rocket.manage(ContextManager::new(ctx)))
101 } else {
102 rocket::error!("Sass Initialization failed. Aborting launch.");
103 Err(rocket)
104 }
105 }
106
107 async fn on_liftoff(&self, rocket: &Rocket<Orbit>) {
108 let ctx_manager = rocket
109 .state::<ContextManager>()
110 .expect("Sass Context not registered in on_ignite");
111
112 let context = &*ctx_manager.context();
113
114 let sass_dir = context
115 .sass_dir
116 .strip_prefix(std::env::current_dir().unwrap())
117 .unwrap();
118 let css_dir = context
119 .css_dir
120 .strip_prefix(std::env::current_dir().unwrap())
121 .unwrap();
122
123 rocket::info!("{}{}:", Paint::emoji("✨ "), Paint::magenta("Sass"));
124 rocket::info_!("sass directory: {}", Paint::white(sass_dir.display()));
125 rocket::info_!("css directory: {}", Paint::white(css_dir.display()));
126
127 if cfg!(debug_assertions) {
129 rocket::info_!("pre-compiling sass files");
130 ctx_manager.compile_all_and_write();
131 }
132 }
133
134 #[cfg(debug_assertions)]
137 async fn on_request(&self, req: &mut rocket::Request<'_>, _data: &mut rocket::Data<'_>) {
138 let context_manager = req
139 .rocket()
140 .state::<ContextManager>()
141 .expect("Sass ContextManager not registered in on_ignite");
142
143 context_manager.reload_if_needed();
144 }
145}