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))
## [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)
### Bug Fixes

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

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

@ -135,6 +135,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",
@ -156,6 +157,7 @@
"lodash.template": "^4.5.0",
"lru-cache": "^11.0.2",
"markdown-it": "^14.1.0",
"markdown-it-async": "^2.0.0",
"markdown-it-anchor": "^9.2.0",
"markdown-it-attrs": "^4.3.1",
"markdown-it-container": "^4.0.0",
@ -183,7 +185,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.3",

@ -197,6 +197,9 @@ importers:
markdown-it-anchor:
specifier: ^9.2.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:
specifier: ^4.3.1
version: 4.3.1(markdown-it@14.1.0)
@ -275,9 +278,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 +701,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 +1891,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 +2481,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==}
@ -3162,8 +3157,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': {}
@ -4377,6 +4370,11 @@ snapshots:
'@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
markdown-it-attrs@4.3.1(markdown-it@14.1.0):
dependencies:
markdown-it: 14.1.0
@ -4962,11 +4960,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`,
@ -96,7 +91,10 @@ const clientTypes: RollupOptions = {
},
external: typesExternal,
plugins: [
dts({ respectExternal: true }),
dts({
respectExternal: true,
tsconfig: 'tsconfig.json'
}),
{
name: 'cleanup',
async closeBundle() {

@ -1,6 +1,6 @@
<script setup lang="ts">
import docsearch from '@docsearch/js'
import { useRouter } from 'vitepress'
import { useRoute, useRouter } from 'vitepress'
import type { DefaultTheme } from 'vitepress/theme'
import { nextTick, onMounted, watch } from 'vue'
import { useData } from '../composables/data'
@ -10,6 +10,7 @@ const props = defineProps<{
}>()
const router = useRouter()
const route = useRoute()
const { site, localeIndex, lang } = useData()
type DocSearchProps = Parameters<typeof docsearch>[0]
@ -50,8 +51,18 @@ function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) {
navigator: {
navigate({ 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)
}
}
},
transformItems(items) {
@ -60,6 +71,17 @@ function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) {
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

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

@ -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) => void
preConfig?: (md: MarkdownItAsync) => void
/**
* Setup markdown-it instance
*/
config?: (md: MarkdownIt) => void
config?: (md: MarkdownItAsync) => 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,11 @@ 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'
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 +50,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,15 +70,13 @@ 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
}
@ -136,7 +127,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,14 +136,7 @@ export async function highlight(
.replace(vueRE, '')
.toLowerCase() || defaultLang
if (!loadLanguage(lang)) {
logger.warn(
c.yellow(
`\nThe language '${lang}' is not loaded, falling back to '${defaultLang}' for syntax highlighting.`
)
)
lang = defaultLang
}
await loadLanguage(lang)
const lineOptions = attrsToLines(attrs)
const mustaches = new Map<string, string>()

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

@ -61,9 +61,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

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

Loading…
Cancel
Save