Rollup merge of #82310 - jsha:rustdoc-search-onfocus, r=GuillaumeGomez
Load rustdoc's JS search index on-demand. Instead of being loaded on every page, the JS search index is now loaded when either (a) there is a `?search=` param, or (b) the search input is focused. This saves both CPU and bandwidth. As of Feb 2021, https://doc.rust-lang.org/search-index1.50.0.js is 273,838 bytes gzipped or 2,544,939 bytes uncompressed. Evaluating it takes 445 ms of CPU time in Chrome 88 on a i7-10710U CPU (out of a total ~2,100 ms page reload). Tested on Firefox and Chrome. New: https://jacob.hoffman-andrews.com/rust/search-on-demand/std/primitive.slice.html https://jacob.hoffman-andrews.com/rust/search-on-demand/std/primitive.slice.html?search=fn Old: https://jacob.hoffman-andrews.com/rust/search-on-load/std/primitive.slice.html https://jacob.hoffman-andrews.com/rust/search-on-load/std/primitive.slice.html?search=fn
This commit is contained in:
commit
36b7bef1cb
@ -58,6 +58,7 @@ crate fn render<T: Print, S: Print>(
|
||||
{style_files}\
|
||||
<script id=\"default-settings\"{default_settings}></script>\
|
||||
<script src=\"{static_root_path}storage{suffix}.js\"></script>\
|
||||
<script src=\"{static_root_path}crates{suffix}.js\"></script>\
|
||||
<noscript><link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\"></noscript>\
|
||||
{css_extension}\
|
||||
{favicon}\
|
||||
@ -112,10 +113,10 @@ crate fn render<T: Print, S: Print>(
|
||||
<section id=\"search\" class=\"content hidden\"></section>\
|
||||
<section class=\"footer\"></section>\
|
||||
{after_content}\
|
||||
<div id=\"rustdoc-vars\" data-root-path=\"{root_path}\" data-current-crate=\"{krate}\"></div>
|
||||
<div id=\"rustdoc-vars\" data-root-path=\"{root_path}\" data-current-crate=\"{krate}\" \
|
||||
data-search-js=\"{root_path}search-index{suffix}.js\"></div>
|
||||
<script src=\"{static_root_path}main{suffix}.js\"></script>\
|
||||
{extra_scripts}\
|
||||
<script defer src=\"{root_path}search-index{suffix}.js\"></script>\
|
||||
</body>\
|
||||
</html>",
|
||||
css_extension = if layout.css_file_extension.is_some() {
|
||||
|
@ -1061,10 +1061,12 @@ themePicker.onblur = handleThemeButtonsBlur;
|
||||
cx.shared.fs.write(&dst, v.as_bytes())?;
|
||||
}
|
||||
|
||||
// Update the search index
|
||||
// Update the search index and crate list.
|
||||
let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix));
|
||||
let (mut all_indexes, mut krates) = try_err!(collect_json(&dst, &krate.name.as_str()), &dst);
|
||||
all_indexes.push(search_index);
|
||||
krates.push(krate.name.to_string());
|
||||
krates.sort();
|
||||
|
||||
// Sort the indexes by crate so the file will be generated identically even
|
||||
// with rustdoc running in parallel.
|
||||
@ -1072,11 +1074,15 @@ themePicker.onblur = handleThemeButtonsBlur;
|
||||
{
|
||||
let mut v = String::from("var searchIndex = JSON.parse('{\\\n");
|
||||
v.push_str(&all_indexes.join(",\\\n"));
|
||||
// "addSearchOptions" has to be called first so the crate filtering can be set before the
|
||||
// search might start (if it's set into the URL for example).
|
||||
v.push_str("\\\n}');\naddSearchOptions(searchIndex);initSearch(searchIndex);");
|
||||
v.push_str("\\\n}');\ninitSearch(searchIndex);");
|
||||
cx.shared.fs.write(&dst, &v)?;
|
||||
}
|
||||
|
||||
let crate_list_dst = cx.dst.join(&format!("crates{}.js", cx.shared.resource_suffix));
|
||||
let crate_list =
|
||||
format!("window.ALL_CRATES = [{}];", krates.iter().map(|k| format!("\"{}\"", k)).join(","));
|
||||
cx.shared.fs.write(&crate_list_dst, &crate_list)?;
|
||||
|
||||
if options.enable_index_page {
|
||||
if let Some(index_page) = options.index_page.clone() {
|
||||
let mut md_opts = options.clone();
|
||||
@ -1098,9 +1104,6 @@ themePicker.onblur = handleThemeButtonsBlur;
|
||||
extra_scripts: &[],
|
||||
static_extra_scripts: &[],
|
||||
};
|
||||
krates.push(krate.name.to_string());
|
||||
krates.sort();
|
||||
krates.dedup();
|
||||
|
||||
let content = format!(
|
||||
"<h1 class=\"fqn\">\
|
||||
|
@ -42,6 +42,7 @@ if (!DOMTokenList.prototype.remove) {
|
||||
if (rustdocVars) {
|
||||
window.rootPath = rustdocVars.attributes["data-root-path"].value;
|
||||
window.currentCrate = rustdocVars.attributes["data-current-crate"].value;
|
||||
window.searchJS = rustdocVars.attributes["data-search-js"].value;
|
||||
}
|
||||
var sidebarVars = document.getElementById("sidebar-vars");
|
||||
if (sidebarVars) {
|
||||
@ -1922,8 +1923,8 @@ function defocusSearchBar() {
|
||||
return searchWords;
|
||||
}
|
||||
|
||||
function startSearch() {
|
||||
var callback = function() {
|
||||
function registerSearchEvents() {
|
||||
var searchAfter500ms = function() {
|
||||
clearInputTimeout();
|
||||
if (search_input.value.length === 0) {
|
||||
if (browserSupportsHistoryApi()) {
|
||||
@ -1935,8 +1936,8 @@ function defocusSearchBar() {
|
||||
searchTimeout = setTimeout(search, 500);
|
||||
}
|
||||
};
|
||||
search_input.onkeyup = callback;
|
||||
search_input.oninput = callback;
|
||||
search_input.onkeyup = searchAfter500ms;
|
||||
search_input.oninput = searchAfter500ms;
|
||||
document.getElementsByClassName("search-form")[0].onsubmit = function(e) {
|
||||
e.preventDefault();
|
||||
clearInputTimeout();
|
||||
@ -1999,7 +2000,6 @@ function defocusSearchBar() {
|
||||
}
|
||||
});
|
||||
}
|
||||
search();
|
||||
|
||||
// This is required in firefox to avoid this problem: Navigating to a search result
|
||||
// with the keyboard, hitting enter, and then hitting back would take you back to
|
||||
@ -2017,8 +2017,14 @@ function defocusSearchBar() {
|
||||
}
|
||||
|
||||
index = buildIndex(rawSearchIndex);
|
||||
startSearch();
|
||||
registerSearchEvents();
|
||||
// If there's a search term in the URL, execute the search now.
|
||||
if (getQueryStringParams().search) {
|
||||
search();
|
||||
}
|
||||
};
|
||||
|
||||
function addSidebarCrates(crates) {
|
||||
// Draw a convenient sidebar of known crates if we have a listing
|
||||
if (window.rootPath === "../" || window.rootPath === "./") {
|
||||
var sidebar = document.getElementsByClassName("sidebar-elems")[0];
|
||||
@ -2029,14 +2035,6 @@ function defocusSearchBar() {
|
||||
var ul = document.createElement("ul");
|
||||
div.appendChild(ul);
|
||||
|
||||
var crates = [];
|
||||
for (var crate in rawSearchIndex) {
|
||||
if (!hasOwnProperty(rawSearchIndex, crate)) {
|
||||
continue;
|
||||
}
|
||||
crates.push(crate);
|
||||
}
|
||||
crates.sort();
|
||||
for (var i = 0; i < crates.length; ++i) {
|
||||
var klass = "crate";
|
||||
if (window.rootPath !== "./" && crates[i] === window.currentCrate) {
|
||||
@ -2044,9 +2042,6 @@ function defocusSearchBar() {
|
||||
}
|
||||
var link = document.createElement("a");
|
||||
link.href = window.rootPath + crates[i] + "/index.html";
|
||||
// The summary in the search index has HTML, so we need to
|
||||
// dynamically render it as plaintext.
|
||||
link.title = convertHTMLToPlaintext(rawSearchIndex[crates[i]].doc);
|
||||
link.className = klass;
|
||||
link.textContent = crates[i];
|
||||
|
||||
@ -2057,7 +2052,7 @@ function defocusSearchBar() {
|
||||
sidebar.appendChild(div);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert HTML to plaintext:
|
||||
@ -2862,37 +2857,18 @@ function defocusSearchBar() {
|
||||
}
|
||||
}
|
||||
|
||||
window.addSearchOptions = function(crates) {
|
||||
function addSearchOptions(crates) {
|
||||
var elem = document.getElementById("crate-search");
|
||||
|
||||
if (!elem) {
|
||||
enableSearchInput();
|
||||
return;
|
||||
}
|
||||
var crates_text = [];
|
||||
if (Object.keys(crates).length > 1) {
|
||||
for (var crate in crates) {
|
||||
if (hasOwnProperty(crates, crate)) {
|
||||
crates_text.push(crate);
|
||||
}
|
||||
}
|
||||
}
|
||||
crates_text.sort(function(a, b) {
|
||||
var lower_a = a.toLowerCase();
|
||||
var lower_b = b.toLowerCase();
|
||||
|
||||
if (lower_a < lower_b) {
|
||||
return -1;
|
||||
} else if (lower_a > lower_b) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
var savedCrate = getSettingValue("saved-filter-crate");
|
||||
for (var i = 0, len = crates_text.length; i < len; ++i) {
|
||||
for (var i = 0, len = crates.length; i < len; ++i) {
|
||||
var option = document.createElement("option");
|
||||
option.value = crates_text[i];
|
||||
option.innerText = crates_text[i];
|
||||
option.value = crates[i];
|
||||
option.innerText = crates[i];
|
||||
elem.appendChild(option);
|
||||
// Set the crate filter from saved storage, if the current page has the saved crate
|
||||
// filter.
|
||||
@ -2900,7 +2876,7 @@ function defocusSearchBar() {
|
||||
// If not, ignore the crate filter -- we want to support filtering for crates on sites
|
||||
// like doc.rust-lang.org where the crates may differ from page to page while on the
|
||||
// same domain.
|
||||
if (crates_text[i] === savedCrate) {
|
||||
if (crates[i] === savedCrate) {
|
||||
elem.value = savedCrate;
|
||||
}
|
||||
}
|
||||
@ -2969,6 +2945,44 @@ function defocusSearchBar() {
|
||||
buildHelperPopup = function() {};
|
||||
}
|
||||
|
||||
function loadScript(url) {
|
||||
var script = document.createElement('script');
|
||||
script.src = url;
|
||||
document.head.append(script);
|
||||
}
|
||||
|
||||
function setupSearchLoader() {
|
||||
var searchLoaded = false;
|
||||
function loadSearch() {
|
||||
if (!searchLoaded) {
|
||||
searchLoaded = true;
|
||||
loadScript(window.searchJS);
|
||||
}
|
||||
}
|
||||
|
||||
// `crates{version}.js` should always be loaded before this script, so we can use it safely.
|
||||
addSearchOptions(window.ALL_CRATES);
|
||||
addSidebarCrates(window.ALL_CRATES);
|
||||
|
||||
search_input.addEventListener("focus", function() {
|
||||
search_input.origPlaceholder = search_input.placeholder;
|
||||
search_input.placeholder = "Type your search here.";
|
||||
loadSearch();
|
||||
});
|
||||
search_input.addEventListener("blur", function() {
|
||||
search_input.placeholder = search_input.origPlaceholder;
|
||||
});
|
||||
enableSearchInput();
|
||||
|
||||
var crateSearchDropDown = document.getElementById("crate-search");
|
||||
crateSearchDropDown.addEventListener("focus", loadSearch);
|
||||
var params = getQueryStringParams();
|
||||
if (params.search !== undefined) {
|
||||
loadSearch();
|
||||
}
|
||||
}
|
||||
|
||||
onHashChange(null);
|
||||
window.onhashchange = onHashChange;
|
||||
setupSearchLoader();
|
||||
}());
|
||||
|
Loading…
x
Reference in New Issue
Block a user