diff --git a/docusaurus-search-local/package.json b/docusaurus-search-local/package.json index e729a45c..3ea7ba6f 100644 --- a/docusaurus-search-local/package.json +++ b/docusaurus-search-local/package.json @@ -23,6 +23,7 @@ }, "license": "MIT", "dependencies": { + "@docusaurus/plugin-content-docs": "^2.0.0-beta.20", "@docusaurus/theme-common": "^2.0.0-beta.20", "@docusaurus/theme-translations": "^2.0.0-beta.20", "@docusaurus/utils": "^2.0.0-beta.20", diff --git a/docusaurus-search-local/src/client/theme/SearchBar/SearchBar.tsx b/docusaurus-search-local/src/client/theme/SearchBar/SearchBar.tsx index 700949c8..10242b28 100644 --- a/docusaurus-search-local/src/client/theme/SearchBar/SearchBar.tsx +++ b/docusaurus-search-local/src/client/theme/SearchBar/SearchBar.tsx @@ -10,6 +10,7 @@ import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import ExecutionEnvironment from "@docusaurus/ExecutionEnvironment"; import { useHistory, useLocation } from "@docusaurus/router"; import { translate } from "@docusaurus/Translate"; +import { useActiveVersion } from '@docusaurus/plugin-content-docs/client'; import { fetchIndexes } from "./fetchIndexes"; import { SearchSourceFactory } from "../../utils/SearchSourceFactory"; @@ -44,9 +45,13 @@ interface SearchBarProps { export default function SearchBar({ handleSearchBarToggle, }: SearchBarProps): ReactElement { - const { + let { siteConfig: { baseUrl }, } = useDocusaurusContext(); + const activeVersion = useActiveVersion(); + if (activeVersion && !activeVersion.isLast) { + baseUrl = activeVersion.path + "/"; + } const history = useHistory(); const location = useLocation(); const searchBarRef = useRef(null); diff --git a/docusaurus-search-local/src/server/utils/postBuildFactory.ts b/docusaurus-search-local/src/server/utils/postBuildFactory.ts index deaf60f7..faffefa9 100644 --- a/docusaurus-search-local/src/server/utils/postBuildFactory.ts +++ b/docusaurus-search-local/src/server/utils/postBuildFactory.ts @@ -17,21 +17,23 @@ export function postBuildFactory(config: ProcessedPluginOptions) { debugInfo("parsing documents"); - // Give every index entry a unique id so that the index does not need to store long URLs. - const allDocuments = await scanDocuments(data); + for (let versionData of data) { + // Give every index entry a unique id so that the index does not need to store long URLs. + const allDocuments = await scanDocuments(versionData.paths); - debugInfo("building index"); + debugInfo("building index"); - const searchIndex = buildIndex(allDocuments, config); + const searchIndex = buildIndex(allDocuments, config); - debugInfo("writing index to disk"); + debugInfo("writing index to disk"); - await writeFileAsync( - path.join(buildData.outDir, "search-index.json"), - JSON.stringify(searchIndex), - { encoding: "utf8" } - ); + await writeFileAsync( + path.join(versionData.outDir, "search-index.json"), + JSON.stringify(searchIndex), + { encoding: "utf8" } + ); - debugInfo("index written to disk successfully!"); + debugInfo("index written to disk successfully!"); + } }; } diff --git a/docusaurus-search-local/src/server/utils/processDocInfos.spec.ts b/docusaurus-search-local/src/server/utils/processDocInfos.spec.ts index 276bdae8..f13af57f 100644 --- a/docusaurus-search-local/src/server/utils/processDocInfos.spec.ts +++ b/docusaurus-search-local/src/server/utils/processDocInfos.spec.ts @@ -47,19 +47,24 @@ describe("processDocInfos", () => { }, [ { - filePath: "/build/docs/a/index.html", - type: "docs", - url: "/base/docs/a", - }, - { - filePath: "/build/blog/b/index.html", - type: "blog", - url: "/base/blog/b", - }, - { - filePath: "/build/page/index.html", - type: "page", - url: "/base/page", + outDir: "/build", + paths: [ + { + filePath: "/build/docs/a/index.html", + type: "docs", + url: "/base/docs/a", + }, + { + filePath: "/build/blog/b/index.html", + type: "blog", + url: "/base/blog/b", + }, + { + filePath: "/build/page/index.html", + type: "page", + url: "/base/page", + }, + ], }, ], ], @@ -112,19 +117,24 @@ describe("processDocInfos", () => { }, [ { - filePath: "/build/docs/a.html", - type: "docs", - url: "/base/docs/a", - }, - { - filePath: "/build/blog/b.html", - type: "blog", - url: "/base/blog/b", - }, - { - filePath: "/build/page.html", - type: "page", - url: "/base/page", + outDir: "/build", + paths: [ + { + filePath: "/build/docs/a.html", + type: "docs", + url: "/base/docs/a", + }, + { + filePath: "/build/blog/b.html", + type: "blog", + url: "/base/blog/b", + }, + { + filePath: "/build/page.html", + type: "page", + url: "/base/page", + }, + ], }, ], ], @@ -177,19 +187,24 @@ describe("processDocInfos", () => { }, [ { - filePath: "/build/docs/a/index.html", - type: "docs", - url: "/base/docs/a/", - }, - { - filePath: "/build/blog/b/index.html", - type: "blog", - url: "/base/blog/b/", - }, - { - filePath: "/build/page/index.html", - type: "page", - url: "/base/page/", + outDir: "/build", + paths: [ + { + filePath: "/build/docs/a/index.html", + type: "docs", + url: "/base/docs/a/", + }, + { + filePath: "/build/blog/b/index.html", + type: "blog", + url: "/base/blog/b/", + }, + { + filePath: "/build/page/index.html", + type: "page", + url: "/base/page/", + }, + ], }, ], ], @@ -226,24 +241,29 @@ describe("processDocInfos", () => { }, [ { - filePath: "/build/index.html", - type: "docs", - url: "/base/", - }, - { - filePath: "/build/docs-a/index.html", - type: "docs", - url: "/base/docs-a", - }, - { - filePath: "/build/docs-b/c/index.html", - type: "docs", - url: "/base/docs-b/c", - }, - { - filePath: "/build/page/index.html", - type: "docs", - url: "/base/page", + outDir: "/build", + paths: [ + { + filePath: "/build/index.html", + type: "docs", + url: "/base/", + }, + { + filePath: "/build/docs-a/index.html", + type: "docs", + url: "/base/docs-a", + }, + { + filePath: "/build/docs-b/c/index.html", + type: "docs", + url: "/base/docs-b/c", + }, + { + filePath: "/build/page/index.html", + type: "docs", + url: "/base/page", + }, + ], }, ], ], @@ -280,19 +300,24 @@ describe("processDocInfos", () => { }, [ { - filePath: "/build/blog-a/index.html", - type: "blog", - url: "/base/blog-a", - }, - { - filePath: "/build/blog-b/c/index.html", - type: "blog", - url: "/base/blog-b/c", - }, - { - filePath: "/build/page/index.html", - type: "blog", - url: "/base/page", + outDir: "/build", + paths: [ + { + filePath: "/build/blog-a/index.html", + type: "blog", + url: "/base/blog-a", + }, + { + filePath: "/build/blog-b/c/index.html", + type: "blog", + url: "/base/blog-b/c", + }, + { + filePath: "/build/page/index.html", + type: "blog", + url: "/base/page", + }, + ], }, ], ], diff --git a/docusaurus-search-local/src/server/utils/processDocInfos.ts b/docusaurus-search-local/src/server/utils/processDocInfos.ts index d459888c..f8ab8cf7 100644 --- a/docusaurus-search-local/src/server/utils/processDocInfos.ts +++ b/docusaurus-search-local/src/server/utils/processDocInfos.ts @@ -2,12 +2,14 @@ import path from "path"; import { DocInfoWithFilePath, DocInfoWithRoute, + VersionDocInfo, ProcessedPluginOptions, PostBuildData, } from "../../shared/interfaces"; +import { LoadedContent, LoadedVersion } from "@docusaurus/plugin-content-docs" export function processDocInfos( - { routesPaths, outDir, baseUrl, siteConfig }: PostBuildData, + { routesPaths, outDir, baseUrl, siteConfig, plugins }: PostBuildData, { indexDocs, indexBlog, @@ -16,76 +18,111 @@ export function processDocInfos( blogRouteBasePath, ignoreFiles, }: ProcessedPluginOptions -): DocInfoWithFilePath[] { - return routesPaths - .map((url: string) => { - // istanbul ignore next - if (!url.startsWith(baseUrl)) { - throw new Error( - `The route must start with the baseUrl "${baseUrl}", but was "${url}". This is a bug, please report it.` - ); +): VersionDocInfo[] { + const emptySet = new Set(); + let versionData: any = [{ versionOutDir: outDir, docs: emptySet }]; + if (plugins) { + const docsPluginData = plugins.find(element => element.name === "docusaurus-plugin-content-docs"); + if (docsPluginData) { + versionData = []; + const loadedVersions:LoadedVersion[] = (docsPluginData.content as LoadedContent).loadedVersions; + for (const loadedVersion of loadedVersions) { + let docs = new Set(); + for (const doc of loadedVersion.docs) { + docs.add(doc.permalink); + } + const route = loadedVersion.path.substr(baseUrl.length); + let versionOutDir = outDir; + // The last versions search-index should always be placed in the root since it is the one used from non-docs pages + if (!loadedVersion.isLast) { + versionOutDir = path.join(outDir, ...route.split("/").filter((i: string) => i)); + } + versionData.push({ versionOutDir, docs }); } - const route = url.substr(baseUrl.length).replace(/\/$/, ""); + } + } - // Do not index homepage, error page and search page. - if ( - ((!docsRouteBasePath || docsRouteBasePath[0] !== "") && route === "") || - route === "404.html" || - route === "search" - ) { - return; - } + // Create a list of files to index per document version. This will always include all pages and blogs. + let result = []; + for (const { versionOutDir, docs } of versionData) { + const versionPaths = routesPaths + .map((url: string) => { + // istanbul ignore next + if (!url.startsWith(baseUrl)) { + throw new Error( + `The route must start with the baseUrl "${baseUrl}", but was "${url}". This is a bug, please report it.` + ); + } + const route = url.substr(baseUrl.length).replace(/\/$/, ""); - // ignore files - if ( - ignoreFiles?.some((reg: RegExp | string) => { - if (typeof reg === "string") { - return route === reg; - } - return route.match(reg); - }) - ) { - return; - } + // Do not index homepage, error page and search page. + if ( + ((!docsRouteBasePath || docsRouteBasePath[0] !== "") && route === "") || + route === "404.html" || + route === "search" + ) { + return; + } - if ( - indexBlog && - blogRouteBasePath.some((basePath) => isSameOrSubRoute(route, basePath)) - ) { + // ignore files if ( - blogRouteBasePath.some( - (basePath) => - isSameRoute(route, basePath) || - isSameOrSubRoute(route, path.posix.join(basePath, "tags")) - ) + ignoreFiles?.some((reg: RegExp | string) => { + if (typeof reg === "string") { + return route === reg; + } + return route.match(reg); + }) ) { - // Do not index list of blog posts and tags filter pages return; } - return { route, url, type: "blog" }; - } - if ( - indexDocs && - docsRouteBasePath.some((basePath) => isSameOrSubRoute(route, basePath)) - ) { - return { route, url, type: "docs" }; - } - if (indexPages) { - return { route, url, type: "page" }; - } - return; - }) - .filter(Boolean as any) - .map(({ route, url, type }) => ({ - filePath: path.join( - outDir, - siteConfig.trailingSlash === false - ? `${route}.html` - : `${route}/index.html` - ), - url, - type, - })); + + if ( + indexBlog && + blogRouteBasePath.some((basePath) => isSameOrSubRoute(route, basePath)) + ) { + if ( + blogRouteBasePath.some( + (basePath) => + isSameRoute(route, basePath) || + isSameOrSubRoute(route, path.posix.join(basePath, "tags")) + ) + ) { + // Do not index list of blog posts and tags filter pages + return; + } + return { route, url, type: "blog" }; + } + if ( + indexDocs && + docsRouteBasePath.some((basePath) => isSameOrSubRoute(route, basePath)) + ) { + if (docs.size === 0 || docs.has(url)) { + return { route, url, type: "docs" }; + } + return; + } + if (indexPages) { + return { route, url, type: "page" }; + } + return; + }) + .filter(Boolean as any) + .map(({ route, url, type }) => ({ + filePath: path.join( + outDir, + siteConfig.trailingSlash === false + ? `${route}.html` + : `${route}/index.html` + ), + url, + type, + })); + if (versionPaths.length > 0) { + result.push({ outDir: versionOutDir, paths: versionPaths }); + } + } + + return result; } function isSameRoute(routeA: string, routeB: string): boolean { diff --git a/docusaurus-search-local/src/shared/interfaces.ts b/docusaurus-search-local/src/shared/interfaces.ts index ab5465d8..934e8d5b 100644 --- a/docusaurus-search-local/src/shared/interfaces.ts +++ b/docusaurus-search-local/src/shared/interfaces.ts @@ -1,4 +1,4 @@ -import { DocusaurusConfig } from "@docusaurus/types"; +import { DocusaurusConfig, LoadedPlugin } from "@docusaurus/types"; import lunr from "lunr"; export type SmartTerm = SmartTermItem[]; @@ -128,6 +128,11 @@ export interface DocInfoWithFilePath { type: DocInfoType; } +export interface VersionDocInfo { + outDir: string; + paths: DocInfoWithFilePath[]; +} + export type DocInfoType = "docs" | "blog" | "page"; export interface PluginOptions { @@ -190,6 +195,7 @@ export interface PostBuildData { outDir: string; baseUrl: string; siteConfig: DocusaurusConfig; + plugins: LoadedPlugin[]; } export interface DocusaurusContext { diff --git a/yarn.lock b/yarn.lock index af8b40e0..8bf55a10 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1825,7 +1825,7 @@ __metadata: languageName: node linkType: hard -"@docusaurus/plugin-content-docs@npm:2.0.0-beta.20": +"@docusaurus/plugin-content-docs@npm:2.0.0-beta.20, @docusaurus/plugin-content-docs@npm:^2.0.0-beta.20": version: 2.0.0-beta.20 resolution: "@docusaurus/plugin-content-docs@npm:2.0.0-beta.20" dependencies: @@ -2128,6 +2128,7 @@ __metadata: resolution: "@easyops-cn/docusaurus-search-local@workspace:docusaurus-search-local" dependencies: "@docusaurus/module-type-aliases": ^2.0.0-beta.20 + "@docusaurus/plugin-content-docs": ^2.0.0-beta.20 "@docusaurus/theme-common": ^2.0.0-beta.20 "@docusaurus/theme-translations": ^2.0.0-beta.20 "@docusaurus/types": ^2.0.0-beta.20