From 80cf2650aa5fa4b49093509f60766cc5b28c19bc Mon Sep 17 00:00:00 2001
From: T <6601329+cookesan@users.noreply.github.com>
Date: Sun, 28 Jun 2026 07:23:29 -0300
Subject: [PATCH 01/29] fix: index rewritten local search pages by locale
(#5241)
---
.../node/plugins/localSearchPlugin.test.ts | 102 ++++++++++++++++++
src/node/plugins/localSearchPlugin.ts | 5 +-
2 files changed, 106 insertions(+), 1 deletion(-)
create mode 100644 __tests__/unit/node/plugins/localSearchPlugin.test.ts
diff --git a/__tests__/unit/node/plugins/localSearchPlugin.test.ts b/__tests__/unit/node/plugins/localSearchPlugin.test.ts
new file mode 100644
index 00000000..c71d628f
--- /dev/null
+++ b/__tests__/unit/node/plugins/localSearchPlugin.test.ts
@@ -0,0 +1,102 @@
+import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'
+import { tmpdir } from 'node:os'
+import path from 'node:path'
+import { resolveConfig } from 'node/config'
+import { localSearchPlugin } from 'node/plugins/localSearchPlugin'
+import MiniSearch from 'minisearch'
+
+describe('node/plugins/localSearchPlugin', () => {
+ let root: string | undefined
+ let nodeEnv: string | undefined
+
+ beforeEach(() => {
+ nodeEnv = process.env.NODE_ENV
+ process.env.NODE_ENV = 'production'
+ })
+
+ afterEach(async () => {
+ if (nodeEnv === undefined) {
+ delete process.env.NODE_ENV
+ } else {
+ process.env.NODE_ENV = nodeEnv
+ }
+
+ if (root) {
+ await rm(root, { recursive: true, force: true })
+ root = undefined
+ }
+ })
+
+ test('indexes rewritten pages by rewritten locale path', async () => {
+ root = await mkdtemp(path.join(tmpdir(), 'vitepress-local-search-'))
+ const configDir = path.join(root, '.vitepress')
+ await mkdir(configDir)
+
+ await writeFile(
+ path.join(root, 'index.md'),
+ '# English home\n\nrootonlytoken\n'
+ )
+ await writeFile(
+ path.join(root, 'zh.md'),
+ '# Chinese home\n\nlocaleonlytoken\n'
+ )
+ await writeFile(
+ path.join(configDir, 'config.ts'),
+ [
+ 'export default {',
+ ' rewrites: {',
+ " 'index.md': 'guide.md',",
+ " 'zh.md': 'zh/guide.md'",
+ ' },',
+ ' locales: {',
+ " root: { label: 'English', lang: 'en' },",
+ " zh: { label: 'Chinese', lang: 'zh' }",
+ ' },',
+ ' themeConfig: {',
+ " search: { provider: 'local' }",
+ ' }',
+ '}'
+ ].join('\n')
+ )
+
+ const siteConfig = await resolveConfig(root, 'build', 'production')
+ const plugin = await localSearchPlugin(siteConfig)
+
+ const indexModule = (await plugin.load?.call(
+ {} as never,
+ '/@localSearchIndex'
+ )) as string
+
+ expect(indexModule).toContain(
+ '"root": () => import(\'@localSearchIndexroot\')'
+ )
+ expect(indexModule).toContain('"zh": () => import(\'@localSearchIndexzh\')')
+
+ const rootIndex = loadIndex(
+ (await plugin.load?.call({} as never, '/@localSearchIndexroot')) as string
+ )
+ const zhIndex = loadIndex(
+ (await plugin.load?.call({} as never, '/@localSearchIndexzh')) as string
+ )
+
+ expect(rootIndex.search('rootonlytoken')).toMatchObject([
+ { id: '/guide.html#english-home' }
+ ])
+ expect(rootIndex.search('localeonlytoken')).toEqual([])
+
+ expect(zhIndex.search('localeonlytoken')).toMatchObject([
+ { id: '/zh/guide.html#chinese-home' }
+ ])
+ expect(zhIndex.search('rootonlytoken')).toEqual([])
+ })
+})
+
+function loadIndex(serializedModule: string) {
+ const serializedIndex = JSON.parse(
+ serializedModule.slice('export default '.length)
+ )
+ return MiniSearch.loadJSON(serializedIndex, {
+ fields: ['title', 'titles', 'text'],
+ storeFields: ['title', 'titles']
+ })
+}
diff --git a/src/node/plugins/localSearchPlugin.ts b/src/node/plugins/localSearchPlugin.ts
index 0af42dac..3c260e20 100644
--- a/src/node/plugins/localSearchPlugin.ts
+++ b/src/node/plugins/localSearchPlugin.ts
@@ -116,7 +116,10 @@ export async function localSearchPlugin(
const file = path.join(siteConfig.srcDir, page)
// get file metadata
const fileId = getDocId(file)
- const locale = getLocaleForPath(siteConfig.site, page)
+ const locale = getLocaleForPath(
+ siteConfig.site,
+ siteConfig.rewrites.map[page] || page
+ )
const index = getIndexByLocale(locale)
// retrieve file and split into "sections"
const html = await render(file)
From d0159c8a850cbd2a010a3d44bdeb97c3db651d0e Mon Sep 17 00:00:00 2001
From: T <6601329+cookesan@users.noreply.github.com>
Date: Sun, 28 Jun 2026 07:23:59 -0300
Subject: [PATCH 02/29] feat: support social link target option (#5242)
---
__tests__/e2e/.vitepress/config.ts | 8 ++++++++
__tests__/e2e/home.test.ts | 9 +++++++++
docs/en/reference/default-theme-config.md | 2 ++
src/client/theme-default/components/VPSocialLink.vue | 3 ++-
src/client/theme-default/components/VPSocialLinks.vue | 3 ++-
types/default-theme.d.ts | 1 +
6 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/__tests__/e2e/.vitepress/config.ts b/__tests__/e2e/.vitepress/config.ts
index 121761e7..441eda1c 100644
--- a/__tests__/e2e/.vitepress/config.ts
+++ b/__tests__/e2e/.vitepress/config.ts
@@ -162,6 +162,14 @@ export default defineConfig({
themeConfig: {
nav,
sidebar,
+ socialLinks: [
+ {
+ icon: 'github',
+ link: '/home',
+ ariaLabel: 'Home social link',
+ target: '_self'
+ }
+ ],
search: {
provider: 'local',
options: {
diff --git a/__tests__/e2e/home.test.ts b/__tests__/e2e/home.test.ts
index 76868361..b6bd6ff9 100644
--- a/__tests__/e2e/home.test.ts
+++ b/__tests__/e2e/home.test.ts
@@ -32,4 +32,13 @@ describe('render correct content', async () => {
const outlineLinksCount = await outlineLinksLocator.count()
expect(outlineLinksCount).toEqual(4)
})
+
+ test('social link target override', async () => {
+ const socialLink = page.locator(
+ '.VPNavBarSocialLinks a[aria-label="Home social link"]'
+ )
+
+ expect(await socialLink.getAttribute('href')).toBe('/home')
+ expect(await socialLink.getAttribute('target')).toBe('_self')
+ })
})
diff --git a/docs/en/reference/default-theme-config.md b/docs/en/reference/default-theme-config.md
index b515cb45..cc4ffd0e 100644
--- a/docs/en/reference/default-theme-config.md
+++ b/docs/en/reference/default-theme-config.md
@@ -253,6 +253,7 @@ export default {
// You can add any icon from simple-icons (https://simpleicons.org/):
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' },
{ icon: 'twitter', link: '...' },
+ { icon: 'discord', link: '/community', target: '_self' },
// You can also add custom icons by passing SVG as string:
{
icon: {
@@ -272,6 +273,7 @@ interface SocialLink {
icon: string | { svg: string }
link: string
ariaLabel?: string
+ target?: string
}
```
diff --git a/src/client/theme-default/components/VPSocialLink.vue b/src/client/theme-default/components/VPSocialLink.vue
index 2a016462..7e441ebb 100644
--- a/src/client/theme-default/components/VPSocialLink.vue
+++ b/src/client/theme-default/components/VPSocialLink.vue
@@ -7,6 +7,7 @@ const props = defineProps<{
icon: DefaultTheme.SocialLinkIcon
link: string
ariaLabel?: string
+ target?: string
me: boolean
}>()
@@ -45,7 +46,7 @@ if (import.meta.env.SSR) {
class="VPSocialLink no-icon"
:href="link"
:aria-label="ariaLabel ?? (typeof icon === 'string' ? icon : '')"
- target="_blank"
+ :target="target ?? '_blank'"
:rel="me ? 'me noopener' : 'noopener'"
v-html="svg"
>
diff --git a/src/client/theme-default/components/VPSocialLinks.vue b/src/client/theme-default/components/VPSocialLinks.vue
index b188fb89..062f7f62 100644
--- a/src/client/theme-default/components/VPSocialLinks.vue
+++ b/src/client/theme-default/components/VPSocialLinks.vue
@@ -13,11 +13,12 @@ withDefaults(defineProps<{
diff --git a/types/default-theme.d.ts b/types/default-theme.d.ts
index ae3c2c71..1d4f4f85 100644
--- a/types/default-theme.d.ts
+++ b/types/default-theme.d.ts
@@ -318,6 +318,7 @@ export namespace DefaultTheme {
icon: SocialLinkIcon
link: string
ariaLabel?: string
+ target?: string
}
export type SocialLinkIcon = string | { svg: string }
From 8288785d5aaa8576fd48d4b4c5633a8fe0832bce Mon Sep 17 00:00:00 2001
From: T <6601329+cookesan@users.noreply.github.com>
Date: Sun, 28 Jun 2026 07:27:50 -0300
Subject: [PATCH 03/29] test: wait for filtered local search results (#5244)
---
__tests__/e2e/local-search/local-search.test.ts | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/__tests__/e2e/local-search/local-search.test.ts b/__tests__/e2e/local-search/local-search.test.ts
index 6b6df97d..71915d4a 100644
--- a/__tests__/e2e/local-search/local-search.test.ts
+++ b/__tests__/e2e/local-search/local-search.test.ts
@@ -9,9 +9,18 @@ describe('local search', () => {
const input = await page.waitForSelector('input#localsearch-input')
await input.type('local')
- await page.waitForSelector('ul#localsearch-list', { state: 'visible' })
-
const searchResults = page.locator('#localsearch-list')
+ await page.waitForFunction(() => {
+ const options = [
+ ...document.querySelectorAll('#localsearch-list li[role=option]')
+ ]
+
+ return (
+ options.length === 1 &&
+ options[0].textContent?.includes('Local search included')
+ )
+ })
+
expect(await searchResults.locator('li[role=option]').count()).toBe(1)
expect(
From ddf178a170967527bafe7c9b262fb66aa10ec9de Mon Sep 17 00:00:00 2001
From: T <6601329+cookesan@users.noreply.github.com>
Date: Sun, 28 Jun 2026 07:28:16 -0300
Subject: [PATCH 04/29] fix: preserve external sidebar links with base (#5243)
---
.../theme-default/support/sidebar.test.ts | 32 +++++++++++++++++++
src/client/theme-default/support/sidebar.ts | 4 +--
2 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/__tests__/unit/client/theme-default/support/sidebar.test.ts b/__tests__/unit/client/theme-default/support/sidebar.test.ts
index f33dcbd9..91e8085b 100644
--- a/__tests__/unit/client/theme-default/support/sidebar.test.ts
+++ b/__tests__/unit/client/theme-default/support/sidebar.test.ts
@@ -103,6 +103,38 @@ describe('client/theme-default/support/sidebar', () => {
)
})
})
+
+ test('applies base only to internal links', () => {
+ expect(
+ getSidebar(
+ {
+ '/en/': {
+ base: '/en/',
+ items: [
+ {
+ text: 'Guide',
+ items: [
+ { text: 'Intro', link: 'intro' },
+ { text: 'Root', link: '/root' },
+ { text: 'External', link: 'https://example.com/' }
+ ]
+ }
+ ]
+ }
+ },
+ '/en/intro'
+ )
+ ).toStrictEqual([
+ {
+ text: 'Guide',
+ items: [
+ { text: 'Intro', link: '/en/intro' },
+ { text: 'Root', link: '/en/root' },
+ { text: 'External', link: 'https://example.com/' }
+ ]
+ }
+ ])
+ })
})
describe('hasActiveLink', () => {
diff --git a/src/client/theme-default/support/sidebar.ts b/src/client/theme-default/support/sidebar.ts
index 13cd0aad..34dcfcf5 100644
--- a/src/client/theme-default/support/sidebar.ts
+++ b/src/client/theme-default/support/sidebar.ts
@@ -1,5 +1,5 @@
import type { DefaultTheme } from 'vitepress/theme'
-import { isActive } from '../../shared'
+import { isActive, isExternal } from '../../shared'
import { ensureStartingSlash } from './utils'
export interface SidebarLink {
@@ -112,7 +112,7 @@ function addBase(items: SidebarItem[], _base?: string): SidebarItem[] {
return [...items].map((_item) => {
const item = { ..._item }
const base = item.base || _base
- if (base && item.link)
+ if (base && item.link && !isExternal(item.link))
item.link = base + item.link.replace(/^\//, base.endsWith('/') ? '' : '/')
if (item.items) item.items = addBase(item.items, base)
return item
From 5c50b99724815a6fb3d2311e801dcad4aeb9b412 Mon Sep 17 00:00:00 2001
From: T <6601329+cookesan@users.noreply.github.com>
Date: Sun, 28 Jun 2026 07:30:27 -0300
Subject: [PATCH 05/29] fix(build): normalize rewrite drive letters (#5245)
---
__tests__/unit/node/markdownToVue.test.ts | 33 +++++++++++++++++++++++
src/node/markdownToVue.ts | 10 ++++---
2 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/__tests__/unit/node/markdownToVue.test.ts b/__tests__/unit/node/markdownToVue.test.ts
index 2a139b1b..9c88cdb5 100644
--- a/__tests__/unit/node/markdownToVue.test.ts
+++ b/__tests__/unit/node/markdownToVue.test.ts
@@ -66,4 +66,37 @@ describe('node/markdownToVue', () => {
line: 8
})
})
+
+ test('applies rewrites with mismatched Windows drive letter case', async () => {
+ root = await mkdtemp(path.join(tmpdir(), 'vitepress-rewrite-'))
+
+ const file = path.join(root, 'index.md')
+ await writeFile(file, '# Home\n')
+
+ const siteConfig = await resolveConfig(root, 'build', 'production')
+ siteConfig.srcDir = 'c:/site/docs'
+ siteConfig.pages = ['en/index.md']
+ siteConfig.rewrites = {
+ map: { 'en/index.md': 'index.md' },
+ inv: { 'index.md': 'en/index.md' }
+ }
+ ;(siteConfig as any).__dirty = true
+
+ const render = await createMarkdownToVueRenderFn(
+ siteConfig.srcDir,
+ { cache: false },
+ '/',
+ false,
+ false,
+ siteConfig
+ )
+
+ const result = await render(
+ '# Home\n',
+ 'C:/site/docs/en/index.md',
+ 'public'
+ )
+
+ expect(result.pageData.relativePath).toBe('index.md')
+ })
})
diff --git a/src/node/markdownToVue.ts b/src/node/markdownToVue.ts
index 6f433bfa..03bc31d2 100644
--- a/src/node/markdownToVue.ts
+++ b/src/node/markdownToVue.ts
@@ -47,6 +47,10 @@ let __dynamicRoutes = new Map()
let __rewrites = new Map()
let __ts: number
+function normalizeDriveLetter(file: string) {
+ return file.replace(/^[a-z]:/i, (drive) => drive.toLowerCase())
+}
+
function getResolutionCache(siteConfig: SiteConfig) {
// @ts-expect-error internal
if (siteConfig.__dirty) {
@@ -61,8 +65,8 @@ function getResolutionCache(siteConfig: SiteConfig) {
__rewrites = new Map(
Object.entries(siteConfig.rewrites.map).map(([key, value]) => [
- slash(path.join(siteConfig.srcDir, key)),
- slash(path.join(siteConfig.srcDir, value!))
+ normalizeDriveLetter(slash(path.join(siteConfig.srcDir, key))),
+ normalizeDriveLetter(slash(path.join(siteConfig.srcDir, value!)))
])
)
@@ -110,7 +114,7 @@ export async function createMarkdownToVueRenderFn(
getPageDataTransformer(dynamicRoute?.[1]!)
].filter((fn) => fn != null)
- file = rewrites.get(file) || file
+ file = rewrites.get(normalizeDriveLetter(file)) || file
const relativePath = slash(path.relative(srcDir, file))
const cacheKey = JSON.stringify({ src, ts, relativePath })
From e68fade75d2259b10695e85277f5483a084e3ae7 Mon Sep 17 00:00:00 2001
From: T <6601329+cookesan@users.noreply.github.com>
Date: Sun, 28 Jun 2026 08:04:16 -0300
Subject: [PATCH 06/29] fix: strip frontmatter before heading includes (#5246)
---
__tests__/unit/node/markdownToVue.test.ts | 57 +++++++++++++++++++++++
src/node/utils/processIncludes.ts | 11 ++++-
2 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/__tests__/unit/node/markdownToVue.test.ts b/__tests__/unit/node/markdownToVue.test.ts
index 9c88cdb5..ec89e7e0 100644
--- a/__tests__/unit/node/markdownToVue.test.ts
+++ b/__tests__/unit/node/markdownToVue.test.ts
@@ -67,6 +67,63 @@ describe('node/markdownToVue', () => {
})
})
+ test('selects included heading sections after frontmatter', async () => {
+ root = await mkdtemp(path.join(tmpdir(), 'vitepress-include-'))
+
+ const file = path.join(root, 'index.md')
+ const source = path.join(root, 'source.md')
+ await writeFile(
+ source,
+ [
+ '---',
+ 'description: Source description',
+ '---',
+ '# Intro',
+ '',
+ 'intro text',
+ '',
+ '## Shared',
+ '',
+ 'shared before target',
+ '',
+ '## Target',
+ '',
+ 'target text',
+ '',
+ '### Child',
+ '',
+ 'child text',
+ '',
+ '## Shared',
+ '',
+ 'shared after target',
+ ''
+ ].join('\n')
+ )
+ const src = ''
+ await writeFile(file, src)
+
+ const siteConfig = await resolveConfig(root, 'build', 'production')
+ const render = await createMarkdownToVueRenderFn(
+ siteConfig.srcDir,
+ { cache: false },
+ '/',
+ false,
+ false,
+ siteConfig
+ )
+
+ const result = await render(src, file, 'public')
+
+ expect(result.vueSrc).toContain('target text
')
+ expect(result.vueSrc).toContain('child text
')
+ expect(result.vueSrc).not.toContain('Source description')
+ expect(result.vueSrc).not.toContain('intro text')
+ expect(result.vueSrc).not.toContain('shared before target')
+ expect(result.vueSrc).not.toContain('shared after target')
+ })
+
test('applies rewrites with mismatched Windows drive letter case', async () => {
root = await mkdtemp(path.join(tmpdir(), 'vitepress-rewrite-'))
diff --git a/src/node/utils/processIncludes.ts b/src/node/utils/processIncludes.ts
index 20f6fbff..021c1b0b 100644
--- a/src/node/utils/processIncludes.ts
+++ b/src/node/utils/processIncludes.ts
@@ -41,12 +41,18 @@ export function processIncludes(
if (region) {
const [regionName] = region
const lines = content.split(/\r?\n/)
+ let selectedLines = lines
let { start, end } = findRegion(lines, regionName.slice(1)) ?? {}
if (start === undefined) {
// region not found, it might be a header
+ const headerContent =
+ path.extname(includePath) === '.md'
+ ? matter(content).content
+ : content
+ const headerLines = headerContent.split(/\r?\n/)
const tokens = md
- .parse(content, {
+ .parse(headerContent, {
path: includePath,
relativePath: slash(path.relative(srcDir, includePath)),
cleanUrls
@@ -57,6 +63,7 @@ export function processIncludes(
)
const token = tokens[idx]
if (token) {
+ selectedLines = headerLines
start = token.map![1]
const level = parseInt(token.tag.slice(1))
for (let i = idx + 1; i < tokens.length; i++) {
@@ -68,7 +75,7 @@ export function processIncludes(
}
}
- content = lines.slice(start, end).join('\n')
+ content = selectedLines.slice(start, end).join('\n')
}
if (range) {
From 01822e7b441aca699ba257357a40673260769535 Mon Sep 17 00:00:00 2001
From: ChisakaKanako
Date: Mon, 29 Jun 2026 13:04:59 +0800
Subject: [PATCH 07/29] docs(search): correct Chinese grammar in search
interface (#5255)
---
docs/zh/config.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/zh/config.ts b/docs/zh/config.ts
index 91687c54..3f20ec50 100644
--- a/docs/zh/config.ts
+++ b/docs/zh/config.ts
@@ -209,7 +209,7 @@ function searchOptions(): Partial {
closeText: '关闭',
backToSearchText: '返回搜索',
closeKeyAriaLabel: 'Esc 键',
- poweredByText: '由…提供支持'
+ poweredByText: '搜索提供'
},
errorScreen: {
titleText: '无法获取结果',
@@ -301,7 +301,7 @@ function searchOptions(): Partial {
'我会搜索你的文档,快速帮你找到设置指南、功能细节和故障排除提示。'
},
logo: {
- poweredByText: '由…提供支持'
+ poweredByText: '搜索提供'
}
}
}
From 8e38b1069b7e328fe9b860801ed222a1dd38e55f Mon Sep 17 00:00:00 2001
From: T <6601329+cookesan@users.noreply.github.com>
Date: Mon, 29 Jun 2026 02:11:09 -0300
Subject: [PATCH 08/29] docs: explain router route-change handlers (#5253)
---
docs/en/guide/custom-theme.md | 18 ++++++++++++++++++
docs/en/reference/runtime-api.md | 12 ++++++++++++
2 files changed, 30 insertions(+)
diff --git a/docs/en/guide/custom-theme.md b/docs/en/guide/custom-theme.md
index c0ce8597..8de4c7ab 100644
--- a/docs/en/guide/custom-theme.md
+++ b/docs/en/guide/custom-theme.md
@@ -67,6 +67,24 @@ export default {
}
```
+The `router` value is the same VitePress router instance returned by [`useRouter()`](../reference/runtime-api#userouter). To listen for route changes, assign handlers on the router:
+
+```ts [.vitepress/theme/index.ts]
+export default {
+ enhanceApp({ router }) {
+ router.onBeforeRouteChange = (to) => {
+ console.log('navigating to', to)
+ }
+
+ router.onAfterRouteChange = (to) => {
+ console.log('navigated to', to)
+ }
+ }
+}
+```
+
+Return `false` from `onBeforeRouteChange` or `onBeforePageLoad` to cancel navigation.
+
The default export is the only contract for a custom theme, and only the `Layout` property is required. So technically, a VitePress theme can be as simple as a single Vue component.
Inside your layout component, it works just like a normal Vite + Vue 3 application. Do note the theme also needs to be [SSR-compatible](./ssr-compat).
diff --git a/docs/en/reference/runtime-api.md b/docs/en/reference/runtime-api.md
index b39e4dcd..a202b270 100644
--- a/docs/en/reference/runtime-api.md
+++ b/docs/en/reference/runtime-api.md
@@ -124,6 +124,18 @@ interface Router {
}
```
+Assign route-change handlers on the router instance:
+
+```ts
+const router = useRouter()
+
+router.onBeforeRouteChange = (to) => {
+ console.log('navigating to', to)
+}
+```
+
+For custom themes, the same router is available from [`enhanceApp`](../guide/custom-theme#theme-interface).
+
## `withBase`
- **Type**: `(path: string) => string`
From f29ffdbb33022eb41327fec836f9cfbc16bf01d8 Mon Sep 17 00:00:00 2001
From: T <6601329+cookesan@users.noreply.github.com>
Date: Fri, 3 Jul 2026 03:59:57 -0400
Subject: [PATCH 09/29] fix: preserve Agent Studio DocSearch options (#5254)
Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>
---
.../theme-default/support/docsearch.test.ts | 106 ++++++++++++++++++
.../components/VPAlgoliaSearchBox.vue | 17 ++-
src/client/theme-default/support/docsearch.ts | 47 ++++++--
3 files changed, 153 insertions(+), 17 deletions(-)
diff --git a/__tests__/unit/client/theme-default/support/docsearch.test.ts b/__tests__/unit/client/theme-default/support/docsearch.test.ts
index 4da8f113..78c5ee68 100644
--- a/__tests__/unit/client/theme-default/support/docsearch.test.ts
+++ b/__tests__/unit/client/theme-default/support/docsearch.test.ts
@@ -1,5 +1,6 @@
import {
buildAskAiConfig,
+ buildSidePanelProps,
hasAskAi,
hasKeywordSearch,
mergeLangFacetFilters,
@@ -192,5 +193,110 @@ describe('client/theme-default/support/docsearch', () => {
)
expect(result.searchParameters?.facetFilters).toEqual(['lang:en'])
})
+
+ test('preserves Agent Studio search parameters by index', () => {
+ const result = buildAskAiConfig(
+ {
+ assistantId: 'assistant123',
+ agentStudio: true,
+ searchParameters: {
+ index: {
+ distinct: false
+ }
+ }
+ } as any,
+ {
+ appId: 'app',
+ apiKey: 'key',
+ indexName: 'index',
+ searchParameters: {
+ facetFilters: ['tag:docs']
+ }
+ } as any,
+ 'en'
+ )
+
+ expect(result.searchParameters).toEqual({
+ index: {
+ distinct: false
+ }
+ })
+ expect(result.searchParameters).not.toHaveProperty('facetFilters')
+ })
+
+ test('does not add legacy facet filters to Agent Studio config', () => {
+ const result = buildAskAiConfig(
+ {
+ assistantId: 'assistant123',
+ agentStudio: true
+ } as any,
+ {
+ appId: 'app',
+ apiKey: 'key',
+ indexName: 'index',
+ searchParameters: {
+ facetFilters: ['tag:docs']
+ }
+ } as any,
+ 'en'
+ )
+
+ expect(result.searchParameters).toBeUndefined()
+ })
+ })
+
+ describe('buildSidePanelProps', () => {
+ test('passes resolved Ask AI options to the side panel', () => {
+ const result = buildSidePanelProps(
+ {
+ assistantId: 'assistant123',
+ agentStudio: true,
+ searchParameters: {
+ index: {
+ facetFilters: ['lang:en']
+ }
+ },
+ suggestedQuestions: true,
+ useStagingEnv: true,
+ sidePanel: {
+ button: {
+ variant: 'inline'
+ },
+ panel: {
+ width: 420,
+ suggestedQuestions: true
+ }
+ }
+ } as any,
+ {
+ appId: 'app',
+ apiKey: 'key',
+ indexName: 'index'
+ } as any
+ )
+
+ expect(result).toEqual({
+ container: '#vp-docsearch-sidepanel',
+ appId: 'app',
+ apiKey: 'key',
+ indexName: 'index',
+ assistantId: 'assistant123',
+ agentStudio: true,
+ searchParameters: {
+ index: {
+ facetFilters: ['lang:en']
+ }
+ },
+ suggestedQuestions: true,
+ useStagingEnv: true,
+ button: {
+ variant: 'inline'
+ },
+ panel: {
+ width: 420,
+ suggestedQuestions: true
+ }
+ })
+ })
})
})
diff --git a/src/client/theme-default/components/VPAlgoliaSearchBox.vue b/src/client/theme-default/components/VPAlgoliaSearchBox.vue
index 26df2b7c..3d56c670 100644
--- a/src/client/theme-default/components/VPAlgoliaSearchBox.vue
+++ b/src/client/theme-default/components/VPAlgoliaSearchBox.vue
@@ -1,12 +1,16 @@
`
@@ -208,8 +207,8 @@ export async function renderPage(
function resolvePageImports(
config: SiteConfig,
page: string,
- result: Rollup.RollupOutput,
- appChunk: Rollup.OutputChunk
+ result: Rolldown.RolldownOutput,
+ appChunk: Rolldown.OutputChunk
) {
page = config.rewrites.inv[page] || page
// find the page's js chunk and inject script tags for its imports so that
@@ -226,7 +225,7 @@ function resolvePageImports(
srcPath = normalizePath(srcPath)
const pageChunk = result.output.find(
(chunk) => chunk.type === 'chunk' && chunk.facadeModuleId === srcPath
- ) as Rollup.OutputChunk
+ ) as Rolldown.OutputChunk
return [
...appChunk.imports,
// ...appChunk.dynamicImports,
@@ -265,14 +264,7 @@ function renderAttrs(attrs: Record): string {
}
async function minifyScript(code: string, filename: string): Promise {
- // @ts-ignore use oxc-minify when rolldown-vite is used
- if (vite.rolldownVersion) {
- const oxcMinify = await import('oxc-minify')
- return (await oxcMinify.minify(filename, code)).code.trim()
- }
- return (
- await transformWithEsbuild(code, filename, { minify: true })
- ).code.trim()
+ return (await minify(filename, code)).code.trim()
}
function filterOutHeadDescription(head: HeadConfig[] = []) {
diff --git a/src/node/plugin.ts b/src/node/plugin.ts
index 6739a75e..09bc3e88 100644
--- a/src/node/plugin.ts
+++ b/src/node/plugin.ts
@@ -7,7 +7,7 @@ import {
type EnvironmentModuleNode,
type Plugin,
type ResolvedConfig,
- type Rollup,
+ type Rolldown,
type UserConfig
} from 'vite'
import {
@@ -54,8 +54,8 @@ const staticRestoreRE = /__VP_STATIC_(START|END)__/g
const scriptClientRE = /
diff --git a/src/client/theme-default/components/VPDocAsideCarbonAds.vue b/src/client/theme-default/components/VPDocAsideCarbonAds.vue
index d10598dd..a04d4f67 100644
--- a/src/client/theme-default/components/VPDocAsideCarbonAds.vue
+++ b/src/client/theme-default/components/VPDocAsideCarbonAds.vue
@@ -1,6 +1,6 @@
diff --git a/src/client/theme-default/components/VPMenuLink.vue b/src/client/theme-default/components/VPMenuLink.vue
index 028d3e82..c98bf19c 100644
--- a/src/client/theme-default/components/VPMenuLink.vue
+++ b/src/client/theme-default/components/VPMenuLink.vue
@@ -1,8 +1,8 @@
diff --git a/src/client/theme-default/components/VPNavBarMenuGroup.vue b/src/client/theme-default/components/VPNavBarMenuGroup.vue
index 85350d47..4d014a49 100644
--- a/src/client/theme-default/components/VPNavBarMenuGroup.vue
+++ b/src/client/theme-default/components/VPNavBarMenuGroup.vue
@@ -1,8 +1,8 @@
diff --git a/src/client/theme-default/components/VPNavScreenMenuGroupLink.vue b/src/client/theme-default/components/VPNavScreenMenuGroupLink.vue
index 0ed634c0..9a884e01 100644
--- a/src/client/theme-default/components/VPNavScreenMenuGroupLink.vue
+++ b/src/client/theme-default/components/VPNavScreenMenuGroupLink.vue
@@ -1,8 +1,8 @@
`
- fs.removeSync(path.resolve(config.outDir, matchingChunk.fileName))
+ fs.rmSync(path.resolve(config.outDir, matchingChunk.fileName), {
+ force: true
+ })
} else {
inlinedScript = ``
}
@@ -189,7 +191,7 @@ export async function renderPage(