From baef9175198418b609dcbd7d1d0c8157af55080b Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Sun, 14 Jul 2024 17:27:04 +0800 Subject: [PATCH 1/6] feat(search): use dexie.js instead of localStorage --- package-lock.json | 6 +++++ package.json | 1 + src/plugins/search/search.js | 45 ++++++++++++++++++++------------ test/integration/example.test.js | 2 -- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9da1be264..e7a9df7e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { + "dexie": "^4.0.8", "medium-zoom": "^1.1.0", "opencollective-postinstall": "^2.0.2", "prismjs": "^1.29.0", @@ -5929,6 +5930,11 @@ "node": ">= 0.8.0" } }, + "node_modules/dexie": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/dexie/-/dexie-4.0.8.tgz", + "integrity": "sha512-1G6cJevS17KMDK847V3OHvK2zei899GwpDiqfEXHP1ASvme6eWJmAp9AU4s1son2TeGkWmC0g3y8ezOBPnalgQ==" + }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", diff --git a/package.json b/package.json index 91b865f23..0ede1e122 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/plugins/search/search.js b/src/plugins/search/search.js index 0428f69af..b609569c5 100644 --- a/src/plugins/search/search.js +++ b/src/plugins/search/search.js @@ -2,8 +2,24 @@ import { getAndRemoveConfig, getAndRemoveDocsifyIgnoreConfig, } from '../../core/render/utils.js'; +import Dexie from 'dexie'; -let INDEXS = {}; +let INDEXES = {}; + +const db = new Dexie('DocsifySearchDB'); +db.version(1).stores({ + search: 'key, value', +}); + +async function saveData(maxAge, expireKey, indexKey) { + await db.search.put({ key: expireKey, value: Date.now() + maxAge }); + await db.search.put({ key: indexKey, value: JSON.stringify(INDEXES) }); +} + +async function getData(key) { + const item = await db.search.get(key); + return item ? item.value : null; +} const LOCAL_STORAGE = { EXPIRE_KEY: 'docsify.search.expires', @@ -73,11 +89,6 @@ 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) { const tokens = window.marked.lexer(content); const slugify = window.Docsify.slugify; @@ -149,10 +160,10 @@ export function ignoreDiacriticalMarks(keyword) { export function search(query) { const matchingResults = []; let data = []; - Object.keys(INDEXS).forEach(key => { + Object.keys(INDEXES).forEach(key => { data = [ ...data, - ...Object.keys(INDEXS[key]).map(page => INDEXS[key][page]), + ...Object.keys(INDEXES[key]).map(page => INDEXES[key][page]), ]; }); @@ -235,7 +246,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; @@ -269,12 +280,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)) < Date.now(); - INDEXS = JSON.parse(localStorage.getItem(indexKey)); + INDEXES = JSON.parse(await getData(indexKey)); if (isExpired) { - INDEXS = {}; + INDEXES = {}; } else if (!isAuto) { return; } @@ -283,14 +294,16 @@ export function init(config, vm) { let count = 0; paths.forEach(path => { - if (INDEXS[path]) { + if (INDEXES[path]) { 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); + if (len === ++count) { + await saveData(config.maxAge, expireKey, indexKey); + } }, ); }); diff --git a/test/integration/example.test.js b/test/integration/example.test.js index 3894ea05e..3117a7153 100644 --- a/test/integration/example.test.js +++ b/test/integration/example.test.js @@ -20,7 +20,6 @@ describe('Creating a Docsify site (integration tests in Jest)', function () { const docsifyInitConfig = { config: { name: 'Docsify Name', - themeColor: 'red', }, markdown: { coverpage: ` @@ -76,7 +75,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', ); From a88f44c0015eae383164a317c8e24a5b30798a24 Mon Sep 17 00:00:00 2001 From: Koy Zhuang Date: Tue, 16 Jul 2024 22:37:28 +0800 Subject: [PATCH 2/6] update: remove search to e2e test. --- test/integration/example.test.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/integration/example.test.js b/test/integration/example.test.js index 3117a7153..4f6b57378 100644 --- a/test/integration/example.test.js +++ b/test/integration/example.test.js @@ -57,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 { @@ -99,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( From bbe3cfff173436b0beebd6c22b5d42267adfd87f Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Sun, 21 Jul 2024 15:19:07 +0800 Subject: [PATCH 3/6] feat: use rows and columns --- src/plugins/search/search.js | 63 ++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/src/plugins/search/search.js b/src/plugins/search/search.js index b609569c5..c125140d8 100644 --- a/src/plugins/search/search.js +++ b/src/plugins/search/search.js @@ -6,19 +6,27 @@ import Dexie from 'dexie'; let INDEXES = {}; -const db = new Dexie('DocsifySearchDB'); +const db = new Dexie('docsify'); db.version(1).stores({ - search: 'key, value', + search: 'slug, title, body, path, indexKey', + expires: 'key, value', }); async function saveData(maxAge, expireKey, indexKey) { - await db.search.put({ key: expireKey, value: Date.now() + maxAge }); - await db.search.put({ key: indexKey, value: JSON.stringify(INDEXES) }); + await db.search.bulkPut( + Object.values(INDEXES).flatMap(innerData => Object.values(innerData)), + ); + await db.expires.put({ key: expireKey, value: Date.now() + maxAge }); } -async function getData(key) { - const item = await db.search.get(key); - return item ? item.value : null; +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 = { @@ -89,7 +97,7 @@ function getListData(token) { return token.text; } -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 = {}; @@ -112,7 +120,13 @@ 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); @@ -120,6 +134,8 @@ export function genIndex(path, content = '', router, depth) { slug, title: path !== '/' ? path.slice(1) : 'Home Page', body: token.text || '', + path: path, + indexKey: indexKey, }; } @@ -140,6 +156,9 @@ export function genIndex(path, content = '', router, depth) { index[slug].body = token.text || ''; } + + index[slug].path = path; + index[slug].indexKey = indexKey; } }); slugify.clear(); @@ -159,13 +178,6 @@ export function ignoreDiacriticalMarks(keyword) { */ export function search(query) { const matchingResults = []; - let data = []; - Object.keys(INDEXES).forEach(key => { - data = [ - ...data, - ...Object.keys(INDEXES[key]).map(page => INDEXES[key][page]), - ]; - }); query = query.trim(); let keywords = query.split(/[\s\-,\\/]+/); @@ -173,7 +185,7 @@ export function search(query) { keywords = [query, ...keywords]; } - for (const post of data) { + for (const post of INDEXES) { let matchesScore = 0; let resultStr = ''; let handlePostTitle = ''; @@ -280,9 +292,9 @@ export async function init(config, vm) { const expireKey = resolveExpireKey(config.namespace) + namespaceSuffix; const indexKey = resolveIndexKey(config.namespace) + namespaceSuffix; - const isExpired = (await getData(expireKey)) < Date.now(); + const isExpired = (await getData(expireKey, true)) < Date.now(); - INDEXES = JSON.parse(await getData(indexKey)); + INDEXES = await getData(indexKey); if (isExpired) { INDEXES = {}; @@ -294,13 +306,22 @@ export async function init(config, vm) { let count = 0; paths.forEach(path => { - if (INDEXES[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( async result => { - INDEXES[path] = genIndex(path, result, vm.router, config.depth); + INDEXES[path] = genIndex( + path, + result, + vm.router, + config.depth, + indexKey, + ); if (len === ++count) { await saveData(config.maxAge, expireKey, indexKey); } From b6e33a6302e176742712449f3497d21f33c18f82 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Sun, 21 Jul 2024 15:27:50 +0800 Subject: [PATCH 4/6] fix: Fix first search error --- src/plugins/search/search.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/search/search.js b/src/plugins/search/search.js index c125140d8..b1d2d1f34 100644 --- a/src/plugins/search/search.js +++ b/src/plugins/search/search.js @@ -13,9 +13,8 @@ db.version(1).stores({ }); async function saveData(maxAge, expireKey, indexKey) { - await db.search.bulkPut( - Object.values(INDEXES).flatMap(innerData => Object.values(innerData)), - ); + INDEXES = Object.values(INDEXES).flatMap(innerData => Object.values(innerData)); + await db.search.bulkPut(INDEXES); await db.expires.put({ key: expireKey, value: Date.now() + maxAge }); } From f193d99e79a58781816efd9882b6cc0fb798c710 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Sun, 21 Jul 2024 15:29:34 +0800 Subject: [PATCH 5/6] fix: lint error --- src/plugins/search/search.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/search/search.js b/src/plugins/search/search.js index b1d2d1f34..b9d0209a4 100644 --- a/src/plugins/search/search.js +++ b/src/plugins/search/search.js @@ -13,7 +13,9 @@ db.version(1).stores({ }); async function saveData(maxAge, expireKey, indexKey) { - INDEXES = Object.values(INDEXES).flatMap(innerData => Object.values(innerData)); + INDEXES = Object.values(INDEXES).flatMap(innerData => + Object.values(innerData), + ); await db.search.bulkPut(INDEXES); await db.expires.put({ key: expireKey, value: Date.now() + maxAge }); } From 52f050d72491e8e0aaa0b4b47c2ccfd6b7babdb4 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Sat, 27 Jul 2024 20:32:37 +0800 Subject: [PATCH 6/6] fix: remove useless code --- src/plugins/search/search.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/search/search.js b/src/plugins/search/search.js index b9d0209a4..31a6948b3 100644 --- a/src/plugins/search/search.js +++ b/src/plugins/search/search.js @@ -12,7 +12,7 @@ db.version(1).stores({ expires: 'key, value', }); -async function saveData(maxAge, expireKey, indexKey) { +async function saveData(maxAge, expireKey) { INDEXES = Object.values(INDEXES).flatMap(innerData => Object.values(innerData), ); @@ -324,7 +324,7 @@ export async function init(config, vm) { indexKey, ); if (len === ++count) { - await saveData(config.maxAge, expireKey, indexKey); + await saveData(config.maxAge, expireKey); } }, );