feat: use `markdown-it-async`, remove `synckit` (#4507)

BREAKING CHANGES: markdown-it-async is used instead of markdown-it

---------

Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>
pull/4530/head
Anthony Fu 8 months ago committed by GitHub
parent 74a0222f9a
commit 80622356f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -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
} }
} }
@ -383,4 +383,4 @@ img[src="/search.png"] {
width: 100%; width: 100%;
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
} }
</style> </style>

@ -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
} }
} }

@ -101,7 +101,6 @@
"@shikijs/core": "^2.1.0", "@shikijs/core": "^2.1.0",
"@shikijs/transformers": "^2.1.0", "@shikijs/transformers": "^2.1.0",
"@shikijs/types": "^2.1.0", "@shikijs/types": "^2.1.0",
"@types/markdown-it": "^14.1.2",
"@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue": "^5.2.1",
"@vue/devtools-api": "^7.7.0", "@vue/devtools-api": "^7.7.0",
"@vue/shared": "^3.5.13", "@vue/shared": "^3.5.13",
@ -135,6 +134,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",
@ -157,6 +157,7 @@
"lru-cache": "^11.0.2", "lru-cache": "^11.0.2",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
"markdown-it-anchor": "^9.2.0", "markdown-it-anchor": "^9.2.0",
"markdown-it-async": "^2.0.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",
"markdown-it-emoji": "^3.0.0", "markdown-it-emoji": "^3.0.0",
@ -183,7 +184,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.4", "vitest": "^3.0.4",
@ -215,7 +215,8 @@
"ora>string-width": "^5" "ora>string-width": "^5"
}, },
"patchedDependencies": { "patchedDependencies": {
"@types/mdurl@2.0.0": "patches/@types__mdurl@2.0.0.patch" "@types/mdurl@2.0.0": "patches/@types__mdurl@2.0.0.patch",
"markdown-it-anchor@9.2.0": "patches/markdown-it-anchor@9.2.0.patch"
} }
} }
} }

@ -0,0 +1,17 @@
diff --git a/types/index.d.ts b/types/index.d.ts
index 40c25c0be1add8b0fc2c51489c25a423dbc49d2c..807bc1b0e434d660c6a298b1dee1c87935bfac86 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -1,10 +1,8 @@
import MarkdownIt from 'markdown-it';
-import { default as MarkdownItToken } from 'markdown-it/lib/token.mjs';
-import { default as MarkdownItState} from 'markdown-it/lib/rules_core/state_core.mjs';
+import { default as Token } from 'markdown-it/lib/token.mjs';
+import { default as State } from 'markdown-it/lib/rules_core/state_core.mjs';
declare namespace anchor {
- export type Token = MarkdownItToken
- export type State = MarkdownItState
export type RenderHref = (slug: string, state: State) => string;
export type RenderAttrs = (slug: string, state: State) => Record<string, string | number>;

@ -11,6 +11,9 @@ patchedDependencies:
'@types/mdurl@2.0.0': '@types/mdurl@2.0.0':
hash: ztuyknm7z4pyl4jot5hljjv5bm hash: ztuyknm7z4pyl4jot5hljjv5bm
path: patches/@types__mdurl@2.0.0.patch path: patches/@types__mdurl@2.0.0.patch
markdown-it-anchor@9.2.0:
hash: ivrlfano2jj27ilcyyknwlzzfu
path: patches/markdown-it-anchor@9.2.0.patch
importers: importers:
@ -34,9 +37,6 @@ importers:
'@shikijs/types': '@shikijs/types':
specifier: ^2.1.0 specifier: ^2.1.0
version: 2.1.0 version: 2.1.0
'@types/markdown-it':
specifier: ^14.1.2
version: 14.1.2
'@vitejs/plugin-vue': '@vitejs/plugin-vue':
specifier: ^5.2.1 specifier: ^5.2.1
version: 5.2.1(vite@6.0.11(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) version: 5.2.1(vite@6.0.11(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3))
@ -131,6 +131,9 @@ importers:
'@types/mark.js': '@types/mark.js':
specifier: ^8.11.12 specifier: ^8.11.12
version: 8.11.12 version: 8.11.12
'@types/markdown-it':
specifier: ^14.1.2
version: 14.1.2
'@types/markdown-it-attrs': '@types/markdown-it-attrs':
specifier: ^4.1.3 specifier: ^4.1.3
version: 4.1.3 version: 4.1.3
@ -196,7 +199,10 @@ importers:
version: 14.1.0 version: 14.1.0
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(patch_hash=ivrlfano2jj27ilcyyknwlzzfu)(@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 +281,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 +704,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 +1894,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 +2484,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==}
@ -3165,8 +3163,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': {}
@ -4375,7 +4371,12 @@ snapshots:
mark.js@8.11.1: {} mark.js@8.11.1: {}
markdown-it-anchor@9.2.0(@types/markdown-it@14.1.2)(markdown-it@14.1.0): markdown-it-anchor@9.2.0(patch_hash=ivrlfano2jj27ilcyyknwlzzfu)(@types/markdown-it@14.1.2)(markdown-it@14.1.0):
dependencies:
'@types/markdown-it': 14.1.2
markdown-it: 14.1.0
markdown-it-async@2.0.0:
dependencies: dependencies:
'@types/markdown-it': 14.1.2 '@types/markdown-it': 14.1.2
markdown-it: 14.1.0 markdown-it: 14.1.0
@ -4965,11 +4966,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`,

@ -10,14 +10,9 @@ import {
type ConfigEnv type ConfigEnv
} from 'vite' } from 'vite'
import { DEFAULT_THEME_PATH } from './alias' import { DEFAULT_THEME_PATH } from './alias'
import type { DefaultTheme } from './defaultTheme'
import { resolvePages } from './plugins/dynamicRoutesPlugin' import { resolvePages } from './plugins/dynamicRoutesPlugin'
import { import { APPEARANCE_KEY, slash, type HeadConfig, type SiteData } from './shared'
APPEARANCE_KEY,
slash,
type DefaultTheme,
type HeadConfig,
type SiteData
} from './shared'
import type { RawConfigExports, SiteConfig, UserConfig } from './siteConfig' import type { RawConfigExports, SiteConfig, UserConfig } from './siteConfig'
export { resolvePages } from './plugins/dynamicRoutesPlugin' export { resolvePages } from './plugins/dynamicRoutesPlugin'

@ -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,

@ -0,0 +1,47 @@
// this file contains node-only types of default theme
// (functions starting with _ are node-only)
// in most of the cases these will leak to client too
// but these can import types from dev deps
import type { MarkdownItAsync } from 'markdown-it-async'
import type { DefaultTheme } from '../../types/default-theme'
import type { PageSplitSection } from '../../types/local-search'
import type { Awaitable, MarkdownEnv } from './shared'
declare module '../../types/default-theme.js' {
namespace DefaultTheme {
interface LocalSearchOptions {
/**
* Allows transformation of content before indexing (node only)
* Return empty string to skip indexing
*/
_render?: (
src: string,
env: MarkdownEnv,
md: MarkdownItAsync
) => Awaitable<string>
}
interface MiniSearchOptions {
/**
* Overrides the default regex based page splitter.
* Supports async generator, making it possible to run in true parallel
* (when used along with `node:child_process` or `worker_threads`)
* ---
* This should be especially useful for scalability reasons.
* ---
* @param {string} path - absolute path to the markdown source file
* @param {string} html - document page rendered as html
*/
_splitIntoSections?: (
path: string,
html: string
) =>
| AsyncGenerator<PageSplitSection>
| Generator<PageSplitSection>
| Awaitable<PageSplitSection[]>
}
}
}
export type { DefaultTheme }

@ -8,11 +8,7 @@ export { defineLoader, type LoaderModule } from './plugins/staticDataPlugin'
export * from './postcss/isolateStyles' export * from './postcss/isolateStyles'
export * from './serve/serve' export * from './serve/serve'
export * from './server' export * from './server'
export type { DefaultTheme } from './defaultTheme'
// shared types // shared types
export type { export type { HeadConfig, Header, SiteData } from '../../types/shared'
DefaultTheme,
HeadConfig,
Header,
SiteData
} from '../../types/shared'

@ -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) => Awaited<void> preConfig?: (md: MarkdownItAsync) => Awaited<void>
/** /**
* Setup markdown-it instance * Setup markdown-it instance
*/ */
config?: (md: MarkdownIt) => Awaited<void> config?: (md: MarkdownItAsync) => Awaited<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,12 @@ 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'
import c from 'picocolors'
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 +51,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,25 +71,14 @@ 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
}
// patch for twoslash - https://github.com/vuejs/vitepress/issues/4334
const internal = highlighter.getInternalContext()
const getLanguage = internal.getLanguage
internal.getLanguage = (name) => {
loadLanguage(name)
return getLanguage.call(internal, name)
} }
await options?.shikiSetup?.(highlighter) await options?.shikiSetup?.(highlighter)
@ -136,7 +119,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,7 +128,9 @@ export async function highlight(
.replace(vueRE, '') .replace(vueRE, '')
.toLowerCase() || defaultLang .toLowerCase() || defaultLang
if (!loadLanguage(lang)) { try {
await loadLanguage(lang)
} catch {
logger.warn( logger.warn(
c.yellow( c.yellow(
`\nThe language '${lang}' is not loaded, falling back to '${defaultLang}' for syntax highlighting.` `\nThe language '${lang}' is not loaded, falling back to '${defaultLang}' for syntax highlighting.`

@ -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 = [],

@ -5,13 +5,9 @@ import path from 'node:path'
import pMap from 'p-map' import pMap from 'p-map'
import type { Plugin, ViteDevServer } from 'vite' import type { Plugin, ViteDevServer } from 'vite'
import type { SiteConfig } from '../config' import type { SiteConfig } from '../config'
import type { DefaultTheme } from '../defaultTheme'
import { createMarkdownRenderer } from '../markdown/markdown' import { createMarkdownRenderer } from '../markdown/markdown'
import { import { getLocaleForPath, slash, type MarkdownEnv } from '../shared'
getLocaleForPath,
slash,
type DefaultTheme,
type MarkdownEnv
} from '../shared'
import { processIncludes } from '../utils/processIncludes' import { processIncludes } from '../utils/processIncludes'
const debug = _debug('vitepress:local-search') const debug = _debug('vitepress:local-search')
@ -61,9 +57,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

@ -1,12 +1,8 @@
import type MarkdownIt from 'markdown-it' import type { Options as _MiniSearchOptions } from 'minisearch'
import type { Options as MiniSearchOptions } from 'minisearch'
import type { ComputedRef, Ref, ShallowRef } from 'vue' import type { ComputedRef, Ref, ShallowRef } from 'vue'
import type { DocSearchProps } from './docsearch.js' import type { DocSearchProps } from './docsearch.js'
import type { import type { LocalSearchTranslations } from './local-search.js'
LocalSearchTranslations, import type { PageData } from './shared.js'
PageSplitSection
} from './local-search.js'
import type { Awaitable, MarkdownEnv, PageData } from './shared.js'
export namespace DefaultTheme { export namespace DefaultTheme {
export interface Config { export interface Config {
@ -413,46 +409,21 @@ export namespace DefaultTheme {
translations?: LocalSearchTranslations translations?: LocalSearchTranslations
locales?: Record<string, Partial<Omit<LocalSearchOptions, 'locales'>>> locales?: Record<string, Partial<Omit<LocalSearchOptions, 'locales'>>>
miniSearch?: { miniSearch?: MiniSearchOptions
/** }
* @see https://lucaong.github.io/minisearch/types/MiniSearch.Options.html
*/ interface MiniSearchOptions {
options?: Pick< /**
MiniSearchOptions, * @see https://lucaong.github.io/minisearch/types/MiniSearch.Options.html
'extractField' | 'tokenize' | 'processTerm' */
> options?: Pick<
/** _MiniSearchOptions,
* @see https://lucaong.github.io/minisearch/types/MiniSearch.SearchOptions.html 'extractField' | 'tokenize' | 'processTerm'
*/ >
searchOptions?: MiniSearchOptions['searchOptions'] /**
* @see https://lucaong.github.io/minisearch/types/MiniSearch.SearchOptions.html
/** */
* Overrides the default regex based page splitter. searchOptions?: _MiniSearchOptions['searchOptions']
* Supports async generator, making it possible to run in true parallel
* (when used along with `node:child_process` or `worker_threads`)
* ---
* This should be especially useful for scalability reasons.
* ---
* @param {string} path - absolute path to the markdown source file
* @param {string} html - document page rendered as html
*/
_splitIntoSections?: (
path: string,
html: string
) =>
| AsyncGenerator<PageSplitSection>
| Generator<PageSplitSection>
| Awaitable<PageSplitSection[]>
}
/**
* Allows transformation of content before indexing (node only)
* Return empty string to skip indexing
*/
_render?: (
src: string,
env: MarkdownEnv,
md: MarkdownIt
) => Awaitable<string>
} }
// algolia ------------------------------------------------------------------- // algolia -------------------------------------------------------------------

Loading…
Cancel
Save