gridsome-plugin-flexsearch
Version:
Add lightning fast search to Gridsome with FlexSearch
213 lines (178 loc) • 6.93 kB
Markdown
> Add lightning fast search to Gridsome with FlexSearch - [demo](https://gridsome-shopify-starter.netlify.app)
Table of contents:
1. [Installation](
2. [Configuration](
- [Additional Options](
- [FlexSearch Options](
3. [Usage](
_Requires a Node version >=12.x, and at least Gridsome `0.7.15`._
```bash
yarn add gridsome-plugin-flexsearch
npm i gridsome-plugin-flexsearch
```
`gridsome.config.js`
```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](https://github.com/nextapps-de/flexsearch#presets) 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`
```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.
### Additional Options
| 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`
```js
// ...
options: {
chunk: true,
compress: true,
autoFetch: '/search',
// Or
chunk: 1000,
autoFetch: ['/search', '/collections'],
// ...
}
// ...
```
### FlexSearch Options
Custom FlexSearch options can be configured under the `flexsearch` key, for example setting default profiles, or adding custom matchers/encoders.
`gridsome.config.js`
```js
// ...
options: {
flexsearch: {
cache: true,
profile: 'match'
}
// ...
}
// ...
```
## Usage
Now you can use it in your Gridsome site - the FlexSearch instance is available at `this.$search`:
```vue
<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:
```vue
<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>
```