feat: use `markdown-it-async`

pull/4507/head
Anthony Fu 8 months ago
parent e0350275b3
commit 758180d9f5
No known key found for this signature in database
GPG Key ID: 179936958CD423FF

@ -4,12 +4,6 @@
- upgrade vite to v6 ([#4504](https://github.com/vuejs/vitepress/issues/4504)) ([6a2efc3](https://github.com/vuejs/vitepress/commit/6a2efc385c90b088241db05f5263b2f3e1f757cf)) - upgrade vite to v6 ([#4504](https://github.com/vuejs/vitepress/issues/4504)) ([6a2efc3](https://github.com/vuejs/vitepress/commit/6a2efc385c90b088241db05f5263b2f3e1f757cf))
## [1.6.3](https://github.com/vuejs/vitepress/compare/v1.6.2...v1.6.3) (2025-01-22)
### Bug Fixes
- docsearch not rendering properly ([3e4120e](https://github.com/vuejs/vitepress/commit/3e4120e94805156bf63587fd633162433dbaf260))
## [1.6.2](https://github.com/vuejs/vitepress/compare/v1.6.1...v1.6.2) (2025-01-22) ## [1.6.2](https://github.com/vuejs/vitepress/compare/v1.6.1...v1.6.2) (2025-01-22)
### Bug Fixes ### Bug Fixes

@ -165,8 +165,8 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return '' if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('local-search/excluded')) return '' if (env.relativePath.startsWith('local-search/excluded')) return ''
return html return html

@ -124,9 +124,9 @@ export default defineConfig({
/** /**
* @param {string} src * @param {string} src
* @param {import('vitepress').MarkdownEnv} env * @param {import('vitepress').MarkdownEnv} env
* @param {import('markdown-it')} md * @param {import('markdown-it-async')} md
*/ */
_render(src, env, md) { async _render(src, env, md) {
// return html string // return html string
} }
} }
@ -149,8 +149,8 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return '' if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('some/path')) return '' if (env.relativePath.startsWith('some/path')) return ''
return html return html
@ -162,7 +162,7 @@ export default defineConfig({
``` ```
::: warning Note ::: warning Note
In case a custom `_render` function is provided, you need to handle the `search: false` frontmatter yourself. Also, the `env` object won't be completely populated before `md.render` is called, so any checks on optional `env` properties like `frontmatter` should be done after that. In case a custom `_render` function is provided, you need to handle the `search: false` frontmatter yourself. Also, the `env` object won't be completely populated before `md.renderAsync` is called, so any checks on optional `env` properties like `frontmatter` should be done after that.
::: :::
#### Example: Transforming content - adding anchors #### Example: Transforming content - adding anchors
@ -175,10 +175,10 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.title) if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html return await md.renderAsync(`# ${env.frontmatter.title}`) + html
return html return html
} }
} }

@ -113,9 +113,9 @@ export default defineConfig({
/** /**
* @param {string} src * @param {string} src
* @param {import('vitepress').MarkdownEnv} env * @param {import('vitepress').MarkdownEnv} env
* @param {import('markdown-it')} md * @param {import('markdown-it-async')} md
*/ */
_render(src, env, md) { async _render(src, env, md) {
// retorne un string HTML // retorne un string HTML
} }
} }
@ -138,8 +138,8 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return '' if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('algum/caminho')) return '' if (env.relativePath.startsWith('algum/caminho')) return ''
return html return html
@ -151,7 +151,7 @@ export default defineConfig({
``` ```
::: warning Nota ::: warning Nota
En este caso, una función `_render` se proporciona, es necesario manipular el `search: false` desde el frente por su cuenta. Además, el objeto `env` no estará completamente poblado antes que `md.render` se llama, luego verifica las propiedades opcionales `env`, como `frontmatter`, debe hacerse después de eso. En este caso, una función `_render` se proporciona, es necesario manipular el `search: false` desde el frente por su cuenta. Además, el objeto `env` no estará completamente poblado antes que `md.renderAsync` se llama, luego verifica las propiedades opcionales `env`, como `frontmatter`, debe hacerse después de eso.
::: :::
#### Ejemplo: Transformar contenido - agregar anclajes {#example-transforming-content-adding-anchors} #### Ejemplo: Transformar contenido - agregar anclajes {#example-transforming-content-adding-anchors}
@ -164,10 +164,10 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.title) if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html return await md.renderAsync(`# ${env.frontmatter.title}`) + html
return html return html
} }
} }

@ -120,9 +120,9 @@ export default defineConfig({
/** /**
* @param {string} src * @param {string} src
* @param {import('vitepress').MarkdownEnv} env * @param {import('vitepress').MarkdownEnv} env
* @param {import('markdown-it')} md * @param {import('markdown-it-async')} md
*/ */
_render(src, env, md) { async _render(src, env, md) {
// بازگشت رشته HTML // بازگشت رشته HTML
} }
} }
@ -145,8 +145,8 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return '' if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('some/path')) return '' if (env.relativePath.startsWith('some/path')) return ''
return html return html
@ -158,7 +158,7 @@ export default defineConfig({
``` ```
::: warning توجه ::: warning توجه
در صورت ارائه تابع `_render` سفارشی، باید خودتان بررسی کنید که آیا frontmatter `search: false` را مدیریت می‌کند یا خیر. همچنین، شی env قبل از فراخوانی `md.render` کاملاً پر نمی‌شود، بنابراین هر بررسی‌ای روی ویژگی‌های اختیاری env مانند `frontmatter` باید بعد از آن انجام شود. در صورت ارائه تابع `_render` سفارشی، باید خودتان بررسی کنید که آیا frontmatter `search: false` را مدیریت می‌کند یا خیر. همچنین، شی env قبل از فراخوانی `md.renderAsync` کاملاً پر نمی‌شود، بنابراین هر بررسی‌ای روی ویژگی‌های اختیاری env مانند `frontmatter` باید بعد از آن انجام شود.
::: :::
#### مثال: تبدیل محتوا - افزودن لینک‌های صفحه {#example-transforming-content-adding-anchors} #### مثال: تبدیل محتوا - افزودن لینک‌های صفحه {#example-transforming-content-adding-anchors}
@ -171,10 +171,10 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.title) if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html return await md.renderAsync(`# ${env.frontmatter.title}`) + html
return html return html
} }
} }

@ -120,9 +120,9 @@ export default defineConfig({
/** /**
* @param {string} src * @param {string} src
* @param {import('vitepress').MarkdownEnv} env * @param {import('vitepress').MarkdownEnv} env
* @param {import('markdown-it')} md * @param {import('markdown-it-async')} md
*/ */
_render(src, env, md) { async _render(src, env, md) {
// return html string // return html string
} }
} }
@ -145,8 +145,8 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return '' if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('some/path')) return '' if (env.relativePath.startsWith('some/path')) return ''
return html return html
@ -158,7 +158,7 @@ export default defineConfig({
``` ```
::: warning 참고 ::: warning 참고
커스텀 `_render` 함수가 제공된 경우, `search: false` 전문을 직접 처리해야 합니다. 또한, `md.render`가 호출되기 전에 `env` 객체가 완전히 채워지지 않으므로, `frontmatter`와 같은 선택적 `env` 프로퍼티에 대한 검사는 그 이후에 수행해야 합니다. 커스텀 `_render` 함수가 제공된 경우, `search: false` 전문을 직접 처리해야 합니다. 또한, `md.renderAsync`가 호출되기 전에 `env` 객체가 완전히 채워지지 않으므로, `frontmatter`와 같은 선택적 `env` 프로퍼티에 대한 검사는 그 이후에 수행해야 합니다.
::: :::
#### 예제: 콘텐츠 변환 - 앵커 추가 {#example-transforming-content-adding-anchors} #### 예제: 콘텐츠 변환 - 앵커 추가 {#example-transforming-content-adding-anchors}
@ -171,10 +171,10 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.title) if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html return await md.renderAsync(`# ${env.frontmatter.title}`) + html
return html return html
} }
} }

@ -113,9 +113,9 @@ export default defineConfig({
/** /**
* @param {string} src * @param {string} src
* @param {import('vitepress').MarkdownEnv} env * @param {import('vitepress').MarkdownEnv} env
* @param {import('markdown-it')} md * @param {import('markdown-it-async')} md
*/ */
_render(src, env, md) { async _render(src, env, md) {
// retorne a string HTML // retorne a string HTML
} }
} }
@ -138,8 +138,8 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return '' if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('algum/caminho')) return '' if (env.relativePath.startsWith('algum/caminho')) return ''
return html return html
@ -151,7 +151,7 @@ export default defineConfig({
``` ```
::: warning Nota ::: warning Nota
No caso uma função `_render` personalizada ser fornecida, você precisa manipular o `search: false` do frontmatter por conta própria. Além disso, o objeto `env` não estará completamente populado antes que `md.render` seja chamado, então verificações em propriedades opcionais `env`, como `frontmatter`, devem ser feitas após isso. No caso uma função `_render` personalizada ser fornecida, você precisa manipular o `search: false` do frontmatter por conta própria. Além disso, o objeto `env` não estará completamente populado antes que `md.renderAsync` seja chamado, então verificações em propriedades opcionais `env`, como `frontmatter`, devem ser feitas após isso.
::: :::
#### Exemplo: Transformando conteúdo - adicionando âncoras {#example-transforming-content-adding-anchors} #### Exemplo: Transformando conteúdo - adicionando âncoras {#example-transforming-content-adding-anchors}
@ -164,10 +164,10 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.title) if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html return await md.renderAsync(`# ${env.frontmatter.title}`) + html
return html return html
} }
} }

@ -124,9 +124,9 @@ export default defineConfig({
/** /**
* @param {string} src * @param {string} src
* @param {import('vitepress').MarkdownEnv} env * @param {import('vitepress').MarkdownEnv} env
* @param {import('markdown-it')} md * @param {import('markdown-it-async')} md
*/ */
_render(src, env, md) { async _render(src, env, md) {
// возвращаем html // возвращаем html
} }
} }
@ -149,8 +149,8 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return '' if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('some/path')) return '' if (env.relativePath.startsWith('some/path')) return ''
return html return html
@ -162,7 +162,7 @@ export default defineConfig({
``` ```
::: warning ПРИМЕЧАНИЕ ::: warning ПРИМЕЧАНИЕ
В случае, если предоставляется пользовательская функция `_render`, вам нужно самостоятельно обработать заголовок `search: false`. Кроме того, объект `env` не будет полностью заполнен до вызова `md.render`, поэтому любые проверки необязательных свойств `env`, таких как `frontmatter`, должны быть выполнены после этого. В случае, если предоставляется пользовательская функция `_render`, вам нужно самостоятельно обработать заголовок `search: false`. Кроме того, объект `env` не будет полностью заполнен до вызова `md.renderAsync`, поэтому любые проверки необязательных свойств `env`, таких как `frontmatter`, должны быть выполнены после этого.
::: :::
#### Пример: Преобразование содержимого - добавление якорей {#example-transforming-content-adding-anchors} #### Пример: Преобразование содержимого - добавление якорей {#example-transforming-content-adding-anchors}
@ -175,10 +175,10 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.title) if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html return await md.renderAsync(`# ${env.frontmatter.title}`) + html
return html return html
} }
} }

@ -113,9 +113,9 @@ export default defineConfig({
/** /**
* @param {string} src * @param {string} src
* @param {import('vitepress').MarkdownEnv} env * @param {import('vitepress').MarkdownEnv} env
* @param {import('markdown-it')} md * @param {import('markdown-it-async')} md
*/ */
_render(src, env, md) { async _render(src, env, md) {
// 返回 html 字符串 // 返回 html 字符串
} }
} }
@ -138,8 +138,8 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return '' if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('some/path')) return '' if (env.relativePath.startsWith('some/path')) return ''
return html return html
@ -151,7 +151,7 @@ export default defineConfig({
``` ```
::: warning 注意 ::: warning 注意
如果提供了自定义的 `_render` 函数,你需要自己处理 `search: false` 的 frontmatter。此外在调用 `md.render` 之前,`env` 对象不会完全填充,因此对可选 `env` 属性 (如 `frontmatter`) 的任何检查都应该在此之后完成。 如果提供了自定义的 `_render` 函数,你需要自己处理 `search: false` 的 frontmatter。此外在调用 `md.renderAsync` 之前,`env` 对象不会完全填充,因此对可选 `env` 属性 (如 `frontmatter`) 的任何检查都应该在此之后完成。
::: :::
#### 示例:转换内容——添加锚点 {#example-transforming-content-adding-anchors} #### 示例:转换内容——添加锚点 {#example-transforming-content-adding-anchors}
@ -164,10 +164,10 @@ export default defineConfig({
search: { search: {
provider: 'local', provider: 'local',
options: { options: {
_render(src, env, md) { async _render(src, env, md) {
const html = md.render(src, env) const html = await md.renderAsync(src, env)
if (env.frontmatter?.title) if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html return await md.renderAsync(`# ${env.frontmatter.title}`) + html
return html return html
} }
} }

@ -135,6 +135,7 @@
"@types/fs-extra": "^11.0.4", "@types/fs-extra": "^11.0.4",
"@types/lodash.template": "^4.5.3", "@types/lodash.template": "^4.5.3",
"@types/mark.js": "^8.11.12", "@types/mark.js": "^8.11.12",
"@types/markdown-it": "^14.1.2",
"@types/markdown-it-attrs": "^4.1.3", "@types/markdown-it-attrs": "^4.1.3",
"@types/markdown-it-container": "^2.0.10", "@types/markdown-it-container": "^2.0.10",
"@types/markdown-it-emoji": "^3.0.1", "@types/markdown-it-emoji": "^3.0.1",
@ -156,6 +157,7 @@
"lodash.template": "^4.5.0", "lodash.template": "^4.5.0",
"lru-cache": "^11.0.2", "lru-cache": "^11.0.2",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
"markdown-it-async": "^2.0.0",
"markdown-it-anchor": "^9.2.0", "markdown-it-anchor": "^9.2.0",
"markdown-it-attrs": "^4.3.1", "markdown-it-attrs": "^4.3.1",
"markdown-it-container": "^4.0.0", "markdown-it-container": "^4.0.0",
@ -183,7 +185,6 @@
"simple-git-hooks": "^2.11.1", "simple-git-hooks": "^2.11.1",
"sirv": "^3.0.0", "sirv": "^3.0.0",
"sitemap": "^8.0.0", "sitemap": "^8.0.0",
"synckit": "^0.9.2",
"tinyglobby": "^0.2.10", "tinyglobby": "^0.2.10",
"typescript": "^5.7.3", "typescript": "^5.7.3",
"vitest": "^3.0.3", "vitest": "^3.0.3",

@ -197,6 +197,9 @@ importers:
markdown-it-anchor: markdown-it-anchor:
specifier: ^9.2.0 specifier: ^9.2.0
version: 9.2.0(@types/markdown-it@14.1.2)(markdown-it@14.1.0) version: 9.2.0(@types/markdown-it@14.1.2)(markdown-it@14.1.0)
markdown-it-async:
specifier: ^2.0.0
version: 2.0.0
markdown-it-attrs: markdown-it-attrs:
specifier: ^4.3.1 specifier: ^4.3.1
version: 4.3.1(markdown-it@14.1.0) version: 4.3.1(markdown-it@14.1.0)
@ -275,9 +278,6 @@ importers:
sitemap: sitemap:
specifier: ^8.0.0 specifier: ^8.0.0
version: 8.0.0 version: 8.0.0
synckit:
specifier: ^0.9.2
version: 0.9.2
tinyglobby: tinyglobby:
specifier: ^0.2.10 specifier: ^0.2.10
version: 0.2.10 version: 0.2.10
@ -701,10 +701,6 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
'@pkgr/core@0.1.1':
resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
'@polka/compression@1.0.0-next.28': '@polka/compression@1.0.0-next.28':
resolution: {integrity: sha512-aDmrBhgHJtxE+jy145WfhW9WmTAFmES/dNnn1LAs8UnnkFgBUj4T8I4ScQ9+rOkpDZStvnVP5iqhN3tvt7O1NA==} resolution: {integrity: sha512-aDmrBhgHJtxE+jy145WfhW9WmTAFmES/dNnn1LAs8UnnkFgBUj4T8I4ScQ9+rOkpDZStvnVP5iqhN3tvt7O1NA==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -1895,6 +1891,9 @@ packages:
'@types/markdown-it': '*' '@types/markdown-it': '*'
markdown-it: '*' markdown-it: '*'
markdown-it-async@2.0.0:
resolution: {integrity: sha512-jBthmQR5MwXR9Y8Y0teRoZAenaKQMdjuTfpbNARqMBSRPvyzyXCVduHZHakyyhL3ugIacCobXJrO07t277sIjw==}
markdown-it-attrs@4.3.1: markdown-it-attrs@4.3.1:
resolution: {integrity: sha512-/ko6cba+H6gdZ0DOw7BbNMZtfuJTRp9g/IrGIuz8lYc/EfnmWRpaR3CFPnNbVz0LDvF8Gf1hFGPqrQqq7De0rg==} resolution: {integrity: sha512-/ko6cba+H6gdZ0DOw7BbNMZtfuJTRp9g/IrGIuz8lYc/EfnmWRpaR3CFPnNbVz0LDvF8Gf1hFGPqrQqq7De0rg==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -2482,10 +2481,6 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
synckit@0.9.2:
resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==}
engines: {node: ^14.18.0 || >=16.0.0}
tabbable@6.2.0: tabbable@6.2.0:
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
@ -3162,8 +3157,6 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5 '@nodelib/fs.scandir': 2.1.5
fastq: 1.18.0 fastq: 1.18.0
'@pkgr/core@0.1.1': {}
'@polka/compression@1.0.0-next.28': {} '@polka/compression@1.0.0-next.28': {}
'@polka/url@1.0.0-next.28': {} '@polka/url@1.0.0-next.28': {}
@ -4377,6 +4370,11 @@ snapshots:
'@types/markdown-it': 14.1.2 '@types/markdown-it': 14.1.2
markdown-it: 14.1.0 markdown-it: 14.1.0
markdown-it-async@2.0.0:
dependencies:
'@types/markdown-it': 14.1.2
markdown-it: 14.1.0
markdown-it-attrs@4.3.1(markdown-it@14.1.0): markdown-it-attrs@4.3.1(markdown-it@14.1.0):
dependencies: dependencies:
markdown-it: 14.1.0 markdown-it: 14.1.0
@ -4962,11 +4960,6 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {} supports-preserve-symlinks-flag@1.0.0: {}
synckit@0.9.2:
dependencies:
'@pkgr/core': 0.1.1
tslib: 2.8.1
tabbable@6.2.0: {} tabbable@6.2.0: {}
temp-dir@3.0.0: {} temp-dir@3.0.0: {}

@ -8,7 +8,6 @@ import { builtinModules, createRequire } from 'node:module'
import { type RollupOptions, defineConfig } from 'rollup' import { type RollupOptions, defineConfig } from 'rollup'
import dts from 'rollup-plugin-dts' import dts from 'rollup-plugin-dts'
import esbuild from 'rollup-plugin-esbuild' import esbuild from 'rollup-plugin-esbuild'
import { globSync } from 'tinyglobby'
const require = createRequire(import.meta.url) const require = createRequire(import.meta.url)
const pkg = require('./package.json') const pkg = require('./package.json')
@ -39,11 +38,7 @@ const plugins = [
] ]
const esmBuild: RollupOptions = { const esmBuild: RollupOptions = {
input: [ input: ['src/node/index.ts', 'src/node/cli.ts'],
'src/node/index.ts',
'src/node/cli.ts',
...globSync('src/node/worker_*.ts')
],
output: { output: {
format: 'esm', format: 'esm',
entryFileNames: `[name].js`, entryFileNames: `[name].js`,
@ -96,7 +91,10 @@ const clientTypes: RollupOptions = {
}, },
external: typesExternal, external: typesExternal,
plugins: [ plugins: [
dts({ respectExternal: true }), dts({
respectExternal: true,
tsconfig: 'tsconfig.json'
}),
{ {
name: 'cleanup', name: 'cleanup',
async closeBundle() { async closeBundle() {

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import docsearch from '@docsearch/js' import docsearch from '@docsearch/js'
import { useRouter } from 'vitepress' import { useRoute, useRouter } from 'vitepress'
import type { DefaultTheme } from 'vitepress/theme' import type { DefaultTheme } from 'vitepress/theme'
import { nextTick, onMounted, watch } from 'vue' import { nextTick, onMounted, watch } from 'vue'
import { useData } from '../composables/data' import { useData } from '../composables/data'
@ -10,6 +10,7 @@ const props = defineProps<{
}>() }>()
const router = useRouter() const router = useRouter()
const route = useRoute()
const { site, localeIndex, lang } = useData() const { site, localeIndex, lang } = useData()
type DocSearchProps = Parameters<typeof docsearch>[0] type DocSearchProps = Parameters<typeof docsearch>[0]
@ -50,7 +51,17 @@ function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) {
navigator: { navigator: {
navigate({ itemUrl }) { navigate({ itemUrl }) {
router.go(itemUrl) const { pathname: hitPathname } = new URL(
window.location.origin + itemUrl
)
// router doesn't handle same-page navigation so we use the native
// browser location API for anchor navigation
if (route.path === hitPathname) {
window.location.assign(window.location.origin + itemUrl)
} else {
router.go(itemUrl)
}
} }
}, },
@ -60,6 +71,17 @@ function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) {
url: getRelativePath(item.url) url: getRelativePath(item.url)
}) })
}) })
},
hitComponent({ hit, children }) {
return {
__v: null,
type: 'a',
ref: undefined,
constructor: undefined,
key: undefined,
props: { href: hit.url, children }
}
} }
}) as DocSearchProps }) as DocSearchProps

@ -144,9 +144,9 @@ export function createContentLoader<T = ContentData[]>(
normalizePath(path.relative(config.srcDir, file)) normalizePath(path.relative(config.srcDir, file))
.replace(/(^|\/)index\.md$/, '$1') .replace(/(^|\/)index\.md$/, '$1')
.replace(/\.md$/, config.cleanUrls ? '' : '.html') .replace(/\.md$/, config.cleanUrls ? '' : '.html')
const html = render ? md.render(src) : undefined const html = render ? await md.renderAsync(src) : undefined
const renderedExcerpt = renderExcerpt const renderedExcerpt = renderExcerpt
? excerpt && md.render(excerpt) ? excerpt && (await md.renderAsync(excerpt))
: undefined : undefined
const data: ContentData = { const data: ContentData = {
src: includeSrc ? src : undefined, src: includeSrc ? src : undefined,

@ -20,7 +20,7 @@ import type {
ThemeRegistrationAny ThemeRegistrationAny
} from '@shikijs/types' } from '@shikijs/types'
import type { Options } from 'markdown-it' import type { Options } from 'markdown-it'
import MarkdownIt from 'markdown-it' import { MarkdownItAsync } from 'markdown-it-async'
import anchorPlugin from 'markdown-it-anchor' import anchorPlugin from 'markdown-it-anchor'
import attrsPlugin from 'markdown-it-attrs' import attrsPlugin from 'markdown-it-attrs'
import { full as emojiPlugin } from 'markdown-it-emoji' import { full as emojiPlugin } from 'markdown-it-emoji'
@ -53,11 +53,11 @@ export interface MarkdownOptions extends Options {
/** /**
* Setup markdown-it instance before applying plugins * Setup markdown-it instance before applying plugins
*/ */
preConfig?: (md: MarkdownIt) => void preConfig?: (md: MarkdownItAsync) => void
/** /**
* Setup markdown-it instance * Setup markdown-it instance
*/ */
config?: (md: MarkdownIt) => void config?: (md: MarkdownItAsync) => void
/** /**
* Disable cache (experimental) * Disable cache (experimental)
*/ */
@ -190,7 +190,7 @@ export interface MarkdownOptions extends Options {
gfmAlerts?: boolean gfmAlerts?: boolean
} }
export type MarkdownRenderer = MarkdownIt export type MarkdownRenderer = MarkdownItAsync
let md: MarkdownRenderer | undefined let md: MarkdownRenderer | undefined
let _disposeHighlighter: (() => void) | undefined let _disposeHighlighter: (() => void) | undefined
@ -223,7 +223,7 @@ export async function createMarkdownRenderer(
_disposeHighlighter = dispose _disposeHighlighter = dispose
md = MarkdownIt({ html: true, linkify: true, highlight, ...options }) md = new MarkdownItAsync({ html: true, linkify: true, highlight, ...options })
md.linkify.set({ fuzzyLink: false }) md.linkify.set({ fuzzyLink: false })
md.use(restoreEntities) md.use(restoreEntities)

@ -7,20 +7,11 @@ import {
type TransformerCompactLineOption type TransformerCompactLineOption
} from '@shikijs/transformers' } from '@shikijs/transformers'
import { customAlphabet } from 'nanoid' import { customAlphabet } from 'nanoid'
import { createRequire } from 'node:module'
import c from 'picocolors'
import type { LanguageRegistration, ShikiTransformer } from 'shiki' import type { LanguageRegistration, ShikiTransformer } from 'shiki'
import { createHighlighter, isSpecialLang } from 'shiki' import { createHighlighter, isSpecialLang } from 'shiki'
import { createSyncFn } from 'synckit'
import type { Logger } from 'vite' import type { Logger } from 'vite'
import type { ShikiResolveLang } from 'worker_shikiResolveLang'
import type { MarkdownOptions, ThemeOptions } from '../markdown' import type { MarkdownOptions, ThemeOptions } from '../markdown'
const require = createRequire(import.meta.url)
const resolveLangSync = createSyncFn<ShikiResolveLang>(
require.resolve('vitepress/dist/node/worker_shikiResolveLang.js')
)
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 10) const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 10)
/** /**
@ -59,7 +50,9 @@ export async function highlight(
theme: ThemeOptions, theme: ThemeOptions,
options: MarkdownOptions, options: MarkdownOptions,
logger: Pick<Logger, 'warn'> = console logger: Pick<Logger, 'warn'> = console
): Promise<[(str: string, lang: string, attrs: string) => string, () => void]> { ): Promise<
[(str: string, lang: string, attrs: string) => Promise<string>, () => void]
> {
const { const {
defaultHighlightLang: defaultLang = 'txt', defaultHighlightLang: defaultLang = 'txt',
codeTransformers: userTransformers = [] codeTransformers: userTransformers = []
@ -77,15 +70,13 @@ export async function highlight(
langAlias: options.languageAlias langAlias: options.languageAlias
}) })
function loadLanguage(name: string | LanguageRegistration) { async function loadLanguage(name: string | LanguageRegistration) {
const lang = typeof name === 'string' ? name : name.name const lang = typeof name === 'string' ? name : name.name
if ( if (
!isSpecialLang(lang) && !isSpecialLang(lang) &&
!highlighter.getLoadedLanguages().includes(lang) !highlighter.getLoadedLanguages().includes(lang)
) { ) {
const resolvedLang = resolveLangSync(lang) await highlighter.loadLanguage(lang as any)
if (resolvedLang.length) highlighter.loadLanguageSync(resolvedLang)
else return false
} }
return true return true
} }
@ -136,7 +127,7 @@ export async function highlight(
const mustacheRE = /\{\{.*?\}\}/g const mustacheRE = /\{\{.*?\}\}/g
return [ return [
(str: string, lang: string, attrs: string) => { async (str: string, lang: string, attrs: string) => {
const vPre = vueRE.test(lang) ? '' : 'v-pre' const vPre = vueRE.test(lang) ? '' : 'v-pre'
lang = lang =
lang lang
@ -145,14 +136,7 @@ export async function highlight(
.replace(vueRE, '') .replace(vueRE, '')
.toLowerCase() || defaultLang .toLowerCase() || defaultLang
if (!loadLanguage(lang)) { await loadLanguage(lang)
logger.warn(
c.yellow(
`\nThe language '${lang}' is not loaded, falling back to '${defaultLang}' for syntax highlighting.`
)
)
lang = defaultLang
}
const lineOptions = attrsToLines(attrs) const lineOptions = attrsToLines(attrs)
const mustaches = new Map<string, string>() const mustaches = new Map<string, string>()

@ -119,7 +119,7 @@ export async function createMarkdownToVueRenderFn(
realPath: fileOrig, realPath: fileOrig,
localeIndex localeIndex
} }
const html = md.render(src, env) const html = await md.renderAsync(src, env)
const { const {
frontmatter = {}, frontmatter = {},
headers = [], headers = [],

@ -61,9 +61,10 @@ export async function localSearchPlugin(
const env: MarkdownEnv = { path: file, relativePath, cleanUrls } const env: MarkdownEnv = { path: file, relativePath, cleanUrls }
const md_raw = await fs.promises.readFile(file, 'utf-8') const md_raw = await fs.promises.readFile(file, 'utf-8')
const md_src = processIncludes(srcDir, md_raw, file, []) const md_src = processIncludes(srcDir, md_raw, file, [])
if (options._render) return await options._render(md_src, env, md) if (options._render) {
else { return await options._render(md_src, env, md)
const html = md.render(md_src, env) } else {
const html = await md.renderAsync(md_src, env)
return env.frontmatter?.search === false ? '' : html return env.frontmatter?.search === false ? '' : html
} }
} }

@ -1,23 +0,0 @@
import {
bundledLanguages,
type DynamicImportLanguageRegistration,
type LanguageRegistration
} from 'shiki'
import { runAsWorker } from 'synckit'
async function resolveLang(lang: string) {
return (
(
bundledLanguages as Record<
string,
DynamicImportLanguageRegistration | undefined
>
)
[lang]?.()
.then((m) => m.default) || ([] as LanguageRegistration[])
)
}
runAsWorker(resolveLang)
export type ShikiResolveLang = typeof resolveLang

@ -6,6 +6,7 @@ import type {
LocalSearchTranslations, LocalSearchTranslations,
PageSplitSection PageSplitSection
} from './local-search.js' } from './local-search.js'
import type { MarkdownItAsync } from 'markdown-it-async'
import type { Awaitable, MarkdownEnv, PageData } from './shared.js' import type { Awaitable, MarkdownEnv, PageData } from './shared.js'
export namespace DefaultTheme { export namespace DefaultTheme {
@ -451,7 +452,7 @@ export namespace DefaultTheme {
_render?: ( _render?: (
src: string, src: string,
env: MarkdownEnv, env: MarkdownEnv,
md: MarkdownIt md: MarkdownItAsync
) => Awaitable<string> ) => Awaitable<string>
} }

Loading…
Cancel
Save