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 7 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: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('local-search/excluded')) return ''
return html

@ -124,9 +124,9 @@ export default defineConfig({
/**
* @param {string} src
* @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
}
}
@ -149,8 +149,8 @@ export default defineConfig({
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('some/path')) return ''
return html
@ -162,7 +162,7 @@ export default defineConfig({
```
::: 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
@ -175,10 +175,10 @@ export default defineConfig({
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html
return await md.renderAsync(`# ${env.frontmatter.title}`) + html
return html
}
}

@ -113,9 +113,9 @@ export default defineConfig({
/**
* @param {string} src
* @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
}
}
@ -138,8 +138,8 @@ export default defineConfig({
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('algum/caminho')) return ''
return html
@ -151,7 +151,7 @@ export default defineConfig({
```
::: 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}
@ -164,10 +164,10 @@ export default defineConfig({
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html
return await md.renderAsync(`# ${env.frontmatter.title}`) + html
return html
}
}

@ -120,9 +120,9 @@ export default defineConfig({
/**
* @param {string} src
* @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
}
}
@ -145,8 +145,8 @@ export default defineConfig({
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('some/path')) return ''
return html
@ -158,7 +158,7 @@ export default defineConfig({
```
::: warning توجه
در صورت ارائه تابع `_render` سفارشی، باید خودتان بررسی کنید که آیا frontmatter `search: false` را مدیریت می‌کند یا خیر. همچنین، شی env قبل از فراخوانی `md.render` کاملاً پر نمی‌شود، بنابراین هر بررسی‌ای روی ویژگی‌های اختیاری env مانند `frontmatter` باید بعد از آن انجام شود.
در صورت ارائه تابع `_render` سفارشی، باید خودتان بررسی کنید که آیا frontmatter `search: false` را مدیریت می‌کند یا خیر. همچنین، شی env قبل از فراخوانی `md.renderAsync` کاملاً پر نمی‌شود، بنابراین هر بررسی‌ای روی ویژگی‌های اختیاری env مانند `frontmatter` باید بعد از آن انجام شود.
:::
#### مثال: تبدیل محتوا - افزودن لینک‌های صفحه {#example-transforming-content-adding-anchors}
@ -171,10 +171,10 @@ export default defineConfig({
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html
return await md.renderAsync(`# ${env.frontmatter.title}`) + html
return html
}
}
@ -383,4 +383,4 @@ img[src="/search.png"] {
width: 100%;
aspect-ratio: 1 / 1;
}
</style>
</style>

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

@ -113,9 +113,9 @@ export default defineConfig({
/**
* @param {string} src
* @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
}
}
@ -138,8 +138,8 @@ export default defineConfig({
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('algum/caminho')) return ''
return html
@ -151,7 +151,7 @@ export default defineConfig({
```
::: 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}
@ -164,10 +164,10 @@ export default defineConfig({
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html
return await md.renderAsync(`# ${env.frontmatter.title}`) + html
return html
}
}

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

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

@ -101,7 +101,6 @@
"@shikijs/core": "^2.1.0",
"@shikijs/transformers": "^2.1.0",
"@shikijs/types": "^2.1.0",
"@types/markdown-it": "^14.1.2",
"@vitejs/plugin-vue": "^5.2.1",
"@vue/devtools-api": "^7.7.0",
"@vue/shared": "^3.5.13",
@ -135,6 +134,7 @@
"@types/fs-extra": "^11.0.4",
"@types/lodash.template": "^4.5.3",
"@types/mark.js": "^8.11.12",
"@types/markdown-it": "^14.1.2",
"@types/markdown-it-attrs": "^4.1.3",
"@types/markdown-it-container": "^2.0.10",
"@types/markdown-it-emoji": "^3.0.1",
@ -157,6 +157,7 @@
"lru-cache": "^11.0.2",
"markdown-it": "^14.1.0",
"markdown-it-anchor": "^9.2.0",
"markdown-it-async": "^2.0.0",
"markdown-it-attrs": "^4.3.1",
"markdown-it-container": "^4.0.0",
"markdown-it-emoji": "^3.0.0",
@ -183,7 +184,6 @@
"simple-git-hooks": "^2.11.1",
"sirv": "^3.0.0",
"sitemap": "^8.0.0",
"synckit": "^0.9.2",
"tinyglobby": "^0.2.10",
"typescript": "^5.7.3",
"vitest": "^3.0.4",
@ -215,7 +215,8 @@
"ora>string-width": "^5"
},
"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':
hash: ztuyknm7z4pyl4jot5hljjv5bm
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:
@ -34,9 +37,6 @@ importers:
'@shikijs/types':
specifier: ^2.1.0
version: 2.1.0
'@types/markdown-it':
specifier: ^14.1.2
version: 14.1.2
'@vitejs/plugin-vue':
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))
@ -131,6 +131,9 @@ importers:
'@types/mark.js':
specifier: ^8.11.12
version: 8.11.12
'@types/markdown-it':
specifier: ^14.1.2
version: 14.1.2
'@types/markdown-it-attrs':
specifier: ^4.1.3
version: 4.1.3
@ -196,7 +199,10 @@ importers:
version: 14.1.0
markdown-it-anchor:
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:
specifier: ^4.3.1
version: 4.3.1(markdown-it@14.1.0)
@ -275,9 +281,6 @@ importers:
sitemap:
specifier: ^8.0.0
version: 8.0.0
synckit:
specifier: ^0.9.2
version: 0.9.2
tinyglobby:
specifier: ^0.2.10
version: 0.2.10
@ -701,10 +704,6 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
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':
resolution: {integrity: sha512-aDmrBhgHJtxE+jy145WfhW9WmTAFmES/dNnn1LAs8UnnkFgBUj4T8I4ScQ9+rOkpDZStvnVP5iqhN3tvt7O1NA==}
engines: {node: '>=6'}
@ -1895,6 +1894,9 @@ packages:
'@types/markdown-it': '*'
markdown-it: '*'
markdown-it-async@2.0.0:
resolution: {integrity: sha512-jBthmQR5MwXR9Y8Y0teRoZAenaKQMdjuTfpbNARqMBSRPvyzyXCVduHZHakyyhL3ugIacCobXJrO07t277sIjw==}
markdown-it-attrs@4.3.1:
resolution: {integrity: sha512-/ko6cba+H6gdZ0DOw7BbNMZtfuJTRp9g/IrGIuz8lYc/EfnmWRpaR3CFPnNbVz0LDvF8Gf1hFGPqrQqq7De0rg==}
engines: {node: '>=6'}
@ -2482,10 +2484,6 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
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:
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
@ -3165,8 +3163,6 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.18.0
'@pkgr/core@0.1.1': {}
'@polka/compression@1.0.0-next.28': {}
'@polka/url@1.0.0-next.28': {}
@ -4375,7 +4371,12 @@ snapshots:
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:
'@types/markdown-it': 14.1.2
markdown-it: 14.1.0
@ -4965,11 +4966,6 @@ snapshots:
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: {}
temp-dir@3.0.0: {}

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

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

@ -144,9 +144,9 @@ export function createContentLoader<T = ContentData[]>(
normalizePath(path.relative(config.srcDir, file))
.replace(/(^|\/)index\.md$/, '$1')
.replace(/\.md$/, config.cleanUrls ? '' : '.html')
const html = render ? md.render(src) : undefined
const html = render ? await md.renderAsync(src) : undefined
const renderedExcerpt = renderExcerpt
? excerpt && md.render(excerpt)
? excerpt && (await md.renderAsync(excerpt))
: undefined
const data: ContentData = {
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 './serve/serve'
export * from './server'
export type { DefaultTheme } from './defaultTheme'
// shared types
export type {
DefaultTheme,
HeadConfig,
Header,
SiteData
} from '../../types/shared'
export type { HeadConfig, Header, SiteData } from '../../types/shared'

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

@ -7,20 +7,12 @@ import {
type TransformerCompactLineOption
} from '@shikijs/transformers'
import { customAlphabet } from 'nanoid'
import { createRequire } from 'node:module'
import c from 'picocolors'
import type { LanguageRegistration, ShikiTransformer } from 'shiki'
import { createHighlighter, isSpecialLang } from 'shiki'
import { createSyncFn } from 'synckit'
import type { Logger } from 'vite'
import type { ShikiResolveLang } from 'worker_shikiResolveLang'
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)
/**
@ -59,7 +51,9 @@ export async function highlight(
theme: ThemeOptions,
options: MarkdownOptions,
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 {
defaultHighlightLang: defaultLang = 'txt',
codeTransformers: userTransformers = []
@ -77,25 +71,14 @@ export async function highlight(
langAlias: options.languageAlias
})
function loadLanguage(name: string | LanguageRegistration) {
async function loadLanguage(name: string | LanguageRegistration) {
const lang = typeof name === 'string' ? name : name.name
if (
!isSpecialLang(lang) &&
!highlighter.getLoadedLanguages().includes(lang)
) {
const resolvedLang = resolveLangSync(lang)
if (resolvedLang.length) highlighter.loadLanguageSync(resolvedLang)
else return false
await highlighter.loadLanguage(lang as any)
}
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)
@ -136,7 +119,7 @@ export async function highlight(
const mustacheRE = /\{\{.*?\}\}/g
return [
(str: string, lang: string, attrs: string) => {
async (str: string, lang: string, attrs: string) => {
const vPre = vueRE.test(lang) ? '' : 'v-pre'
lang =
lang
@ -145,7 +128,9 @@ export async function highlight(
.replace(vueRE, '')
.toLowerCase() || defaultLang
if (!loadLanguage(lang)) {
try {
await loadLanguage(lang)
} catch {
logger.warn(
c.yellow(
`\nThe language '${lang}' is not loaded, falling back to '${defaultLang}' for syntax highlighting.`

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

@ -5,13 +5,9 @@ import path from 'node:path'
import pMap from 'p-map'
import type { Plugin, ViteDevServer } from 'vite'
import type { SiteConfig } from '../config'
import type { DefaultTheme } from '../defaultTheme'
import { createMarkdownRenderer } from '../markdown/markdown'
import {
getLocaleForPath,
slash,
type DefaultTheme,
type MarkdownEnv
} from '../shared'
import { getLocaleForPath, slash, type MarkdownEnv } from '../shared'
import { processIncludes } from '../utils/processIncludes'
const debug = _debug('vitepress:local-search')
@ -61,9 +57,10 @@ export async function localSearchPlugin(
const env: MarkdownEnv = { path: file, relativePath, cleanUrls }
const md_raw = await fs.promises.readFile(file, 'utf-8')
const md_src = processIncludes(srcDir, md_raw, file, [])
if (options._render) return await options._render(md_src, env, md)
else {
const html = md.render(md_src, env)
if (options._render) {
return await options._render(md_src, env, md)
} else {
const html = await md.renderAsync(md_src, env)
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 { DocSearchProps } from './docsearch.js'
import type {
LocalSearchTranslations,
PageSplitSection
} from './local-search.js'
import type { Awaitable, MarkdownEnv, PageData } from './shared.js'
import type { LocalSearchTranslations } from './local-search.js'
import type { PageData } from './shared.js'
export namespace DefaultTheme {
export interface Config {
@ -413,46 +409,21 @@ export namespace DefaultTheme {
translations?: LocalSearchTranslations
locales?: Record<string, Partial<Omit<LocalSearchOptions, 'locales'>>>
miniSearch?: {
/**
* @see https://lucaong.github.io/minisearch/types/MiniSearch.Options.html
*/
options?: Pick<
MiniSearchOptions,
'extractField' | 'tokenize' | 'processTerm'
>
/**
* @see https://lucaong.github.io/minisearch/types/MiniSearch.SearchOptions.html
*/
searchOptions?: MiniSearchOptions['searchOptions']
/**
* 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[]>
}
/**
* Allows transformation of content before indexing (node only)
* Return empty string to skip indexing
*/
_render?: (
src: string,
env: MarkdownEnv,
md: MarkdownIt
) => Awaitable<string>
miniSearch?: MiniSearchOptions
}
interface MiniSearchOptions {
/**
* @see https://lucaong.github.io/minisearch/types/MiniSearch.Options.html
*/
options?: Pick<
_MiniSearchOptions,
'extractField' | 'tokenize' | 'processTerm'
>
/**
* @see https://lucaong.github.io/minisearch/types/MiniSearch.SearchOptions.html
*/
searchOptions?: _MiniSearchOptions['searchOptions']
}
// algolia -------------------------------------------------------------------

Loading…
Cancel
Save