Skip to content

Commit f254371

Browse files
authored
First version of MeiliSearch plugin for Vuepress (#1)
1 parent 2aa8e13 commit f254371

20 files changed

+16440
-205
lines changed

.eslintignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
playground
2+
assets
3+
scripts

.eslintrc.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module.exports = {
2+
env: {
3+
browser: true,
4+
commonjs: true,
5+
es6: true,
6+
jest: true
7+
},
8+
extends: [
9+
'plugin:vue/essential',
10+
'standard',
11+
'plugin:vue/recommended'
12+
],
13+
globals: {
14+
HOST_URL: 'readonly',
15+
API_KEY: 'readonly',
16+
INDEX_UID: 'readonly',
17+
MAX_SUGGESTIONS: 'readonly',
18+
CROP_LENGTH: 'readonly',
19+
HOT_KEYS: 'readonly',
20+
PLACEHOLDER: 'readonly'
21+
},
22+
parserOptions: {
23+
parser: 'babel-eslint',
24+
ecmaVersion: 2018
25+
},
26+
plugins: [
27+
'vue'
28+
],
29+
rules: {
30+
'no-console': ['error', { allow: ['warn', 'error'] }]
31+
}
32+
}

.github/workflows/npm-publish.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Publish to NPM
2+
3+
on:
4+
push:
5+
tags:
6+
- v*
7+
8+
jobs:
9+
publish-npm:
10+
runs-on: ubuntu-18.04
11+
steps:
12+
- uses: actions/checkout@v2
13+
- name: Check release validity
14+
run: sh scripts/check-release.sh
15+
- uses: actions/setup-node@v1
16+
with:
17+
node-version: 12
18+
registry-url: https://registry.npmjs.org/
19+
- name: Install dependencies
20+
run: yarn install
21+
- name: Run tests
22+
run: yarn run test
23+
- name: Publish
24+
run: npm publish
25+
env:
26+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.github/workflows/test-lint.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: Tests-Lint
2+
3+
on: [pull_request]
4+
5+
jobs:
6+
test:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v2
10+
- name: Install dependencies
11+
run: yarn install
12+
- name: Run tests
13+
run: yarn run test
14+
- name: Run linter
15+
run: yarn run lint

.npmignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
scripts
2+
.editorconfig
3+
.eslintrc.js
4+
.github
5+
tests
6+
jest.config.js

MeiliSearchBox.vue

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,71 +8,96 @@
88
id="meilisearch-search-input"
99
class="search-query"
1010
:placeholder="placeholder"
11-
/>
11+
>
1212
</form>
1313
</template>
1414

1515
<script>
16-
console.log('In meilisearch component')
17-
console.log(HOST_URL)
18-
console.log(API_KEY)
19-
console.log(INDEX_UID)
2016
export default {
21-
name: "MeiliSearchBox",
22-
data() {
17+
name: 'MeiliSearchBox',
18+
data () {
2319
return {
24-
placeholder: undefined,
25-
};
20+
placeholder: undefined
21+
}
2622
},
2723
watch: {
28-
options(newValue) {
29-
this.update(newValue);
30-
},
24+
options (newValue) {
25+
this.update(newValue)
26+
}
3127
},
32-
mounted() {
33-
let options = {
28+
mounted () {
29+
const options = {
3430
hostUrl: HOST_URL,
3531
apiKey: API_KEY,
36-
indexUid: INDEX_UID
32+
indexUid: INDEX_UID,
33+
meilisearchOptions: {
34+
limit: MAX_SUGGESTIONS || this.$site.themeConfig.searchMaxSuggestions || 5,
35+
cropLength: CROP_LENGTH
36+
},
37+
autocompleteOptions: {
38+
keyboardShortcuts: HOT_KEYS
39+
}
3740
}
38-
this.initialize(options);
39-
this.placeholder = this.$site.themeConfig.searchPlaceholder || "";
41+
this.initialize(options)
42+
this.placeholder = PLACEHOLDER || this.$site.themeConfig.searchPlaceholder || ''
4043
},
4144
4245
methods: {
43-
initialize(userOptions) {
46+
initialize (userOptions) {
4447
Promise.all([
4548
import(
46-
/* webpackChunkName: "docs-searchbar" */ "docs-searchbar.js/dist/cdn/docs-searchbar.min.js"
49+
/* webpackChunkName: "docs-searchbar" */ 'docs-searchbar.js/dist/cdn/docs-searchbar.min.js'
4750
),
4851
import(
49-
/* webpackChunkName: "docs-searchbar" */ "docs-searchbar.js/dist/cdn/docs-searchbar.min.css"
50-
),
52+
/* webpackChunkName: "docs-searchbar" */ 'docs-searchbar.js/dist/cdn/docs-searchbar.min.css'
53+
)
5154
]).then(([docsSearchBar]) => {
52-
docsSearchBar = docsSearchBar.default;
55+
docsSearchBar = docsSearchBar.default
5356
const input = Object.assign({}, userOptions, {
54-
inputSelector: "#meilisearch-search-input",
55-
meilisearchOptions: { cropLength: 40 },
57+
inputSelector: '#meilisearch-search-input',
5658
handleSelected: (input, event, suggestion) => {
57-
const { pathname, hash } = new URL(suggestion.url);
58-
const routepath = pathname.replace(this.$site.base, "/");
59-
this.$router.push(`${routepath}${hash}`);
60-
},
61-
});
62-
docsSearchBar(input);
63-
});
59+
const { pathname, hash } = new URL(suggestion.url)
60+
const routepath = pathname.replace(this.$site.base, '/')
61+
this.$router.push(`${routepath}${hash}`)
62+
}
63+
})
64+
docsSearchBar(input)
65+
})
6466
},
6567
66-
update(options) {
68+
update (options) {
6769
this.$el.innerHTML =
68-
'<input id="meilisearch-search-input" class="search-query">';
69-
this.initialize(options);
70-
},
71-
},
72-
};
70+
'<input id="meilisearch-search-input" class="search-query">'
71+
this.initialize(options)
72+
}
73+
}
74+
}
7375
</script>
7476

7577
<style lang="stylus">
78+
.search-box
79+
display inline-block
80+
position relative
81+
margin-right 1rem
82+
input
83+
cursor text
84+
width 10rem
85+
height: 2rem
86+
color lighten($textColor, 25%)
87+
display inline-block
88+
border 1px solid darken($borderColor, 10%)
89+
border-radius 2rem
90+
font-size 0.9rem
91+
line-height 2rem
92+
padding 0 0.5rem 0 2rem
93+
outline none
94+
transition all .2s ease
95+
&:focus
96+
cursor auto
97+
border-color $accentColor
98+
background #fff url(assets/search.svg) 0.6rem 0.5rem no-repeat
99+
background-size 1rem
100+
76101
.meilisearch-search-wrapper
77102
& > span
78103
vertical-align middle

README.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,166 @@
2121
<p align="center">⚡ Lightning Fast, Ultra Relevant, and Typo-Tolerant Search Engine MeiliSearch plugin for Vuepress</p>
2222

2323
**MeiliSearch Vuepress** is a **MeiliSearch** plugin for Vuepress. **MeiliSearch** is a powerful, fast, open-source, easy to use and deploy search engine. Both searching and indexing are highly customizable. Features such as typo-tolerance, filters, and synonyms are provided out-of-the-box.
24+
25+
This plugin is used in production on the [MeiliSearch documentation](https://docs.meilisearch.com/).
26+
27+
![MeiliSearch docs demo](assets/docs-searchbar-demo.gif).
28+
29+
## Table of Contents <!-- omit in toc -->
30+
31+
- [Usage](#usage)
32+
- [Run MeiliSearch](#run-meilisearch)
33+
- [Basic usage](#basic-usage)
34+
- [Customization](#customization)
35+
- [Scrap your Content](#scrap-your-content)
36+
- [Your MeiliSearch Instance](#your-meilisearch-instance)
37+
- [Your Scraper](#your-scraper)
38+
- [Development Workflow](#development-workflow)
39+
- [Related Repositories](#related-repositories)
40+
- [🤖 Compatibility with MeiliSearch](#-compatibility-with-meilisearch)
41+
42+
## Usage
43+
44+
### Run MeiliSearch
45+
46+
First of all, you need your Vuepress content to be scraped and pushed into a MeiliSearch instance.
47+
48+
This can be done in few steps. Read the [dedicated section](#scrap-your-content).
49+
50+
The host URL, the API key and the index UID you will provide in your configuration file are the credentials of this MeiliSearch instance.
51+
52+
**Without running a MeiliSearch instance, the next steps will not work.**
53+
54+
### Basic usage
55+
56+
In your Vuepress project:
57+
58+
```bash
59+
$ yarn add vuepress-plugin-meilisearch
60+
# or
61+
$ npm install vuepress-plugin-meilisearch
62+
```
63+
64+
In your `config.js` file:
65+
66+
```js
67+
module.exports = {
68+
plugins: [
69+
[
70+
"vuepress-plugin-meilisearch",
71+
{
72+
"hostUrl": "https://mymeilisearch.com",
73+
"apiKey": "XXX",
74+
"indexUid": "docs"
75+
}
76+
],
77+
],
78+
}
79+
```
80+
81+
**WARNING**: Since the configuration file is public, we recommand to provide the MeiliSearch public key, which is enough to perform searches.<br>
82+
Read more about [MeiliSearch authentication](https://docs.meilisearch.com/guides/advanced_guides/authentication.html#authentication).
83+
84+
### Customization
85+
86+
```js
87+
module.exports = {
88+
plugins: [
89+
[
90+
"vuepress-plugin-meilisearch",
91+
{
92+
"hostUrl": "https://mymeilisearch.com", // Mandatory
93+
"apiKey": "XXX", // Mandatory
94+
"indexUid": "docs-test", // Mandatory
95+
"placeholder": "Search as you type...", // Default: ""
96+
"maxSuggestions": 10, // Default: 5
97+
"hotKeys": [], // Default: ['s', '/']
98+
"cropLength": 50 // Default: 30
99+
}
100+
],
101+
],
102+
}
103+
```
104+
105+
## Scrap your Content
106+
107+
To use this plugin, your need:
108+
- a MeiliSearch instance running in production.
109+
- a scraping tool that scraps your Vuepress pages on regular bases.
110+
111+
### Your MeiliSearch Instance
112+
113+
This step has to be done on your side: MeiliSearch is open-source and can run on your own server! 😄
114+
115+
Here is the [documentation to install and run MeiliSearch](https://docs.meilisearch.com/guides/advanced_guides/installation.html#installation).
116+
117+
_A tutorial about how to run MeiliSearch in production is coming..._
118+
119+
### Your Scraper
120+
121+
We already provide a scraper for your website: [docs-scraper](https://github.com/meilisearch/docs-scraper).<br>
122+
This scraper is used in production on the [MeiliSearch documentation](https://docs.meilisearch.com/).
123+
124+
All the steps to use it are detailed in the scraper repository.<br>
125+
You can easily run the scraper with Docker or in a GitHub Action. The best would be to run the scraper on each website deployment.
126+
127+
## Development Workflow
128+
129+
### Install <!-- omit in toc -->
130+
131+
```bash
132+
$ yarn install
133+
```
134+
135+
### Test with the Playground <!-- omit in toc -->
136+
137+
A playground of a Vuepress environment is provided to test the plugin.
138+
139+
```bash
140+
$ yarn serve
141+
```
142+
143+
Then, open your browser on the indicated URL and test the search bar 🙂
144+
145+
Since the automatic tests are not relevant, we really recommend to use it during development.
146+
147+
### Tests and Linter <!-- omit in toc -->
148+
149+
```bash
150+
# Automatic tests (need improvement)
151+
$ yarn test
152+
# Linter
153+
$ yarn lint
154+
# Linter with auto-correct
155+
$ yarn lint:fix
156+
```
157+
158+
### Release <!-- omit in toc -->
159+
160+
MeiliSearch tools follow the [Semantic Versioning Convention](https://semver.org/).
161+
162+
You must do a PR modifying the file `package.json` with the right version.<br>
163+
164+
```javascript
165+
"version": X.X.X
166+
```
167+
168+
Once the changes are merged on `master`, in your terminal, you must be on the `master` branch and push a new tag with the right version:
169+
170+
```bash
171+
$ git checkout master
172+
$ git pull origin master
173+
$ git tag vX.X.X
174+
$ git push --tag origin master
175+
```
176+
177+
A GitHub Action will be triggered and push the package on [npm](https://www.npmjs.com/package/vuepress-plugin-meilisearch).
178+
179+
## Related Repositories
180+
181+
- [docs-searchBar.js](https://github.com/meilisearch/docs-searchbar.js): the library used to display the dropdown of this plugin. It can be useful if you want a search bar for your documentation but you don't use vuepress.
182+
- [docs-scraper](https://github.com/meilisearch/docs-scraper): the scraper used to scrap websites pages and automatically index the content in MeiliSearch.
183+
184+
## 🤖 Compatibility with MeiliSearch
185+
186+
This plugin works for MeiliSearch `>=0.10`.

assets/docs-searchbar-demo.gif

12.4 MB
Loading

assets/search.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)