diff --git a/build.rs b/build.rs index 6dbd4bdb7..9a9fc9114 100644 --- a/build.rs +++ b/build.rs @@ -15,6 +15,7 @@ fn main() { ); // Don't rerun anytime a single change is made + println!("cargo:rerun-if-changed=templates/style/vendored.scss"); println!("cargo:rerun-if-changed=templates/style/base.scss"); println!("cargo:rerun-if-changed=templates/style/_rustdoc.scss"); println!("cargo:rerun-if-changed=templates/style/_vars.scss"); @@ -57,30 +58,54 @@ fn get_git_hash() -> Option { }) } -fn compile_sass() -> Result<(), Box> { +fn compile_sass_file( + name: &str, + target: &str, + include_paths: &[String], +) -> Result<(), Box> { use sass_rs::{Context, Options, OutputStyle}; const STYLE_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/templates/style"); - let mut context = Context::new_file(format!("{}/base.scss", STYLE_DIR))?; + let include_paths = { + let mut paths = vec![STYLE_DIR.to_owned()]; + paths.extend_from_slice(include_paths); + paths + }; + + // Compile base.scss + let mut context = Context::new_file(format!("{}/{}.scss", STYLE_DIR, name))?; context.set_options(Options { output_style: OutputStyle::Compressed, - include_paths: vec![ - STYLE_DIR.to_owned(), - concat!(env!("CARGO_MANIFEST_DIR"), "/vendor/fontawesome/scss").to_owned(), - concat!(env!("CARGO_MANIFEST_DIR"), "/vendor/pure-css/css").to_owned(), - ], + include_paths, ..Default::default() }); let css = context.compile()?; - let dest_path = Path::new(&env::var("OUT_DIR")?).join("style.css"); + let dest_path = Path::new(&env::var("OUT_DIR")?).join(format!("{}.css", target)); let mut file = File::create(&dest_path)?; file.write_all(css.as_bytes())?; Ok(()) } +fn compile_sass() -> Result<(), Box> { + // Compile base.scss -> style.css + compile_sass_file("base", "style", &[])?; + + // Compile vendored.scss -> vendored.css + compile_sass_file( + "vendored", + "vendored", + &[ + concat!(env!("CARGO_MANIFEST_DIR"), "/vendor/fontawesome/scss").to_owned(), + concat!(env!("CARGO_MANIFEST_DIR"), "/vendor/pure-css/css").to_owned(), + ], + )?; + + Ok(()) +} + fn copy_js() { ["menu.js", "index.js"].iter().for_each(|path| { let source_path = diff --git a/src/utils/html.rs b/src/utils/html.rs index b03ac3f2d..b8d47f158 100644 --- a/src/utils/html.rs +++ b/src/utils/html.rs @@ -19,9 +19,11 @@ pub(crate) fn rewrite_lol( let templates = templates.templates.load(); let tera_head = templates.render("rustdoc/head.html", &ctx).unwrap(); + let tera_vendored_css = templates.render("rustdoc/vendored.html", &ctx).unwrap(); let tera_body = templates.render("rustdoc/body.html", &ctx).unwrap(); let tera_rustdoc_header = templates.render("rustdoc/header.html", &ctx).unwrap(); + // Append `style.css` stylesheet after all head elements. let head_handler = |head: &mut Element| { head.append(&tera_head, ContentType::Html); @@ -62,17 +64,34 @@ pub(crate) fn rewrite_lol( Ok(()) }; - let (head_selector, body_selector) = ("head".parse().unwrap(), "body".parse().unwrap()); - let head = ( - &head_selector, - ElementContentHandlers::default().element(head_handler), - ); - let body = ( - &body_selector, - ElementContentHandlers::default().element(body_handler), + // Append `vendored.css` before the first stylesheet (rustdoc's first stylesheet is `normalize.css`). + let first_stylesheet_handler = |head: &mut Element| { + head.before(&tera_vendored_css, ContentType::Html); + + Ok(()) + }; + + let (head_selector, body_selector, first_stylesheet_selector) = ( + "head".parse().unwrap(), + "body".parse().unwrap(), + "link[type='text/css'][href*='normalize']".parse().unwrap(), ); + let element_content_handlers = vec![ + ( + &head_selector, + ElementContentHandlers::default().element(head_handler), + ), + ( + &body_selector, + ElementContentHandlers::default().element(body_handler), + ), + ( + &first_stylesheet_selector, + ElementContentHandlers::default().element(first_stylesheet_handler), + ), + ]; let settings = Settings { - element_content_handlers: vec![head, body], + element_content_handlers, memory_settings: MemorySettings { max_allowed_memory_usage, ..MemorySettings::default() diff --git a/src/web/metrics.rs b/src/web/metrics.rs index 969d854e8..3c9ec0166 100644 --- a/src/web/metrics.rs +++ b/src/web/metrics.rs @@ -132,6 +132,7 @@ mod tests { ("/robots.txt", "static resource"), ("/sitemap.xml", "static resource"), ("/-/static/style.css", "static resource"), + ("/-/static/vendored.css", "static resource"), ]; wrapper(|env| { diff --git a/src/web/statics.rs b/src/web/statics.rs index e37b915b5..5745d8261 100644 --- a/src/web/statics.rs +++ b/src/web/statics.rs @@ -10,6 +10,7 @@ use mime_guess::MimeGuess; use router::Router; use std::{ffi::OsStr, fs, path::Path}; +const VENDORED_CSS: &str = include_str!(concat!(env!("OUT_DIR"), "/vendored.css")); const STYLE_CSS: &str = include_str!(concat!(env!("OUT_DIR"), "/style.css")); const MENU_JS: &str = include_str!(concat!(env!("OUT_DIR"), "/menu.js")); const INDEX_JS: &str = include_str!(concat!(env!("OUT_DIR"), "/index.js")); @@ -20,6 +21,7 @@ pub(crate) fn static_handler(req: &mut Request) -> IronResult { let file = cexpect!(req, router.find("file")); match file { + "vendored.css" => serve_resource(VENDORED_CSS, ContentType("text/css".parse().unwrap())), "style.css" => serve_resource(STYLE_CSS, ContentType("text/css".parse().unwrap())), "index.js" => serve_resource( INDEX_JS, @@ -119,7 +121,7 @@ pub(super) fn ico_handler(req: &mut Request) -> IronResult { #[cfg(test)] mod tests { - use super::{INDEX_JS, MENU_JS, STATIC_SEARCH_PATHS, STYLE_CSS}; + use super::{INDEX_JS, MENU_JS, STATIC_SEARCH_PATHS, STYLE_CSS, VENDORED_CSS}; use crate::test::wrapper; use std::fs; @@ -141,6 +143,24 @@ mod tests { }); } + #[test] + fn vendored_css() { + wrapper(|env| { + let web = env.frontend(); + + let resp = web.get("/-/static/vendored.css").send()?; + assert!(resp.status().is_success()); + assert_eq!( + resp.headers().get("Content-Type"), + Some(&"text/css".parse().unwrap()), + ); + assert_eq!(resp.content_length().unwrap(), VENDORED_CSS.len() as u64); + assert_eq!(resp.text()?, VENDORED_CSS); + + Ok(()) + }); + } + #[test] fn index_js() { wrapper(|env| { diff --git a/templates/base.html b/templates/base.html index e313b3a4e..a8a61d433 100644 --- a/templates/base.html +++ b/templates/base.html @@ -10,6 +10,7 @@ {%- block meta -%}{%- endblock meta -%} {# Docs.rs styles #} + diff --git a/templates/rustdoc/vendored.html b/templates/rustdoc/vendored.html new file mode 100644 index 000000000..ecb163b30 --- /dev/null +++ b/templates/rustdoc/vendored.html @@ -0,0 +1,2 @@ + + diff --git a/templates/style/base.scss b/templates/style/base.scss index eaae503fa..ff48d001e 100644 --- a/templates/style/base.scss +++ b/templates/style/base.scss @@ -1,6 +1,5 @@ // FIXME: Use modules -@import "vars", "rustdoc", "utils", "navbar", "fontawesome", "regular", "solid", "brands", "pure-min", - "grids-responsive-min"; +@import "vars", "rustdoc", "utils", "navbar"; html, input, diff --git a/templates/style/vendored.scss b/templates/style/vendored.scss new file mode 100644 index 000000000..89fcf0d64 --- /dev/null +++ b/templates/style/vendored.scss @@ -0,0 +1,3 @@ +@import "fontawesome", "regular", "solid", "brands", "pure-min", + "grids-responsive-min"; +