preface
When making the knowledge base within the group, I chose docsify, a document generator based on VUE, considering its lightness and ease of writing (only markdown files are needed). To paraphrase his summary:
Docsify can help you quickly generate document websites. Unlike GitBook, Hexo does not generate static.html files; all conversion is done at run time. If you want to get started, just create an index.html and start writing documentation and deploy it directly on GitHub Pages.
In fact, it is very lightweight and easy to use, but there is a problem that has not been as good as the experience, is search, because as more and more documents, sometimes you want to search a document based on a keyword, but you can’t find it.
The use of the search plugin
In fact, docsify is a full text search plug-in, specific see: full text search – search, writing is not wrong, configuration is very simple, even the source code is very good to understand, is not complex.
The full-text search plug-in retrives the document content based on the hyperlink on the current page and indexes the document in localStorage. The default expiration time is one day. Of course, you can specify the list of files to cache or set the expiration time.
However, the problem lies in his configuration. He converts these MD files into search index blocks by reading the paths parameter passed in beforehand, and then stores them in localStorage. The whole query behind is actually the front-end query, without back-end intervention (Docsify deployment does not need back-end intervention. Only a Web Server hosting is required and no build is required because the requested Vue JS will convert the MD file to HTML, which is the root cause of its portability), but also because it is front-end search and its search source is on top of LocalStorage.
Then he will go through the MD file in the Paths array that we passed in, and he will crawl the contents of the MD file and create a search block that will be stored in localStorage
search : [
'/', // => /README.md
'/guide', // => /guide.md
'/get-started', // => /get-started.md
'/zh-cn/', // => /zh-cn/README.md
],
Copy the code
Or complete configuration parameters:
Search: {maxAge: 86400000, // Expiration time, in milliseconds, default day paths: [ '/', // => /README.md '/guide', // => /guide.md '/get-started', // => /get-started.md '/zh-cn/', // => /zh-cn/README.md ], }Copy the code
If configured this way, then your search pool is the top 4 MD files, the other MD files are not in the search pool.
Of course, that’s a hassle, so he offers another way to search, which is:
Search: 'auto', // defaultCopy the code
Or:
paths: 'auto'
Copy the code
When you set it to Auto, it will go to the navigation bar, which is _sidebar. Md, where all the index directories are in the MD file. Then use these files as a search pool to create the corresponding search index block, and then save it in localStorage. The specific code is as follows:
function init(config, vm) { var isAuto = config.paths === 'auto'; var expireKey = resolveExpireKey(config.namespace); var indexKey = resolveIndexKey(config.namespace); var isExpired = localStorage.getItem(expireKey) < Date.now(); INDEXS = JSON.parse(localStorage.getItem(indexKey)); if (isExpired) { INDEXS = {}; } else if (! isAuto) { return } var paths = isAuto ? getAllPaths(vm.router) : config.paths; var len = paths.length; var count = 0; paths.forEach(function (path) { if (INDEXS[path]) { return count++ } Docsify .get(vm.router.getFile(path), false, vm.config.requestHeaders) .then(function (result) { INDEXS[path] = genIndex(path, result, vm.router, config.depth); len === ++count && saveData(config.maxAge, expireKey, indexKey); }); }); }Copy the code
For example, I set _sidebar. Md like this:
* / directory (/) * [official website] (/ xxx_web_www) * / management background (/ xxx_business_admin) * [web side] (/ XXX /)Copy the code
So when I set it to Auto, then localstorage is going to be
The search pool becomes these four MD files, that is, if all your MD files are in the navigation file _sidebar. Md, then the search pool in your localstorage is all, which is what we want.
But in fact, this is very difficult to achieve. Since it’s unlikely that you’ll be writing an MD file, you’ll have to modify the navigation file. So maintaining the navigation bar file is too expensive.
Populate paths directly with scripts
Since the MD files in paths are the search pool, just put all the MD files in this array. So my approach is to write all the MD files into this array. The original index.html configuration looked like this:
Gulpfile.js /*gulp*/paths: [], // allow the creation of search index blocks, location to 6 level title depth: 6, placeholder: 'search... ', noData: 'No results found, try another search term? ', namespace: 'web', },Copy the code
So we just need to run out all the md file names of the Docsify project and put them into the Paths array. There are many ways to execute them. I choose gulp, which I am familiar with, as follows:
"use strict";
const gulp = require('gulp');
var fs = require('fs');
const replace = require('gulp-replace');
// Walk through a folder, every time you get a file, or get a folder,
// finishCb completes the callback
// Array of valid files to return
// ignoreFileArr Specifies the name of the file to ignore, including the folder
// The original path
function traverseDir (path, finishCb, fileArr, ignoreFileArr, originPath) {
fileArr = fileArr || [];
ignoreFileArr = ignoreFileArr || [];
originPath = originPath || path;
fs.readdir(path, function (err, files) {
// Err indicates an error. Files file name list contains folders and files
if (err) {
console.log('error:\n' + err);
return;
}
var count = files.length;
var trackCount = 0;
var singleFinish = function(){
trackCount += 1;
checkIsDone();
};
var doneCb = function(){
// This is done
finishCb(fileArr);
};
var checkIsDone = function(){
if(trackCount === count){ doneCb(); }};if (count === 0) {
doneCb();
} else {
files.forEach(function (file, index) {
var filePath = path + '/' + file;
fs.stat(filePath, function (err, stat) {
if (err) {
console.log(err);
return;
}
// Determine whether to filter this folder or this folder
var validFileName = filePath.substr(originPath.length + 1);
// console.log("valid file:" + validFileName);
if(ignoreFileArr.indexOf(validFileName) > -1) {// If it is in the filter array. So filter it out.
// console.log("ignore file:=============" + validFileName);
trackCount += 1;
checkIsDone();
}else{
if (stat.isDirectory()) {
// If it is a folder, recurse
traverseDir(filePath, singleFinish, fileArr, ignoreFileArr, originPath);
} else {
// Read all the files
// only.md files need to be inserted
var tmpArr = file.split(".");
if(tmpArr.length > 1 && tmpArr.pop() === 'md'){
fileArr.push('/' + validFileName);
}
trackCount += 1; checkIsDone(); }}}); }); }}); }; gulp.task('default'.cb= > {
return traverseDir(process.cwd(), function(fileArr) {
console.log("Traversal common file:" + fileArr.length);
return gulp.src(process.cwd() + '/index.html')
.pipe(replace(/(\/\*gulp\*\/paths:)(.*)/.'$1'+ JSON.stringify(fileArr) +', '))
.pipe(gulp.dest(process.cwd()))
},[],[
// This is the file or folder to filter out
// There is one detail to note on todo, because these search keywords are placed on localstorage and have only 5M space, so if there are too many documents, it is possible to explode, unless you directly change the code to store them in indexDB or something
'node_modules'.'project_relevance.md'.'_sidebar.md',]); });Copy the code
The logic was simple enough to traverse the directory and find all files with the MD suffix, while allowing me to ignore some folders or files. You end up with an array of all the MD files, and then replace the values for paths in index.html. That will do. As a result, the index.html configuration becomes (I only took part of it because the array is too long):
search: {
maxAge: 86400000.// The todo array is generated by executing the script and does not need to be manually modified. See gulpfile.js for details
/*gulp*/paths: ["/README.md"."/xxx/connect_broken.md"."/xxx/connectionLimit.md"."/xxx/extension.md"."/xxx/README.md"."/xxx/lite.md"."/xxx/gopush.md"."/xxx/webrtc_stat.md"."/xxx/e2ee.md"."/xxx_admin/README.md"."/air-ui/README.md"."/xxx_business_admin/README.md"."/xxx_attachment/README.md"."/xxx_lang/doc.md"."/xxx_lang/downloadFile.md"."/xxx_lang/README.md"."/xxx_mail_nms/README.md"."/xxx_business_embed/README.md"."/xxx_device_embed/README.md"."/xxx_pc/README.md"."/xxx_mail_nms_server/README.md"."/xxx_pc_online/README.md"."/xxx_device_help/README.md"."/xxx_web_www/README.md"."/xxx_web_www/optimization.md"].depth: 6.placeholder: 'search... '.noData: 'Failed to find results, try another search term? '.namespace: 'web',},Copy the code
The result of viewing it in the browser is:
This is the true full-text search:
Then you just need to execute the gulp script when you write the document regularly.
note
However, it is important to note that because it is the front-end search, and it is stored in localstorage, and localstorage can only store 5M data, once the stored data exceeds 5M, then an error will be reported.
If this happens later, it is possible to change the search.js source code to store it in indexDB. This need to change later, I go to modify the source code, it is not difficult. Use it for now
See my personal site: kebingzao.com/ for more good articles