Gatsby plugin for full text search implementation based on FlexSearch.js client-side index, heavily inspired in the gatsby-plugin-lunr.
Install gatsby-plugin-flexsearch
npm install --save gatsby-plugin-flexsearch
Add gatsby-plugin-flexsearch
configuration to the gatsby-config.js
as following:
module.exports = {
plugins: [
{
resolve: 'gatsby-plugin-flexsearch',
options: {
// L
languages: ['en'],
type: 'MarkdownRemark', // Filter the node types you want to index
// Fields to index.
fields: [
{
name: 'title',
indexed: true, // If indexed === true, the field will be indexed.
resolver: 'frontmatter.title',
// Attributes for indexing logic. Check https://github.com/nextapps-de/flexsearch#presets for details.
attributes: {
encode: 'balance',
tokenize: 'strict',
threshold: 6,
depth: 3,
},
store: true, // In case you want to make the field available in the search results.
},
{
name: 'description',
indexed: true,
resolver: 'frontmatter.description',
attributes: {
encode: 'balance',
tokenize: 'strict',
threshold: 6,
depth: 3,
},
store: false,
},
{
name: 'url',
indexed: false,
resolver: 'fields.slug',
store: true,
},
],
},
},
The search data will be available on the client side via window.__FLEXSEARCH__
that is an object with the following fields:
index
- a flexsearch index instancestore
- object that stores the indexed gatsby nodes where the id of each node corresponds to the id the filter, according with flexsearch.js best practices (https://github.com/nextapps-de/flexsearch#best-practices)).
import React, { Component } from 'react'
import { Link } from 'gatsby'
// Search component
class Search extends Component {
state = {
query: '',
results: [],
}
render() {
const ResultList = () => {
if (this.state.results.length > 0) {
return this.state.results.map((page, i) => (
<div className="item-search" key={i}>
<Link to={page.url} className="link">
<h4>{page.title}</h4>
</Link>
</div>
))
} else if (this.state.query.length > 2) {
return 'No results for ' + this.state.query
} else if (
this.state.results.length === 0 &&
this.state.query.length > 0
) {
return 'Please insert at least 3 characters'
} else {
return ''
}
}
return (
<div className={this.props.classNames}>
<input
className="search__input"
type="text"
onChange={this.search}
placeholder={'Search'}
/>
<div className="search__list">
<ResultList />
</div>
</div>
)
}
getSearchResults(query) {
// adicionar variável para língua
var index = window.__FLEXSEARCH__.en.index
var store = window.__FLEXSEARCH__.en.store
if (!query || !index) {
return []
} else {
var results = []
// search the indexed fields
Object.keys(index).forEach(idx => {
results.push(...index[idx].values.search(query)) // more search options at https://github.com/nextapps-de/flexsearch#index.search
})
// find the unique ids of the nodes
results = Array.from(new Set(results))
// return the corresponding nodes in the store
var nodes = store
.filter(node => (results.includes(node.id) ? node : null))
.map(node => node.node)
return nodes
}
}
search = event => {
const query = event.target.value
if (this.state.query.length > 2) {
const results = this.getSearchResults(query)
this.setState({ results: results, query: query })
} else {
this.setState({ results: [], query: query })
}
}
}
export default Search