about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-02-05 18:28:16 +0000
committerbors <bors@rust-lang.org>2025-02-05 18:28:16 +0000
commita9730c3b5f84a001c052c60c97ed0765e9ceac04 (patch)
treed8ba2797c83e8ccdbc32ddbf36fb30bf2e5ce485
parentd4bdd1ed551fed0c951eb47b4be2c79d7a02d181 (diff)
parent68646e9e5fd6731106c47696dbe04a6945996197 (diff)
downloadrust-a9730c3b5f84a001c052c60c97ed0765e9ceac04.tar.gz
rust-a9730c3b5f84a001c052c60c97ed0765e9ceac04.zip
Auto merge of #136253 - notriddle:notriddle/aot-minify, r=GuillaumeGomez
rustdoc: run css and html minifier at build instead of runtime

This way, adding a bunch of comments to the JS files won't make rustdoc slower.

Meant to address https://github.com/rust-lang/rust/pull/136161#issuecomment-2622069453
-rw-r--r--src/librustdoc/Cargo.toml1
-rw-r--r--src/librustdoc/build.rs24
-rw-r--r--src/librustdoc/config.rs4
-rw-r--r--src/librustdoc/html/render/write_shared.rs10
-rw-r--r--src/librustdoc/html/static_files.rs28
5 files changed, 35 insertions, 32 deletions
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 70749f7cb17..d9bd11267da 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -33,6 +33,7 @@ features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"]
 
 [build-dependencies]
 sha2 = "0.10.8"
+minifier = { version = "0.3.2", default-features = false }
 
 [dev-dependencies]
 expect-test = "1.4.0"
diff --git a/src/librustdoc/build.rs b/src/librustdoc/build.rs
index b4b0a8d0615..07269d5bdc2 100644
--- a/src/librustdoc/build.rs
+++ b/src/librustdoc/build.rs
@@ -1,3 +1,6 @@
+use std::str;
+
+use sha2::Digest;
 fn main() {
     // generate sha256 files
     // this avoids having to perform hashing at runtime
@@ -40,14 +43,27 @@ fn main() {
     for path in files {
         let inpath = format!("html/{path}");
         println!("cargo::rerun-if-changed={inpath}");
-        let bytes = std::fs::read(inpath).expect("static path exists");
-        use sha2::Digest;
-        let bytes = sha2::Sha256::digest(bytes);
-        let mut digest = format!("-{bytes:x}");
+        let data_bytes = std::fs::read(&inpath).expect("static path exists");
+        let hash_bytes = sha2::Sha256::digest(&data_bytes);
+        let mut digest = format!("-{hash_bytes:x}");
         digest.truncate(9);
         let outpath = std::path::PathBuf::from(format!("{out_dir}/{path}.sha256"));
         std::fs::create_dir_all(outpath.parent().expect("all file paths are in a directory"))
             .expect("should be able to write to out_dir");
         std::fs::write(&outpath, digest.as_bytes()).expect("write to out_dir");
+        let minified_path = std::path::PathBuf::from(format!("{out_dir}/{path}.min"));
+        if path.ends_with(".js") || path.ends_with(".css") {
+            let minified: String = if path.ends_with(".css") {
+                minifier::css::minify(str::from_utf8(&data_bytes).unwrap())
+                    .unwrap()
+                    .to_string()
+                    .into()
+            } else {
+                minifier::js::minify(str::from_utf8(&data_bytes).unwrap()).to_string().into()
+            };
+            std::fs::write(&minified_path, minified.as_bytes()).expect("write to out_dir");
+        } else {
+            std::fs::copy(&inpath, &minified_path).unwrap();
+        }
     }
 }
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index c6fb70eee08..fd4d9845c89 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -489,7 +489,7 @@ impl Options {
         let to_check = matches.opt_strs("check-theme");
         if !to_check.is_empty() {
             let mut content =
-                std::str::from_utf8(static_files::STATIC_FILES.rustdoc_css.bytes).unwrap();
+                std::str::from_utf8(static_files::STATIC_FILES.rustdoc_css.src_bytes).unwrap();
             if let Some((_, inside)) = content.split_once("/* Begin theme: light */") {
                 content = inside;
             }
@@ -638,7 +638,7 @@ impl Options {
         let mut themes = Vec::new();
         if matches.opt_present("theme") {
             let mut content =
-                std::str::from_utf8(static_files::STATIC_FILES.rustdoc_css.bytes).unwrap();
+                std::str::from_utf8(static_files::STATIC_FILES.rustdoc_css.src_bytes).unwrap();
             if let Some((_, inside)) = content.split_once("/* Begin theme: light */") {
                 content = inside;
             }
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index fb6f3bc2c76..57d07c05c11 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -207,14 +207,8 @@ fn write_static_files(
     if opt.emit.is_empty() || opt.emit.contains(&EmitType::Toolchain) {
         static_files::for_each(|f: &static_files::StaticFile| {
             let filename = static_dir.join(f.output_filename());
-            let contents: &[u8];
-            let contents_vec: Vec<u8>;
-            if opt.disable_minification {
-                contents = f.bytes;
-            } else {
-                contents_vec = f.minified();
-                contents = &contents_vec;
-            };
+            let contents: &[u8] =
+                if opt.disable_minification { f.src_bytes } else { f.minified_bytes };
             fs::write(&filename, contents).map_err(|e| PathError::new(e, &filename))
         })?;
     }
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index 0bcaf11da0c..45589a37069 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -8,26 +8,18 @@ use std::{fmt, str};
 
 pub(crate) struct StaticFile {
     pub(crate) filename: PathBuf,
-    pub(crate) bytes: &'static [u8],
+    pub(crate) src_bytes: &'static [u8],
+    pub(crate) minified_bytes: &'static [u8],
 }
 
 impl StaticFile {
-    fn new(filename: &str, bytes: &'static [u8], sha256: &'static str) -> StaticFile {
-        Self { filename: static_filename(filename, sha256), bytes }
-    }
-
-    pub(crate) fn minified(&self) -> Vec<u8> {
-        let extension = match self.filename.extension() {
-            Some(e) => e,
-            None => return self.bytes.to_owned(),
-        };
-        if extension == "css" {
-            minifier::css::minify(str::from_utf8(self.bytes).unwrap()).unwrap().to_string().into()
-        } else if extension == "js" {
-            minifier::js::minify(str::from_utf8(self.bytes).unwrap()).to_string().into()
-        } else {
-            self.bytes.to_owned()
-        }
+    fn new(
+        filename: &str,
+        src_bytes: &'static [u8],
+        minified_bytes: &'static [u8],
+        sha256: &'static str,
+    ) -> StaticFile {
+        Self { filename: static_filename(filename, sha256), src_bytes, minified_bytes }
     }
 
     pub(crate) fn output_filename(&self) -> &Path {
@@ -68,7 +60,7 @@ macro_rules! static_files {
 
         // sha256 files are generated in build.rs
         pub(crate) static STATIC_FILES: std::sync::LazyLock<StaticFiles> = std::sync::LazyLock::new(|| StaticFiles {
-            $($field: StaticFile::new($file_path, include_bytes!($file_path), include_str!(concat!(env!("OUT_DIR"), "/", $file_path, ".sha256"))),)+
+            $($field: StaticFile::new($file_path, include_bytes!($file_path), include_bytes!(concat!(env!("OUT_DIR"), "/", $file_path, ".min")), include_str!(concat!(env!("OUT_DIR"), "/", $file_path, ".sha256"))),)+
         });
 
         pub(crate) fn for_each<E>(f: impl Fn(&StaticFile) -> Result<(), E>) -> Result<(), E> {