Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: remove @orama/plugin-match-highlight in favor of @orama/highlight #545

Merged
merged 5 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 47 additions & 47 deletions packages/docs/public/sitemap-0.xml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/plugin-docusaurus/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
"@algolia/autocomplete-js": "^1.7.2",
"@algolia/autocomplete-theme-classic": "^1.7.3",
"@docusaurus/theme-common": "^2.4.3",
"@orama/highlight": "^0.1.2",
"@orama/orama": "workspace:*",
"@orama/plugin-match-highlight": "workspace:*",
"@orama/plugin-parsedoc": "workspace:*",
"github-slugger": "^2.0.0",
"pako": "^2.1.0",
Expand Down
77 changes: 42 additions & 35 deletions packages/plugin-docusaurus/src/client/theme/SearchBar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
import { autocomplete } from '@algolia/autocomplete-js'
import '@algolia/autocomplete-theme-classic/dist/theme.min.css'
import { autocomplete } from "@algolia/autocomplete-js"
import "@algolia/autocomplete-theme-classic/dist/theme.min.css"
// eslint-disable-next-line @typescript-eslint/ban-ts-comment, @typescript-eslint/prefer-ts-expect-error
// @ts-ignore Will fail in CJS compilation
import { GlobalVersion, useActiveVersion, useVersions } from '@docusaurus/plugin-content-docs/client'
import { useColorMode, useDocsPreferredVersion } from '@docusaurus/theme-common'
import useBaseUrl from '@docusaurus/useBaseUrl'
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
import { usePluginData } from '@docusaurus/useGlobalData'
import useIsBrowser from '@docusaurus/useIsBrowser'
import { create, load, AnyDocument } from '@orama/orama'
import type { OramaWithHighlight, Position } from '@orama/plugin-match-highlight'
import { searchWithHighlight } from '@orama/plugin-match-highlight'
import { ungzip } from 'pako'
import { Fragment, createElement, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { render } from 'react-dom'
import { GlobalVersion, useActiveVersion, useVersions } from "@docusaurus/plugin-content-docs/client"
import { useColorMode, useDocsPreferredVersion } from "@docusaurus/theme-common"
import useBaseUrl from "@docusaurus/useBaseUrl"
import useDocusaurusContext from "@docusaurus/useDocusaurusContext"
import { usePluginData } from "@docusaurus/useGlobalData"
import useIsBrowser from "@docusaurus/useIsBrowser"
import { AnyDocument, create, load, Orama, RawData, search as oramaSearch } from "@orama/orama"
import { Highlight } from "@orama/highlight"
import { ungzip } from "pako"
import { createElement, Fragment, useCallback, useEffect, useMemo, useRef, useState } from "react"
import { render } from "react-dom"
// @ts-expect-error Resolve at runtime
import { SearchNoResults } from '@theme/SearchNoResults'
import { SearchNoResults } from "@theme/SearchNoResults"
// @ts-expect-error Resolve at runtime
import { SearchResults } from '@theme/SearchResults'
import { SearchResults } from "@theme/SearchResults"
// @ts-expect-error Resolve at runtime
import { SearchResult } from '@theme/SearchResult'
import { Hit, INDEX_FILE, PLUGIN_NAME, PluginData, RawDataWithPositions, schema } from '../../../server/types.js'
import { SearchResult } from "@theme/SearchResult"
import { Hit, INDEX_FILE, PLUGIN_NAME, PluginData, schema } from "../../../server/types.js"

const highlighter = new Highlight({
CSSClass: 'aa-ItemContentHighlight',
HTMLTag: 'span',
})

export default function SearchBar(): JSX.Element {
const isBrowser = useIsBrowser()
const { siteConfig } = useDocusaurusContext()
const containerRef = useRef<HTMLDivElement>(null)
const { colorMode } = useColorMode()
const { searchData } = usePluginData(PLUGIN_NAME) as PluginData
const [database, setDatabase] = useState<OramaWithHighlight<AnyDocument>>()
const [database, setDatabase] = useState<Orama<AnyDocument>>()
const searchBaseUrl = useBaseUrl(INDEX_FILE)
const versions = useVersions(undefined)
const activeVersion = useActiveVersion(undefined)
Expand Down Expand Up @@ -79,21 +83,24 @@ export default function SearchBar(): JSX.Element {
{
sourceId: 'orama',
async getItems() {
const results = await searchWithHighlight(database, {
if(!term) {
return []
}

const results = await oramaSearch(database, {
term,
properties: ['sectionTitle', 'sectionContent', 'type']
})

const processed = results.hits.flatMap(hit =>
Object.values((hit as any).positions.sectionContent).flatMap(positions =>
(positions as any).map((position: Position) => ({
...hit,
position
}))
)
)

return processed
return results.hits.flatMap((hit) => {
return {
...hit,
document: {
...hit.document,
sectionContent: highlighter.highlight(hit.document.sectionContent, term).trim(20),
}
}
})
},
getItemUrl({ item }: { item: Hit }) {
return item.document.pageRoute
Expand Down Expand Up @@ -151,13 +158,13 @@ export default function SearchBar(): JSX.Element {
}

const deflated = ungzip(buffer, { to: 'string' })
const data: RawDataWithPositions = JSON.parse(deflated)
const data: RawData = JSON.parse(deflated)

const _db = await create({ schema })
const db = _db as OramaWithHighlight<typeof _db>;
await load(db, data)
db.data.positions = data.positions
setDatabase(db)

await load(_db, data)

setDatabase(_db)
}

if (!isBrowser || !version) {
Expand Down
12 changes: 12 additions & 0 deletions packages/plugin-docusaurus/src/client/theme/SearchBar/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,15 @@
font-size: 0.9em;
color: var(--ifm-color-emphasis-600);
}

.aa-ItemLink {
margin-bottom: .6rem;
text-decoration: none !important;
color: rgba(var(--aa-primary-color-rgb), 1) !important;
padding: calc(var(--aa-spacing-half)/1.2);
}

.aa-ItemContentHighlight {
color: rgba(var(--aa-primary-color-rgb), 1);
font-weight: bold;
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function SearchBarFooter({ translations = {} }: SearchBarFooterProps): JS
navigateDownKeyAriaLabel = 'Arrow down',
closeText = 'to close',
closeKeyAriaLabel = 'Escape key',
searchByText = 'Search by'
searchByText = 'Powered by'
} = translations

const { colorMode } = useColorMode()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,5 @@ a.aa-FooterSearchCredit span {
}

a.aa-FooterSearchCredit svg {
min-width: 8em;
min-width: 7em;
}
40 changes: 5 additions & 35 deletions packages/plugin-docusaurus/src/client/theme/SearchResult/index.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,8 @@
import { Result } from '@orama/orama'
import { Position } from '@orama/plugin-match-highlight'
import { SectionSchema } from '../../../server/types.js'

type Hit = Result<SectionSchema> & { position: Position }
import { Result } from "@orama/orama"
import { SectionSchema } from "../../../server/types.js"

interface SearchResultProps {
hit: Hit
}

function snippet(hit: Hit): JSX.Element {
const PADDING = 20
const PADDING_MARKER = '...'
const isBeginning = hit.position.start < PADDING
const isEnd = hit.position.start + hit.position.length > (hit.document.sectionContent as string).length - PADDING
const preMatch = (hit.document.sectionContent as string).substring(
isBeginning ? 0 : hit.position.start - PADDING,
hit.position.start
)
const match = (hit.document.sectionContent as string).substring(
hit.position.start,
hit.position.start + hit.position.length
)
const postMatch = (hit.document.sectionContent as string).substring(
hit.position.start + hit.position.length,
hit.position.start + hit.position.length + PADDING
)
return (
<p>
{isBeginning ? '' : PADDING_MARKER}
{preMatch}
<u>{match}</u>
{postMatch}
{isEnd ? '' : PADDING_MARKER}
</p>
)
hit: Result<SectionSchema>
}

export function SearchResult({ hit }: SearchResultProps): JSX.Element {
Expand All @@ -44,7 +13,8 @@ export function SearchResult({ hit }: SearchResultProps): JSX.Element {
<div className="aa-ItemContentTitle">
<h5 style={{ marginBottom: 0 }}>{hit.document.sectionTitle as string}</h5>
</div>
<div className="aa-ItemContentDescription">{snippet(hit)}</div>
<div className="aa-ItemContentDescription"
dangerouslySetInnerHTML={{ __html: hit.document.sectionContent }}></div>
</div>
</div>
</a>
Expand Down
19 changes: 5 additions & 14 deletions packages/plugin-docusaurus/src/server/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { LoadedContent, LoadedVersion } from '@docusaurus/plugin-content-docs'
import type { LoadContext, Plugin } from '@docusaurus/types'
import { create, insertMultiple, save } from '@orama/orama'
import { OramaWithHighlight, afterInsert as highlightAfterInsert } from '@orama/plugin-match-highlight'
import type { DefaultSchemaElement, NodeContent, PopulateFnContext } from '@orama/plugin-parsedoc'
import { defaultHtmlSchema, populate } from '@orama/plugin-parsedoc'
import * as githubSlugger from 'github-slugger'
Expand All @@ -13,9 +12,9 @@ import { gzip as gzipCB } from 'node:zlib'
import type { Configuration as WebpackConfiguration } from 'webpack'

import { retrieveTranslationMessages } from './translationMessages.js'
import { INDEX_FILE, PLUGIN_NAME, PluginOptions, RawDataWithPositions, SectionSchema, schema } from './types.js'
import { INDEX_FILE, PLUGIN_NAME, PluginOptions, SectionSchema, schema } from './types.js'

export type { PluginData, PluginOptions, RawDataWithPositions, SectionSchema } from './types.js'
export type { PluginData, PluginOptions, SectionSchema } from './types.js'

const gzip = promisify(gzipCB)

Expand Down Expand Up @@ -146,20 +145,12 @@ async function buildDevSearchData(siteDir: string, outDir: string, allContent: a

// Create the Orama database and then serialize it
const _db = await create({
schema,
plugins: [
{
name: 'highlight',
afterInsert: highlightAfterInsert
}
]
schema
})
const db = _db as OramaWithHighlight<typeof _db>

await insertMultiple(db, documents)
await insertMultiple(_db, documents)

const serialized = (await save(db)) as RawDataWithPositions
serialized.positions = db.data.positions
const serialized = (await save(_db))

await writeFile(indexPath(outDir, version), await gzip(JSON.stringify(serialized)))
}
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-docusaurus/src/server/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Result } from '@orama/orama'
import type { Position } from '@orama/plugin-match-highlight'
import type { Position } from '@orama/highlight'

import type { AnyDocument, AnySchema, RawData } from '@orama/orama'

Expand Down
21 changes: 7 additions & 14 deletions packages/plugin-docusaurus/test/integration.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { AnyOrama, TypedDocument, create, load } from '@orama/orama'
import { OramaWithHighlight, SearchResultWithHighlight, searchWithHighlight } from '@orama/plugin-match-highlight'
import { create, load, search } from "@orama/orama"
import assert from 'node:assert'
import { exec, ExecException } from 'node:child_process'
import { existsSync } from 'node:fs'
Expand Down Expand Up @@ -28,10 +27,6 @@ async function cleanup(): Promise<void> {
await rm(sandbox, { force: true, recursive: true })
}

function search<T extends AnyOrama, ResultDocument = TypedDocument<T>>(database: OramaWithHighlight<T>, term: string): Promise<SearchResultWithHighlight<ResultDocument>> {
return searchWithHighlight(database, { term, properties: ['sectionTitle', 'sectionContent', 'type'] })
}

async function execute(command: string, cwd?: string): Promise<Execution> {
const { HOME, PATH } = process.env
const env = cwd ? { HOME, PATH } : process.env
Expand Down Expand Up @@ -94,31 +89,29 @@ await test('generated DBs have indexed pages content', async () => {
const rawData = gunzipSync(rawCompressedData).toString('utf-8')
const data = JSON.parse(rawData)

const _database = await create({ schema })
const database = _database as OramaWithHighlight<typeof _database>;
const database = await create({ schema })
await load(database, data)
database.data.positions = data.positions

// Search results seem reasonable
const indexSearchResult = await search(database, 'index')
const indexSearchResult = await search(database, { term: 'index', properties: ['sectionTitle', 'sectionContent', 'type'] })
assert.ok(indexSearchResult.count === 1)
assert.ok(indexSearchResult.hits[0].document.pageRoute === '/#main')

const catSearchResult = await search(database, 'cat')
const catSearchResult = await search(database, { term: 'cat', properties: ['sectionTitle', 'sectionContent', 'type'] })
assert.ok(catSearchResult.count === 1)
assert.ok(catSearchResult.hits[0].document.pageRoute === '/animals_cat')

const dogSearchResult = await search(database, 'dog')
const dogSearchResult = await search(database, { term: 'dog', properties: ['sectionTitle', 'sectionContent', 'type'] })
assert.ok(dogSearchResult.count === 2)
assert.ok(dogSearchResult.hits[0].document.pageRoute === '/animals_dog#dog')

const domesticSearchResult = await search(database, 'domestic')
const domesticSearchResult = await search(database, { term: 'domestic', properties: ['sectionTitle', 'sectionContent', 'type'] })
assert.ok(domesticSearchResult.count === 2)
assert.ok(domesticSearchResult.hits[0].document.pageRoute === '/animals_cat')
assert.ok(domesticSearchResult.hits[1].document.pageRoute === '/animals_dog#dog')

// We do not have content about turtles
const turtleSearchResult = await search(database, 'turtle')
const turtleSearchResult = await search(database, { term: 'turtle', properties: ['sectionTitle', 'sectionContent', 'type'] })
assert.ok(turtleSearchResult.count === 0)
})

Expand Down
17 changes: 14 additions & 3 deletions pnpm-lock.yaml

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