From e1a46d213e69ca194bf57c9bcacc912ab9c16f42 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 13 Jun 2018 14:51:15 -0500 Subject: [PATCH] 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. --- src/renderer/html_handlebars/search.rs | 14 ++++++-------- src/theme/searcher/searcher.js | 23 ++++++++++++++++------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/renderer/html_handlebars/search.rs b/src/renderer/html_handlebars/search.rs index 310d8f09..20a17cfc 100644 --- a/src/renderer/html_handlebars/search.rs +++ b/src/renderer/html_handlebars/search.rs @@ -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)?; } - let index = write_to_js(index, &search_config, doc_urls)?; + let index = write_to_json(index, &search_config, doc_urls)?; debug!("Writing search index ✓"); 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 { - 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, "mark.min.js", searcher::MARK_JS)?; utils::fs::write_file(destination, "elasticlunr.min.js", searcher::ELASTICLUNR_JS)?; @@ -164,10 +165,7 @@ fn render_item( Ok(()) } -/// Exports the index and search options to a JS script which stores the index in `window.search`. -/// 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) -> Result { +fn write_to_json(index: Index, search_config: &Search, doc_urls: Vec) -> Result { use std::collections::BTreeMap; use self::elasticlunr::config::{SearchBool, SearchOptions, SearchOptionsField}; @@ -225,7 +223,7 @@ fn write_to_js(index: Index, search_config: &Search, doc_urls: Vec) -> R let json_contents = serde_json::to_value(&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 { diff --git a/src/theme/searcher/searcher.js b/src/theme/searcher/searcher.js index 85c890ae..82041c66 100644 --- a/src/theme/searcher/searcher.js +++ b/src/theme/searcher/searcher.js @@ -247,12 +247,12 @@ window.search = window.search || {}; return teaser_split.join(''); } - function init() { - results_options = window.search.results_options; - search_options = window.search.search_options; - searchbar_outer = window.search.searchbar_outer; - doc_urls = window.search.doc_urls; - searchindex = elasticlunr.Index.load(window.search.index); + function init(config) { + results_options = config.results_options; + search_options = config.search_options; + searchbar_outer = config.searchbar_outer; + doc_urls = config.doc_urls; + searchindex = elasticlunr.Index.load(config.index); // Set up events searchicon.addEventListener('click', function(e) { searchIconClickHandler(); }, false); @@ -462,7 +462,16 @@ window.search = window.search || {}; 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 search.hasFocus = hasFocus; })(window.search);