Skip to content

Commit

Permalink
feat(search): use dexie.js instead of localStorage (#2464)
Browse files Browse the repository at this point in the history
  • Loading branch information
sy-records authored Jul 31, 2024
1 parent 7cbd532 commit 42f2548
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 29 deletions.
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"*.js": "eslint --fix"
},
"dependencies": {
"dexie": "^4.0.8",
"medium-zoom": "^1.1.0",
"opencollective-postinstall": "^2.0.2",
"prismjs": "^1.29.0",
Expand Down
83 changes: 59 additions & 24 deletions src/plugins/search/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,33 @@ import {
getAndRemoveConfig,
getAndRemoveDocsifyIgnoreConfig,
} from '../../core/render/utils.js';
import Dexie from 'dexie';

let INDEXES = {};

const db = new Dexie('docsify');
db.version(1).stores({
search: 'slug, title, body, path, indexKey',
expires: 'key, value',
});

async function saveData(maxAge, expireKey) {
INDEXES = Object.values(INDEXES).flatMap(innerData =>
Object.values(innerData),
);
await db.search.bulkPut(INDEXES);
await db.expires.put({ key: expireKey, value: Date.now() + maxAge });
}

let INDEXS = {};
async function getData(key, isExpireKey = false) {
if (isExpireKey) {
const item = await db.expires.get(key);
return item ? item.value : 0;
}

const item = await db.search.where({ indexKey: key }).toArray();
return item ? item : null;
}

const LOCAL_STORAGE = {
EXPIRE_KEY: 'docsify.search.expires',
Expand Down Expand Up @@ -73,12 +98,7 @@ function getListData(token) {
return token.text;
}

function saveData(maxAge, expireKey, indexKey) {
localStorage.setItem(expireKey, Date.now() + maxAge);
localStorage.setItem(indexKey, JSON.stringify(INDEXS));
}

export function genIndex(path, content = '', router, depth) {
export function genIndex(path, content = '', router, depth, indexKey) {
const tokens = window.marked.lexer(content);
const slugify = window.Docsify.slugify;
const index = {};
Expand All @@ -101,14 +121,22 @@ export function genIndex(path, content = '', router, depth) {
title = getAndRemoveDocsifyIgnoreConfig(str).content;
}

index[slug] = { slug, title: title, body: '' };
index[slug] = {
slug,
title: title,
body: '',
path: path,
indexKey: indexKey,
};
} else {
if (tokenIndex === 0) {
slug = router.toURL(path);
index[slug] = {
slug,
title: path !== '/' ? path.slice(1) : 'Home Page',
body: token.text || '',
path: path,
indexKey: indexKey,
};
}

Expand All @@ -129,6 +157,9 @@ export function genIndex(path, content = '', router, depth) {

index[slug].body = token.text || '';
}

index[slug].path = path;
index[slug].indexKey = indexKey;
}
});
slugify.clear();
Expand All @@ -148,21 +179,14 @@ export function ignoreDiacriticalMarks(keyword) {
*/
export function search(query) {
const matchingResults = [];
let data = [];
Object.keys(INDEXS).forEach(key => {
data = [
...data,
...Object.keys(INDEXS[key]).map(page => INDEXS[key][page]),
];
});

query = query.trim();
let keywords = query.split(/[\s\-,\\/]+/);
if (keywords.length !== 1) {
keywords = [query, ...keywords];
}

for (const post of data) {
for (const post of INDEXES) {
let matchesScore = 0;
let resultStr = '';
let handlePostTitle = '';
Expand Down Expand Up @@ -235,7 +259,7 @@ export function search(query) {
return matchingResults.sort((r1, r2) => r2.score - r1.score);
}

export function init(config, vm) {
export async function init(config, vm) {
const isAuto = config.paths === 'auto';
const paths = isAuto ? getAllPaths(vm.router) : config.paths;

Expand Down Expand Up @@ -269,12 +293,12 @@ export function init(config, vm) {
const expireKey = resolveExpireKey(config.namespace) + namespaceSuffix;
const indexKey = resolveIndexKey(config.namespace) + namespaceSuffix;

const isExpired = localStorage.getItem(expireKey) < Date.now();
const isExpired = (await getData(expireKey, true)) < Date.now();

INDEXS = JSON.parse(localStorage.getItem(indexKey));
INDEXES = await getData(indexKey);

if (isExpired) {
INDEXS = {};
INDEXES = {};
} else if (!isAuto) {
return;
}
Expand All @@ -283,14 +307,25 @@ export function init(config, vm) {
let count = 0;

paths.forEach(path => {
if (INDEXS[path]) {
const pathExists = Array.isArray(INDEXES)
? INDEXES.some(obj => obj.path === path)
: false;
if (pathExists) {
return count++;
}

Docsify.get(vm.router.getFile(path), false, vm.config.requestHeaders).then(
result => {
INDEXS[path] = genIndex(path, result, vm.router, config.depth);
len === ++count && saveData(config.maxAge, expireKey, indexKey);
async result => {
INDEXES[path] = genIndex(
path,
result,
vm.router,
config.depth,
indexKey,
);
if (len === ++count) {
await saveData(config.maxAge, expireKey);
}
},
);
});
Expand Down
5 changes: 0 additions & 5 deletions test/integration/example.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ describe('Creating a Docsify site (integration tests in Jest)', function () {
const docsifyInitConfig = {
config: {
name: 'Docsify Name',
themeColor: 'red',
},
markdown: {
coverpage: `
Expand Down Expand Up @@ -58,8 +57,6 @@ describe('Creating a Docsify site (integration tests in Jest)', function () {
scriptURLs: [
// docsifyInit() route
'data-test-scripturls.js',
// Server route
'/dist/plugins/search.js',
],
style: `
body {
Expand All @@ -76,7 +73,6 @@ describe('Creating a Docsify site (integration tests in Jest)', function () {

// Verify config options
expect(typeof window.$docsify).toBe('object');
expect(window.$docsify).toHaveProperty('themeColor', 'red');
expect(document.querySelector('.app-name').textContent).toContain(
'Docsify Name',
);
Expand All @@ -101,7 +97,6 @@ describe('Creating a Docsify site (integration tests in Jest)', function () {

// Verify docsifyInitConfig.scriptURLs were executed
expect(document.body.hasAttribute('data-test-scripturls')).toBe(true);
expect(document.querySelector('.search input[type="search"]')).toBeTruthy();

// Verify docsifyInitConfig.script was added to the DOM
expect(
Expand Down

0 comments on commit 42f2548

Please sign in to comment.