Skip to content

安装

NPM versionNPM downloadsGitHub

使用 npm 或 使用 CDN 安装:

sh
npm install -D shiki
sh
yarn add -D shiki
sh
pnpm add -D shiki
sh
bun add -D shiki

集成

我们也提供了一些集成:

使用方法

简写

使用 shiki 的最快方式是使用我们提供的简写函数。它会根据需求加载必要的主题和语言,并自动将其缓存到内存中。

将你的代码片段传给 codeToHtml 函数并指定 langtheme,它将返回一个带有高亮显示的 HTML 字符串,你可以将其嵌入到页面中。生成的 HTML 中,每个标签都有相应的内联样式,因此你不需要额外的 CSS 来进行样式设置。

ts
import { 
codeToHtml
} from 'shiki'
const
code
= 'const a = 1' // 输入代码
const
html
= await
codeToHtml
(
code
, {
lang
: 'javascript',
theme
: 'vitesse-dark'
})
console
.
log
(
html
) // 带有高亮显示的 HTML 字符串

更进一步,你还可以使用 codeToTokenscodeToHast 来获取中间数据结构,并自行渲染它们:

ts
import { 
codeToTokens
} from 'shiki'
const {
tokens
} = await
codeToTokens
('<div class="foo">bar</div>', {
lang
: 'html',
theme
: 'min-dark'
})
ts
import { 
codeToHast
} from 'shiki'
const
hast
=
codeToHast
('.text-red { color: red; }', {
lang
: 'css',
theme
: 'catppuccin-mocha'
})

高亮器用法

因为我们使用了 WASM,所以提供的 简写 是异步执行的,并在内部按需加载主题和语言。在某些情况下,你可能需要同步地高亮代码,因此我们提供了 getHighlighter 函数来创建一个可以在后续同步使用的高亮器实例。

用法与 shiki 基本相同,其中,每个主题和语言文件都是动态导入的 ES 模块。最好显式地列出语言和主题以获得最佳性能。

ts
import { 
getHighlighter
} from 'shiki'
// `getHighlighter` 是异步的,它会初始化内部(internal) // 并加载指定的语言和主题。 const
highlighter
= await
getHighlighter
({
themes
: ['nord'],
langs
: ['javascript'],
}) // 然后你就可以同步地使用 `highlighter.codeToHtml` // 并使用你刚刚指定的其中一个主题和语言。 const
code
=
highlighter
.
codeToHtml
('const a = 1', {
lang
: 'javascript',
theme
: 'nord'
})

此外,如果要在创建高亮器后加载主题和语言,使用 loadThemeloadLanguage 方法。

ts
// 在创建后加载主题和语言
await 
highlighter
.
loadTheme
('vitesse-light')
await
highlighter
.
loadLanguage
('css')

自 v1.0 起,shiki 要求所有的主题和语言都被显式的加载。

ts
import { 
getHighlighter
} from 'shiki'
const
highlighter
= await
getHighlighter
({
themes
: ['slack-dark'],
langs
: ['css']
})
highlighter
.
codeToHtml
(
'const a = 1', {
lang
: 'javascript',
theme
: 'slack-dark' }
)
Throw error, `javascript` is not loaded
await
highlighter
.
loadLanguage
('javascript') // load the language
// now it works

如果你想加载所有主题和语言(并不建议),你可以遍历 bundledLanguagesbundledThemes 中的所有键。

ts
import { 
bundledLanguages
,
bundledThemes
,
getHighlighter
} from 'shiki'
const
highlighter
= await
getHighlighter
({
themes
:
Object
.
keys
(
bundledThemes
),
langs
:
Object
.
keys
(
bundledLanguages
),
})
highlighter
.
codeToHtml
('const a = 1', {
lang
: 'javascript',
theme
: 'poimandres'
})

细粒度捆绑

当导入 shiki 时,所有的主题和语言都被捆绑为异步块(async chunks)。通常情况下,如果你不使用它们,你就不必在意,因为它们不会被加载。某些情况下,如果你要控制这些捆绑包的内容,你可以使用核心(shiki/core)来组合自己的捆绑包。

ts
// `shiki/core` 不包含任何主题、语言和 WASM 二进制文件
import { 
getHighlighterCore
} from 'shiki/core'
// `shiki/wasm` 包含以 BASE64 字符串内联的 WASM 二进制文件 import
getWasm
from 'shiki/wasm'
// 直接导入你需要的主题和语言模块,只有你导入的模块会被捆绑 import
nord
from 'shiki/themes/nord.mjs'
const
highlighter
= await
getHighlighterCore
({
themes
: [
// 你需要传入你导入的包,而不是字符串
nord
,
// 如果你需要块分割(chunk splitting),请使用动态导入 import('shiki/themes/material-theme-ocean.mjs') ],
langs
: [
import('shiki/langs/javascript.mjs'), // shiki 会尝试使用模块的默认导出 () => import('shiki/langs/css.mjs'), // 或者一个返回自定义语法的 getter async () =>
JSON
.
parse
(await fs.readFile('my-grammar.json', 'utf-8'))
],
loadWasm
:
getWasm
}) // 可选的,在创建后加载主题和语言 await
highlighter
.
loadTheme
(import('shiki/themes/vitesse-light.mjs'))
const
code
=
highlighter
.
codeToHtml
('const a = 1', {
lang
: 'javascript',
theme
: 'material-theme-ocean'
})

注意

简写 只在 shiki 捆绑包中可用。对于细粒度捆绑,你可以使用 createSingletonShorthands 来创建一个简写函数或者自己实现。

预设捆绑包

为了使用方便,我们还提供了一些预制的捆绑包,你可以在 捆绑包 部分了解更多信息。

使用 CJS

为了减小包的大小,shiki 以仅 ESM 的形式发布。但由于 Node.js 支持在 CJS 中动态导入 ESM 模块,你仍可以在 CJS 中使用它。

例如,以下 ESM 代码:

ts
// ESM
import { 
getHighlighter
} from 'shiki'
async function
main
() {
const
highlighter
= await
getHighlighter
({
themes
: ['vitesse-dark'],
langs
: ['javascript'],
}) const
code
=
highlighter
.
codeToHtml
('const a = 1', {
theme
: 'vitesse-dark',
lang
: 'javascript',
}) }

可以在 CJS 中写成:

ts
// CJS
async function 
main
() {
const {
getHighlighter
} = await import('shiki')
const
highlighter
= await
getHighlighter
({
themes
: ['vitesse-dark'],
langs
: ['javascript'],
}) const
code
=
highlighter
.
codeToHtml
('const a = 1', {
theme
: 'vitesse-dark',
lang
: 'javascript'
}) }

使用 CDN

要在浏览器中通过 CDN 来使用 shiki,你可以使用 esm.run 或者 esm.sh

html
<body>
  <div id="foo"></div>

  <script type="module">
    // 指定确切的版本号
    import { codeToHtml } from 'https://esm.sh/shiki@1.0.0'
    //
    // import { codeToHtml } from 'https://esm.run/shiki@1.0.0'

    const foo = document.getElementById('foo')
    foo.innerHTML = await codeToHtml('console.log("Hi, Shiki on CDN :)")', {
      lang: 'js',
      theme: 'rose-pine'
    })
  </script>
</body>

这非常高效,因为它只会按需加载语言和主题。对于上面的代码片段,只会发出四个请求(shikishiki/themes/vitesse-light.mjsshiki/langs/javascript.mjsshiki/wasm.mjs),共计传输约 200KB 的数据。

示例

Cloudflare Workers

Cloudflare Workers 不支持从二进制数据初始化 WebAssembly,因此默认的 WASM 构建将无法工作。你需要将 WASM 作为资产上传并直接导入。

同时,建议使用 细粒度捆绑 来减小捆绑的体积。

ts
import { 
getHighlighterCore
,
loadWasm
} from 'shiki/core'
import
nord
from 'shiki/themes/nord.mjs'
import
js
from 'shiki/langs/javascript.mjs'
// 将 WASM 作为资产导入 await
loadWasm
(import('shiki/onig.wasm'))
export default { async
fetch
() {
const
highlighter
= await
getHighlighterCore
({
themes
: [
nord
],
langs
: [
js
],
}) return new
Response
(
highlighter
.
codeToHtml
('console.log(\'shiki\');', {
theme
: 'nord',
lang
: 'js'
})) }, }

以 MIT 许可证发布