Skip to content

Commit 7f04a64

Browse files
committed
Auto merge of #56005 - GuillaumeGomez:speedup-doc-render, r=QuietMisdreavus
Greatly improve rustdoc rendering speed issues Fixes #55900. So a few improvements here: * we're switching to `DOMTokenList` API when available providing a replacement if it isn't (should only happen on safari and IE I think...) * hide doc sections by default to allow the whole HTML generation to happen in the background to avoid triggering DOM redraw all the times (which killed the performances) r? @QuietMisdreavus
2 parents 91857a3 + b8c1726 commit 7f04a64

File tree

7 files changed

+688
-612
lines changed

7 files changed

+688
-612
lines changed

src/librustdoc/html/layout.rs

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
5454
<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}light{suffix}.css\" \
5555
id=\"themeStyle\">\
5656
<script src=\"{root_path}storage{suffix}.js\"></script>\
57+
<noscript><link rel=\"stylesheet\" href=\"{root_path}noscript{suffix}.css\"></noscript>\
5758
{css_extension}\
5859
{favicon}\
5960
{in_header}\

src/librustdoc/html/render.rs

+47-57
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,9 @@ fn write_shared(
772772
write_minify(cx.dst.join(&format!("settings{}.css", cx.shared.resource_suffix)),
773773
static_files::SETTINGS_CSS,
774774
options.enable_minification)?;
775+
write_minify(cx.dst.join(&format!("noscript{}.css", cx.shared.resource_suffix)),
776+
static_files::NOSCRIPT_CSS,
777+
options.enable_minification)?;
775778

776779
// To avoid "light.css" to be overwritten, we'll first run over the received themes and only
777780
// then we'll run over the "official" styles.
@@ -865,9 +868,8 @@ themePicker.onblur = handleThemeButtonsBlur;
865868
}
866869

867870
{
868-
let mut data = format!("var resourcesSuffix = \"{}\";\n",
869-
cx.shared.resource_suffix);
870-
data.push_str(static_files::STORAGE_JS);
871+
let mut data = static_files::STORAGE_JS.to_owned();
872+
data.push_str(&format!("var resourcesSuffix = \"{}\";", cx.shared.resource_suffix));
871873
write_minify(cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)),
872874
&data,
873875
options.enable_minification)?;
@@ -3013,6 +3015,22 @@ fn item_trait(
30133015
// Trait documentation
30143016
document(w, cx, it)?;
30153017

3018+
fn write_small_section_header(
3019+
w: &mut fmt::Formatter,
3020+
id: &str,
3021+
title: &str,
3022+
extra_content: &str,
3023+
) -> fmt::Result {
3024+
write!(w, "
3025+
<h2 id='{0}' class='small-section-header'>\
3026+
{1}<a href='#{0}' class='anchor'></a>\
3027+
</h2>{2}", id, title, extra_content)
3028+
}
3029+
3030+
fn write_loading_content(w: &mut fmt::Formatter, extra_content: &str) -> fmt::Result {
3031+
write!(w, "{}<span class='loading-content'>Loading content...</span>", extra_content)
3032+
}
3033+
30163034
fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::Item)
30173035
-> fmt::Result {
30183036
let name = m.name.as_ref().unwrap();
@@ -3033,74 +3051,45 @@ fn item_trait(
30333051
}
30343052

30353053
if !types.is_empty() {
3036-
write!(w, "
3037-
<h2 id='associated-types' class='small-section-header'>
3038-
Associated Types<a href='#associated-types' class='anchor'></a>
3039-
</h2>
3040-
<div class='methods'>
3041-
")?;
3054+
write_small_section_header(w, "associated-types", "Associated Types",
3055+
"<div class='methods'>")?;
30423056
for t in &types {
30433057
trait_item(w, cx, *t, it)?;
30443058
}
3045-
write!(w, "</div>")?;
3059+
write_loading_content(w, "</div>")?;
30463060
}
30473061

30483062
if !consts.is_empty() {
3049-
write!(w, "
3050-
<h2 id='associated-const' class='small-section-header'>
3051-
Associated Constants<a href='#associated-const' class='anchor'></a>
3052-
</h2>
3053-
<div class='methods'>
3054-
")?;
3063+
write_small_section_header(w, "associated-const", "Associated Constants",
3064+
"<div class='methods'>")?;
30553065
for t in &consts {
30563066
trait_item(w, cx, *t, it)?;
30573067
}
3058-
write!(w, "</div>")?;
3068+
write_loading_content(w, "</div>")?;
30593069
}
30603070

30613071
// Output the documentation for each function individually
30623072
if !required.is_empty() {
3063-
write!(w, "
3064-
<h2 id='required-methods' class='small-section-header'>
3065-
Required Methods<a href='#required-methods' class='anchor'></a>
3066-
</h2>
3067-
<div class='methods'>
3068-
")?;
3073+
write_small_section_header(w, "required-methods", "Required methods",
3074+
"<div class='methods'>")?;
30693075
for m in &required {
30703076
trait_item(w, cx, *m, it)?;
30713077
}
3072-
write!(w, "</div>")?;
3078+
write_loading_content(w, "</div>")?;
30733079
}
30743080
if !provided.is_empty() {
3075-
write!(w, "
3076-
<h2 id='provided-methods' class='small-section-header'>
3077-
Provided Methods<a href='#provided-methods' class='anchor'></a>
3078-
</h2>
3079-
<div class='methods'>
3080-
")?;
3081+
write_small_section_header(w, "provided-methods", "Provided methods",
3082+
"<div class='methods'>")?;
30813083
for m in &provided {
30823084
trait_item(w, cx, *m, it)?;
30833085
}
3084-
write!(w, "</div>")?;
3086+
write_loading_content(w, "</div>")?;
30853087
}
30863088

30873089
// If there are methods directly on this trait object, render them here.
30883090
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)?;
30893091

30903092
let cache = cache();
3091-
let impl_header = "\
3092-
<h2 id='implementors' class='small-section-header'>\
3093-
Implementors<a href='#implementors' class='anchor'></a>\
3094-
</h2>\
3095-
<div class='item-list' id='implementors-list'>\
3096-
";
3097-
3098-
let synthetic_impl_header = "\
3099-
<h2 id='synthetic-implementors' class='small-section-header'>\
3100-
Auto implementors<a href='#synthetic-implementors' class='anchor'></a>\
3101-
</h2>\
3102-
<div class='item-list' id='synthetic-implementors-list'>\
3103-
";
31043093

31053094
let mut synthetic_types = Vec::new();
31063095

@@ -3137,11 +3126,7 @@ fn item_trait(
31373126
concrete.sort_by(compare_impl);
31383127

31393128
if !foreign.is_empty() {
3140-
write!(w, "
3141-
<h2 id='foreign-impls' class='small-section-header'>
3142-
Implementations on Foreign Types<a href='#foreign-impls' class='anchor'></a>
3143-
</h2>
3144-
")?;
3129+
write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "")?;
31453130

31463131
for implementor in foreign {
31473132
let assoc_link = AssocItemLink::GotoSource(
@@ -3152,33 +3137,38 @@ fn item_trait(
31523137
RenderMode::Normal, implementor.impl_item.stable_since(), false,
31533138
None)?;
31543139
}
3140+
write_loading_content(w, "")?;
31553141
}
31563142

3157-
write!(w, "{}", impl_header)?;
3143+
write_small_section_header(w, "implementors", "Implementors",
3144+
"<div class='item-list' id='implementors-list'>")?;
31583145
for implementor in concrete {
31593146
render_implementor(cx, implementor, w, &implementor_dups)?;
31603147
}
3161-
write!(w, "</div>")?;
3148+
write_loading_content(w, "</div>")?;
31623149

31633150
if t.auto {
3164-
write!(w, "{}", synthetic_impl_header)?;
3151+
write_small_section_header(w, "synthetic-implementors", "Auto implementors",
3152+
"<div class='item-list' id='synthetic-implementors-list'>")?;
31653153
for implementor in synthetic {
31663154
synthetic_types.extend(
31673155
collect_paths_for_type(implementor.inner_impl().for_.clone())
31683156
);
31693157
render_implementor(cx, implementor, w, &implementor_dups)?;
31703158
}
3171-
write!(w, "</div>")?;
3159+
write_loading_content(w, "</div>")?;
31723160
}
31733161
} else {
31743162
// even without any implementations to write in, we still want the heading and list, so the
31753163
// implementors javascript file pulled in below has somewhere to write the impls into
3176-
write!(w, "{}", impl_header)?;
3177-
write!(w, "</div>")?;
3164+
write_small_section_header(w, "implementors", "Implementors",
3165+
"<div class='item-list' id='implementors-list'>")?;
3166+
write_loading_content(w, "</div>")?;
31783167

31793168
if t.auto {
3180-
write!(w, "{}", synthetic_impl_header)?;
3181-
write!(w, "</div>")?;
3169+
write_small_section_header(w, "synthetic-implementors", "Auto implementors",
3170+
"<div class='item-list' id='synthetic-implementors-list'>")?;
3171+
write_loading_content(w, "</div>")?;
31823172
}
31833173
}
31843174
write!(w, r#"<script type="text/javascript">window.inlined_types=new Set({});</script>"#,

0 commit comments

Comments
 (0)