Use JSON search index with JS fallback

This allows the search index to be loaded asynchronously, and should
use fewer resources as it doesn't have to execute the JS.
JS loading is kept as a fallback for CORS issues with file:// URIs in Chrome.
This commit is contained in:
Matt Ickstadt 2018-06-13 14:51:15 -05:00
parent 62c8311301
commit e1a46d213e
2 changed files with 22 additions and 15 deletions

View File

@ -24,14 +24,15 @@ pub fn create_files(search_config: &Search, destination: &Path, book: &Book) ->
render_item(&mut index, &search_config, &mut doc_urls, item)?; render_item(&mut index, &search_config, &mut doc_urls, item)?;
} }
let index = write_to_js(index, &search_config, doc_urls)?; let index = write_to_json(index, &search_config, doc_urls)?;
debug!("Writing search index ✓"); debug!("Writing search index ✓");
if index.len() > 10_000_000 { if index.len() > 10_000_000 {
warn!("searchindex.js is very large ({} bytes)", index.len()); warn!("searchindex.json is very large ({} bytes)", index.len());
} }
if search_config.copy_js { if search_config.copy_js {
utils::fs::write_file(destination, "searchindex.js", index.as_bytes())?; utils::fs::write_file(destination, "searchindex.json", index.as_bytes())?;
utils::fs::write_file(destination, "searchindex.js", format!("window.search = {};", index).as_bytes())?;
utils::fs::write_file(destination, "searcher.js", searcher::JS)?; utils::fs::write_file(destination, "searcher.js", searcher::JS)?;
utils::fs::write_file(destination, "mark.min.js", searcher::MARK_JS)?; utils::fs::write_file(destination, "mark.min.js", searcher::MARK_JS)?;
utils::fs::write_file(destination, "elasticlunr.min.js", searcher::ELASTICLUNR_JS)?; utils::fs::write_file(destination, "elasticlunr.min.js", searcher::ELASTICLUNR_JS)?;
@ -164,10 +165,7 @@ fn render_item(
Ok(()) Ok(())
} }
/// Exports the index and search options to a JS script which stores the index in `window.search`. fn write_to_json(index: Index, search_config: &Search, doc_urls: Vec<String>) -> Result<String> {
/// Using a JS script is a workaround for CORS in `file://` URIs. It also removes the need for
/// downloading/parsing JSON in JS.
fn write_to_js(index: Index, search_config: &Search, doc_urls: Vec<String>) -> Result<String> {
use std::collections::BTreeMap; use std::collections::BTreeMap;
use self::elasticlunr::config::{SearchBool, SearchOptions, SearchOptionsField}; use self::elasticlunr::config::{SearchBool, SearchOptions, SearchOptionsField};
@ -225,7 +223,7 @@ fn write_to_js(index: Index, search_config: &Search, doc_urls: Vec<String>) -> R
let json_contents = serde_json::to_value(&json_contents)?; let json_contents = serde_json::to_value(&json_contents)?;
let json_contents = serde_json::to_string(&json_contents)?; let json_contents = serde_json::to_string(&json_contents)?;
Ok(format!("window.search = {};", json_contents)) Ok(json_contents)
} }
fn clean_html(html: &str) -> String { fn clean_html(html: &str) -> String {

View File

@ -247,12 +247,12 @@ window.search = window.search || {};
return teaser_split.join(''); return teaser_split.join('');
} }
function init() { function init(config) {
results_options = window.search.results_options; results_options = config.results_options;
search_options = window.search.search_options; search_options = config.search_options;
searchbar_outer = window.search.searchbar_outer; searchbar_outer = config.searchbar_outer;
doc_urls = window.search.doc_urls; doc_urls = config.doc_urls;
searchindex = elasticlunr.Index.load(window.search.index); searchindex = elasticlunr.Index.load(config.index);
// Set up events // Set up events
searchicon.addEventListener('click', function(e) { searchIconClickHandler(); }, false); searchicon.addEventListener('click', function(e) { searchIconClickHandler(); }, false);
@ -462,7 +462,16 @@ window.search = window.search || {};
showResults(true); showResults(true);
} }
init(); fetch('searchindex.json')
.then(response => response.json())
.then(json => init(json))
.catch(error => { // Try to load searchindex.js if fetch failed
var script = document.createElement('script');
script.src = 'searchindex.js';
script.onload = () => init(window.search);
document.head.appendChild(script);
});
// Exported functions // Exported functions
search.hasFocus = hasFocus; search.hasFocus = hasFocus;
})(window.search); })(window.search);