Search json index (#1998)
* search: Add support for a JSON index * docs: Document JSON index for search * docs: Use lazy-loaded JSON index * Add elasticlunr prefix to search engine format configuration This will be useful if support for more search libraries are added in the future
This commit is contained in:
parent
291c93e4ba
commit
7000f787b3
@ -1,5 +1,18 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum IndexFormat {
|
||||||
|
ElasticlunrJson,
|
||||||
|
ElasticlunrJavascript,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for IndexFormat {
|
||||||
|
fn default() -> IndexFormat {
|
||||||
|
IndexFormat::ElasticlunrJavascript
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct Search {
|
pub struct Search {
|
||||||
@ -15,6 +28,8 @@ pub struct Search {
|
|||||||
pub include_description: bool,
|
pub include_description: bool,
|
||||||
/// Include the path of the page in the search index. `false` by default.
|
/// Include the path of the page in the search index. `false` by default.
|
||||||
pub include_path: bool,
|
pub include_path: bool,
|
||||||
|
/// Foramt of the search index to be produced. Javascript by default
|
||||||
|
pub index_format: IndexFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Search {
|
impl Default for Search {
|
||||||
@ -25,6 +40,7 @@ impl Default for Search {
|
|||||||
include_description: false,
|
include_description: false,
|
||||||
include_path: false,
|
include_path: false,
|
||||||
truncate_content_length: None,
|
truncate_content_length: None,
|
||||||
|
index_format: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,13 @@ mod theme;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
pub use crate::config::{
|
pub use crate::config::{
|
||||||
languages::LanguageOptions, link_checker::LinkChecker, link_checker::LinkCheckerLevel,
|
languages::LanguageOptions,
|
||||||
search::Search, slugify::Slugify, taxonomies::TaxonomyConfig, Config,
|
link_checker::LinkChecker,
|
||||||
|
link_checker::LinkCheckerLevel,
|
||||||
|
search::{IndexFormat, Search},
|
||||||
|
slugify::Slugify,
|
||||||
|
taxonomies::TaxonomyConfig,
|
||||||
|
Config,
|
||||||
};
|
};
|
||||||
use errors::Result;
|
use errors::Result;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ use libs::rayon::prelude::*;
|
|||||||
use libs::tera::{Context, Tera};
|
use libs::tera::{Context, Tera};
|
||||||
use libs::walkdir::{DirEntry, WalkDir};
|
use libs::walkdir::{DirEntry, WalkDir};
|
||||||
|
|
||||||
use config::{get_config, Config};
|
use config::{get_config, Config, IndexFormat};
|
||||||
use content::{Library, Page, Paginator, Section, Taxonomy};
|
use content::{Library, Page, Paginator, Section, Taxonomy};
|
||||||
use errors::{anyhow, bail, Context as ErrorContext, Result};
|
use errors::{anyhow, bail, Context as ErrorContext, Result};
|
||||||
use libs::relative_path::RelativePathBuf;
|
use libs::relative_path::RelativePathBuf;
|
||||||
@ -764,32 +764,36 @@ impl Site {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn index_for_lang(&self, lang: &str) -> Result<()> {
|
||||||
|
let index_json = search::build_index(
|
||||||
|
&self.config.default_language,
|
||||||
|
&self.library.read().unwrap(),
|
||||||
|
&self.config,
|
||||||
|
)?;
|
||||||
|
let (path, content) = match &self.config.search.index_format {
|
||||||
|
IndexFormat::ElasticlunrJson => {
|
||||||
|
let path = self.output_path.join(&format!("search_index.{}.json", lang));
|
||||||
|
(path, index_json)
|
||||||
|
}
|
||||||
|
IndexFormat::ElasticlunrJavascript => {
|
||||||
|
let path = self.output_path.join(&format!("search_index.{}.js", lang));
|
||||||
|
let content = format!("window.searchIndex = {};", index_json);
|
||||||
|
(path, content)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
create_file(&path, &content)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build_search_index(&self) -> Result<()> {
|
pub fn build_search_index(&self) -> Result<()> {
|
||||||
ensure_directory_exists(&self.output_path)?;
|
ensure_directory_exists(&self.output_path)?;
|
||||||
// TODO: add those to the SITE_CONTENT map
|
// TODO: add those to the SITE_CONTENT map
|
||||||
|
|
||||||
// index first
|
// index first
|
||||||
create_file(
|
self.index_for_lang(&self.config.default_language)?;
|
||||||
&self.output_path.join(&format!("search_index.{}.js", self.config.default_language)),
|
|
||||||
&format!(
|
|
||||||
"window.searchIndex = {};",
|
|
||||||
search::build_index(
|
|
||||||
&self.config.default_language,
|
|
||||||
&self.library.read().unwrap(),
|
|
||||||
&self.config
|
|
||||||
)?
|
|
||||||
),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
for (code, language) in &self.config.other_languages() {
|
for (code, language) in &self.config.other_languages() {
|
||||||
if code != &self.config.default_language && language.build_search_index {
|
if code != &self.config.default_language && language.build_search_index {
|
||||||
create_file(
|
self.index_for_lang(code)?;
|
||||||
&self.output_path.join(&format!("search_index.{}.js", &code)),
|
|
||||||
&format!(
|
|
||||||
"window.searchIndex = {};",
|
|
||||||
search::build_index(code, &self.library.read().unwrap(), &self.config)?
|
|
||||||
),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,9 @@ description = "Everything you need to make a static site engine in one binary."
|
|||||||
compile_sass = true
|
compile_sass = true
|
||||||
build_search_index = true
|
build_search_index = true
|
||||||
|
|
||||||
|
[search]
|
||||||
|
index_format = "elasticlunr_json"
|
||||||
|
|
||||||
[markdown]
|
[markdown]
|
||||||
highlight_code = true
|
highlight_code = true
|
||||||
highlight_theme = "kronuz"
|
highlight_theme = "kronuz"
|
||||||
|
@ -17,6 +17,9 @@ After `zola build` or `zola serve`, you should see two files in your public dire
|
|||||||
- `search_index.${default_language}.js`: so `search_index.en.js` for a default setup
|
- `search_index.${default_language}.js`: so `search_index.en.js` for a default setup
|
||||||
- `elasticlunr.min.js`
|
- `elasticlunr.min.js`
|
||||||
|
|
||||||
|
If you set `index_format = "elasticlunr_json"` in your `config.toml`, a `search_index.${default_language}.json` is generated
|
||||||
|
instead of the default `search_index.${default_language}.js`.
|
||||||
|
|
||||||
As each site will be different, Zola makes no assumptions about your search function and doesn't provide
|
As each site will be different, Zola makes no assumptions about your search function and doesn't provide
|
||||||
the JavaScript/CSS code to do an actual search and display results. You can look at how this site
|
the JavaScript/CSS code to do an actual search and display results. You can look at how this site
|
||||||
implements it to get an idea: [search.js](https://github.com/getzola/zola/tree/master/docs/static/search.js).
|
implements it to get an idea: [search.js](https://github.com/getzola/zola/tree/master/docs/static/search.js).
|
||||||
|
@ -160,6 +160,10 @@ include_content = true
|
|||||||
# become too big to load on the site. Defaults to not being set.
|
# become too big to load on the site. Defaults to not being set.
|
||||||
# truncate_content_length = 100
|
# truncate_content_length = 100
|
||||||
|
|
||||||
|
# Wether to produce the search index as a javascript file or as a JSON file
|
||||||
|
# Accepted value "elasticlunr_javascript" or "elasticlunr_json"
|
||||||
|
index_format = "elasticlunr_javascript"
|
||||||
|
|
||||||
# Optional translation object for the default language
|
# Optional translation object for the default language
|
||||||
# Example:
|
# Example:
|
||||||
# default_language = "fr"
|
# default_language = "fr"
|
||||||
|
21
docs/static/search.js
vendored
21
docs/static/search.js
vendored
@ -142,11 +142,24 @@ function initSearch() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
var currentTerm = "";
|
var currentTerm = "";
|
||||||
var index = elasticlunr.Index.load(window.searchIndex);
|
var index;
|
||||||
|
|
||||||
$searchInput.addEventListener("keyup", debounce(function() {
|
var initIndex = async function () {
|
||||||
|
if (index === undefined) {
|
||||||
|
index = fetch("/search_index.en.json")
|
||||||
|
.then(
|
||||||
|
async function(response) {
|
||||||
|
return await elasticlunr.Index.load(await response.json());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let res = await index;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
$searchInput.addEventListener("keyup", debounce(async function() {
|
||||||
var term = $searchInput.value.trim();
|
var term = $searchInput.value.trim();
|
||||||
if (term === currentTerm || !index) {
|
if (term === currentTerm) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$searchResults.style.display = term === "" ? "none" : "block";
|
$searchResults.style.display = term === "" ? "none" : "block";
|
||||||
@ -156,7 +169,7 @@ function initSearch() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var results = index.search(term, options);
|
var results = (await initIndex()).search(term, options);
|
||||||
if (results.length === 0) {
|
if (results.length === 0) {
|
||||||
$searchResults.style.display = "none";
|
$searchResults.style.display = "none";
|
||||||
return;
|
return;
|
||||||
|
1
docs/templates/index.html
vendored
1
docs/templates/index.html
vendored
@ -103,7 +103,6 @@
|
|||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script type="text/javascript" src="{{ get_url(path="elasticlunr.min.js") }}"></script>
|
<script type="text/javascript" src="{{ get_url(path="elasticlunr.min.js") }}"></script>
|
||||||
<script type="text/javascript" src="{{ get_url(path="search_index.en.js") }}"></script>
|
|
||||||
<script type="text/javascript" src="{{ get_url(path="search.js") }}"></script>
|
<script type="text/javascript" src="{{ get_url(path="search.js") }}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
Reference in New Issue
Block a user