Skip to content

Commit 5a241b9

Browse files
authored
Merge pull request #469 from easyops-cn/steve/webworker
feat: move search to Web Worker
2 parents 3f28255 + 15b7fba commit 5a241b9

File tree

8 files changed

+249
-200
lines changed

8 files changed

+249
-200
lines changed

docusaurus-search-local/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"@node-rs/jieba": "^1.6.0",
4040
"cheerio": "^1.0.0",
4141
"clsx": "^1.1.1",
42+
"comlink": "^4.4.2",
4243
"debug": "^4.2.0",
4344
"fs-extra": "^10.0.0",
4445
"klaw-sync": "^6.0.0",

docusaurus-search-local/src/client/theme/SearchBar/SearchBar.tsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,11 @@ import {
1616
} from "@docusaurus/theme-common";
1717
import { useActivePlugin } from "@docusaurus/plugin-content-docs/client";
1818

19-
import { fetchIndexes } from "./fetchIndexes";
20-
import { SearchSourceFactory } from "../../utils/SearchSourceFactory";
19+
import { fetchIndexesByWorker, searchByWorker } from "../searchByWorker";
2120
import { SuggestionTemplate } from "./SuggestionTemplate";
2221
import { EmptyTemplate } from "./EmptyTemplate";
2322
import { SearchResult } from "../../../shared/interfaces";
2423
import {
25-
searchResultLimits,
2624
Mark,
2725
searchBarShortcut,
2826
searchBarShortcutHint,
@@ -149,9 +147,9 @@ export default function SearchBar({
149147
search.current?.autocomplete.destroy();
150148
setLoading(true);
151149

152-
const [{ wrappedIndexes, zhDictionary }, autoComplete] = await Promise.all([
153-
fetchIndexes(versionUrl, searchContext),
150+
const [autoComplete] = await Promise.all([
154151
fetchAutoCompleteJS(),
152+
fetchIndexesByWorker(versionUrl, searchContext),
155153
]);
156154

157155
const searchFooterLinkElement = ({
@@ -256,11 +254,17 @@ export default function SearchBar({
256254
},
257255
[
258256
{
259-
source: SearchSourceFactory(
260-
wrappedIndexes,
261-
zhDictionary,
262-
searchResultLimits
263-
),
257+
source: async (
258+
input: string,
259+
callback: (output: SearchResult[]) => void
260+
) => {
261+
const result = await searchByWorker(
262+
versionUrl,
263+
searchContext,
264+
input
265+
);
266+
callback(result);
267+
},
264268
templates: {
265269
suggestion: SuggestionTemplate,
266270
empty: EmptyTemplate,

docusaurus-search-local/src/client/theme/SearchBar/fetchIndexes.spec.ts

Lines changed: 0 additions & 84 deletions
This file was deleted.

docusaurus-search-local/src/client/theme/SearchBar/fetchIndexes.ts

Lines changed: 0 additions & 84 deletions
This file was deleted.

docusaurus-search-local/src/client/theme/SearchPage/SearchPage.tsx

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ import { usePluralForm } from "@docusaurus/theme-common";
88
import clsx from "clsx";
99

1010
import useSearchQuery from "../hooks/useSearchQuery";
11-
import { fetchIndexes } from "../SearchBar/fetchIndexes";
12-
import { SearchSourceFactory } from "../../utils/SearchSourceFactory";
11+
import { fetchIndexesByWorker, searchByWorker } from "../searchByWorker";
1312
import {
1413
SearchDocument,
1514
SearchDocumentType,
@@ -52,10 +51,6 @@ function SearchPageContent(): React.ReactElement {
5251
updateSearchContext,
5352
} = useSearchQuery();
5453
const [searchQuery, setSearchQuery] = useState(searchValue);
55-
const [searchSource, setSearchSource] =
56-
useState<
57-
(input: string, callback: (results: SearchResult[]) => void) => void
58-
>();
5954
const [searchResults, setSearchResults] = useState<SearchResult[]>();
6055
const versionUrl = `${baseUrl}${searchVersion}`;
6156

@@ -83,19 +78,22 @@ function SearchPageContent(): React.ReactElement {
8378
useEffect(() => {
8479
updateSearchPath(searchQuery);
8580

86-
if (searchSource) {
87-
if (searchQuery) {
88-
searchSource(searchQuery, (results) => {
89-
setSearchResults(results);
90-
});
91-
} else {
92-
setSearchResults(undefined);
93-
}
81+
if (searchQuery) {
82+
(async () => {
83+
const results = await searchByWorker(
84+
versionUrl,
85+
searchContext,
86+
searchQuery
87+
);
88+
setSearchResults(results);
89+
})();
90+
} else {
91+
setSearchResults(undefined);
9492
}
9593

9694
// `updateSearchPath` should not be in the deps,
9795
// otherwise will cause call stack overflow.
98-
}, [searchQuery, searchSource]);
96+
}, [searchQuery, versionUrl, searchContext]);
9997

10098
const handleSearchInputChange = useCallback(
10199
(e: React.ChangeEvent<HTMLInputElement>) => {
@@ -110,17 +108,18 @@ function SearchPageContent(): React.ReactElement {
110108
}
111109
}, [searchValue]);
112110

111+
const [searchWorkerReady, setSearchWorkerReady] = useState(false);
112+
113113
useEffect(() => {
114114
async function doFetchIndexes() {
115-
const { wrappedIndexes, zhDictionary } =
115+
if (
116116
!Array.isArray(searchContextByPaths) ||
117117
searchContext ||
118118
useAllContextsWithNoSearchContext
119-
? await fetchIndexes(versionUrl, searchContext)
120-
: { wrappedIndexes: [], zhDictionary: [] };
121-
setSearchSource(() =>
122-
SearchSourceFactory(wrappedIndexes, zhDictionary, 100)
123-
);
119+
) {
120+
await fetchIndexesByWorker(versionUrl, searchContext);
121+
}
122+
setSearchWorkerReady(true);
124123
}
125124
doFetchIndexes();
126125
}, [searchContext, versionUrl]);
@@ -198,7 +197,7 @@ function SearchPageContent(): React.ReactElement {
198197
) : null}
199198
</div>
200199

201-
{!searchSource && searchQuery && (
200+
{!searchWorkerReady && searchQuery && (
202201
<div>
203202
<LoadingRing />
204203
</div>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import * as Comlink from "comlink";
2+
import { SearchResult } from "../../shared/interfaces";
3+
4+
interface RemoteWorker {
5+
fetchIndexes(baseUrl: string, searchContext: string): Promise<void>;
6+
search(
7+
baseUrl: string,
8+
searchContext: string,
9+
input: string
10+
): Promise<SearchResult[]>;
11+
}
12+
13+
let remoteWorkerPromise: Promise<RemoteWorker> | undefined;
14+
15+
function getRemoteWorker() {
16+
if (!remoteWorkerPromise) {
17+
remoteWorkerPromise = (async () => {
18+
const Remote = Comlink.wrap(
19+
new Worker(new URL("./worker.js", import.meta.url))
20+
) as any;
21+
return await new Remote();
22+
})();
23+
}
24+
return remoteWorkerPromise;
25+
}
26+
27+
export async function fetchIndexesByWorker(
28+
baseUrl: string,
29+
searchContext: string
30+
): Promise<void> {
31+
if (process.env.NODE_ENV === "production") {
32+
const remoteWorker = await getRemoteWorker();
33+
await remoteWorker!.fetchIndexes(baseUrl, searchContext);
34+
}
35+
}
36+
37+
export async function searchByWorker(
38+
baseUrl: string,
39+
searchContext: string,
40+
input: string
41+
): Promise<SearchResult[]> {
42+
if (process.env.NODE_ENV === "production") {
43+
const remoteWorker = await getRemoteWorker();
44+
return remoteWorker!.search(baseUrl, searchContext, input);
45+
}
46+
return [];
47+
}

0 commit comments

Comments
 (0)