shikiji-twoslash
TypeScript TwoSlash 是一个 Shikiji 转换器, 提供了在代码块中的内联类型悬停。灵感来自 shiki-twoslash
。
安装
npm i -D shikiji-twoslash
不同于 shiki-twoslash
是对 shiki
的封装,这个包是 一个 Shikiji 转换器。这意味着对于任何支持 shikiji 转换器的集成,您都可以使用这个包。
import {
,
} from 'shikiji'
import {
,
} from 'shikiji-twoslash'
const = await (`console.log()`, {
: 'ts',
: 'vitesse-dark',
: [
(), // <-- here
// ...
],
})
类似于 shiki-twoslash
,输出是没有样式的。您需要添加一些额外的 CSS 来让它们看起来好看。 如果您想在浏览器或者 worker 中运行 TwoSlash,请参考 CDN Usage 章节。
渲染器
感谢 hast
的灵活性,这个转换器允许您通过 AST 来自定义输出 HTML 中每个信息的渲染。
我们内置了两个渲染器,您也可以自己创建:
rendererClassic
这是默认的渲染器,它的输出和 shiki-twoslash
一致。
您可能需要参考 shiki-twoslash
的 CSS 来使它们更好看。这里 我们也复制了 shiki-twoslash
的 CSS,但可能需要一些清理。
rendererRich
这个渲染器提供了一个更明确的类名,它总是以 twoslash-
为前缀。此外,它还对悬停信息进行语法高亮。
import { , } from 'shikiji-twoslash'
({
: () // <--
})
以下是内置的几个示例 style-rich.css
:
interface {
: string
}
const : <> = {
: 'Delete inactive users'.(),
}
.title = 'Hello'
.p- parseFloat
- parseInt
- prototype
arseInt('123', 10)
//
//
import { } from 'shikiji/core'
const = await ({})
const = 1Custom log messageconst = 1Custom error messageconst = 1Custom warning messageCustom annotation message
配置项
显示触发
当与 markdown-it-shikiji
或 rehype-shikiji
集成时,我们可能不希望 TwoSlash 在每个代码块上运行。在这种情况下,我们可以将 explicitTrigger
设置为 true
,以便仅在代码框中出现 twoslash
的代码块上运行。
import { } from 'shikiji-twoslash'
({
: true // <--
})
在 markdown 中,您可以使用以下语法来触发 TwoSlash:
```ts
// 正常代码块
```
```ts twoslash
// TwoSlash 代码块
```
秘诀
CDN 用法
WARNING
这是一个实验特性。
默认情况下,@typescript/twoslash
在 Node.js 上运行,并依赖于您的本地系统来解析 TypeScript 和导入的类型。在非 Node.js 环境中直接导入它将不起作用。
幸运的是,TwoSlash 实现了一个虚拟文件系统,允许您在内存中提供自己的文件供 TypeScript 解析。然而,如何在浏览器中加载这些文件仍然是一个挑战。感谢 TypeScript 网站,TypeScript 团队已经为通过 CDN 获取类型提供了一些实用程序,他们称之为 Automatic Type Acquisition (ATA)。
我们在构建块周围做了一些小包装,并在 twoslash-cdn
,提供了一个易于使用的 API。例如:
// TODO: Replace with explicit versions in production
import { createTransformerFactory, rendererRich } from 'https://esm.sh/shikiji-twoslash@latest/core'
import { codeToHtml } from 'https://esm.sh/shikiji@latest'
import { createStorage } from 'https://esm.sh/unstorage@latest'
import indexedDbDriver from 'https://esm.sh/unstorage@latest/drivers/indexedb'
import { createTwoSlashFromCDN } from 'https://esm.sh/twoslash-cdn@latest'
// ============= Initialization =============
// 一个使用 IndexedDB 缓存虚拟文件系统的 unstorage 示例
const storage = createStorage({
driver: indexedDbDriver({ base: 'twoslash-cdn' }),
})
const twoslash = createTwoSlashFromCDN({
storage,
compilerOptions: {
lib: ['esnext', 'dom'],
},
})
const transformerTwoSlash = createTransformerFactory(twoslash.runSync)({
renderer: rendererRich(),
})
// ============= Execution =============
const app = document.getElementById('app')
const source = `
import { ref } from 'vue'
console.log("Hi! Shikiji + TwoSlash on CDN :)")
const count = ref(0)
// ^?
`.trim()
// 在渲染之前,我们需要准备类型,以便渲染可以同步进行
await twoslash.prepareTypes(source)
// 然后渲染代码
app.innerHTML = await codeToHtml(source, {
lang: 'ts',
theme: 'vitesse-dark',
transformers: [transformerTwoSlash],
})
集成
VitePress
VitePress 从 1.0.0-rc.30
开始使用 Shikiji 来进行语法高亮。要使用这个转换器,您可以将它添加到 VitePress 配置文件中的 markdown.codeTransformers
选项中。
// .vitepress/config.ts
import { } from 'vitepress'
import { , } from 'shikiji-twoslash'
export default ({
: {
: [
({
// 这使得 TwoSlash 仅在代码块中出现 `twoslash` 时运行
: true,
// 使用 rich 渲染器
: ({
// 让 VitePress 在复制时忽略额外的元数据 DOM
// 从 VitePress 1.0.0-rc.33 开始可用
: 'vp-copy-ignore',
}),
})
]
},
})
并导入 CSS 到 .vitepress/theme/index.ts
中
// .vitepress/theme/index.ts
import 'shikiji-twoslash/style-rich.css'
export default {
// ...
}