Add lightning fast search to Gridsome with FlexSearch - demo
Table of contents:
Requires a Node version >=12.x, and at least Gridsome 0.7.15
.
# Yarn
yarn add gridsome-plugin-flexsearch
# NPM
npm i gridsome-plugin-flexsearch
gridsome.config.js
module.exports = {
// ...
plugins: [
{
use: 'gridsome-plugin-flexsearch',
options: {
searchFields: ['title'],
collections: [
{
typeName: 'SomeType',
indexName: 'SomeType',
fields: ['title', 'handle', 'description']
}
]
}
}
]
}
This plugin requires a few configurations to get going.
Firstly, you will need to add the fields that will be included in the index and searched. Note that this is different from the below fields
option, as fields will not be searched - they are just what is returned in each result.
Option | Explanation |
---|---|
searchFields |
An array of keys in each node, that will be used for the search index. |
You can also specify optional flexsearch configurations under a flexsearch
key - the default configuration is to use the default
profile, which will setup the FlexSearch instance with some sensible defaults.
However you can override this profile, or set custom options such as tokenize
, resolution
etc. Read the FlexSearch docs to find out more.
Next, you need to specify what types you want to add to the index with collections: [...
. collections
expects an array of objects, each with at least two fields, and one optional field.
Option | Explanation |
---|---|
typeName |
The Schema typename - e.g. Post . All nodes with this typename will be added to the search index. |
indexName |
The name of the index created for this collection - can be the same as typeName . It is added to the result, so you can differentiate between Collection & Product search results for example. |
fields |
An array of keys that will be extracted from each node, and added to the search index doc (what the search result will return when queried). |
transform |
Transforms a schema to enable searching in nested data structures (optional). |
Fields will be returned with the search result under a node
key, so for example you could include a product title, slug, and image to show the product name & image in the search result, and add a link to the relevant page.
An example setup is shown below, assuming there is a Post
and a Collection
type:
gridsome.config.js
module.exports = {
// ...
plugins: [
{
use: 'gridsome-plugin-flexsearch',
options: {
searchFields: ['title', 'tags', 'authors'],
collections: [
{
typeName: 'Post'
indexName: 'Post',
fields: ['id', 'title', 'slug', 'image']
},
{
typeName: 'Collection'
indexName: 'Collection',
fields: ['id', 'title', 'path'],
transform: (collection) => ({
...collection,
authors: collection.authors.map(author => author.name)
})
}
]
}
}
]
}
Previous versions of this plugin(<=1.0
) supported using the GraphQL source plugin - however, this has now been deprecated, due to difficulties in querying and fetching the data - it is usually better to import your data into Gridsome's store anyway.
Option | Explanation |
---|---|
chunk |
Defaults to false. If true or a Number (docs array chunk size), it will split up the FlexSearch index & docs JSON file to reduce filesizes - useful if you have a huge amount of data. |
compress |
Defaults to false. If you have a large amount of data (5k+ nodes) you can compress this data to substantially decrease the JSON size. Note that this may actually increase the JSON size if you have a small amount of data, due to the way compression works. |
autoFetch |
Defaults to true. This plugin will usually automatically fetch and import the generated FlexSearch index & docs as soon as the site is loaded, but if you only want this to happen on a certain route (i.e. /search ) to reduce other page load times for example, you can specify that route with this option, or disable it completely and import yourself with this.$search.import({ ... ] |
Some examples of these configurations are shown below:
gridsome.config.js
// ...
options: {
chunk: true,
compress: true,
autoFetch: '/search',
// Or
chunk: 1000,
autoFetch: ['/search', '/collections'],
// ...
}
// ...
Custom FlexSearch options can be configured under the flexsearch
key, for example setting default profiles, or adding custom matchers/encoders.
gridsome.config.js
// ...
options: {
flexsearch: {
cache: true,
profile: 'match'
}
// ...
}
// ...
Now you can use it in your Gridsome site - the FlexSearch instance is available at this.$search
:
<template>
<Layout>
<input
id="search"
v-model="searchTerm"
class="input"
type="text"
placeholder="Search">
{{ searchResults }}
</Layout>
</template>
<script>
export default {
data: () => ({
searchTerm: ''
}),
computed: {
searchResults () {
const searchTerm = this.searchTerm
if (searchTerm.length < 3) return []
return this.$search.search({ query: searchTerm, limit: 5 })
}
}
}
</script>
The search results will be an array of objects, each containing an id
, the index name as index
, a node
object containing the fields you specified in collections, and the path
to the resource (if using the gridsome.config.js
templates
option) which you can use with g-link
. Image processing is also supported (for local images only), so you can use processed images with g-image
as ususal.
A handy mixin is also included with this package, to save you writing the above boilerplate:
<template>
<Layout>
<input
id="search"
v-model="searchTerm"
class="input"
type="text"
placeholder="Search">
<g-link
v-for="result in searchResults"
:key="result.id"
:to="result.path"
class="navbar-item">
<p>{{ result.title }}</p>
<g-image :src="result.image">
</g-link>
</Layout>
</template>
<script>
import Search from 'gridsome-plugin-flexsearch/SearchMixin'
export default {
mixins: [Search]
}
</script>