首页
/ Slidev Monaco 编辑器完整配置指南:setup 文件、自动类型、Shiki 主题与代码运行选项

Slidev Monaco 编辑器完整配置指南:setup 文件、自动类型、Shiki 主题与代码运行选项

2026-09-05 21:54:57作者:盛欣凯Ernestine

本篇围绕 Slidev 的 Monaco 编辑器定制能力展开:如何编写 setup/monaco.ts 接入 defineMonacoSetup、如何让编辑器自动获取依赖类型、如何复用 Shiki 主题保持一致的视觉风格,以及如何通过 frontmatter 控制启用范围与严格模式。读完后可在 Slidev 幻灯片中直接落地一个类型提示完整、主题统一、行为可控的 Monaco 代码编辑环境。

编写 Monaco 配置文件 setup/monaco.ts

Slidev 允许在客户端通过一个独立的 setup 文件对 Monaco 进行全局定制。在项目根目录创建 ./setup/monaco.ts,从 @slidev/types 导入 defineMonacoSetup 并导出一个接收 monaco 实例的函数:

import { defineMonacoSetup } from '@slidev/types'

export default defineMonacoSetup(async (monaco) => {
  // use `monaco` to configure
})

defineMonacoSetup 本质上是一个类型包装函数,定义在 setups.ts

// client side
export type MonacoSetup = (m: typeof monaco) => Awaitable<MonacoSetupReturn | void>

function defineSetup<Fn>(fn: Fn) {
  return fn
}

export const defineMonacoSetup = defineSetup<MonacoSetup>

其返回值类型 MonacoSetupReturn 目前仅包含可选的 editorOptions 字段(setups.ts):

export interface MonacoSetupReturn {
  editorOptions?: monaco.editor.IEditorOptions
}

仓库内的实际示例位于 demo/composable-vue/setup/monaco.ts,演示了如何用 typescriptDefaults.addExtraLib 注入一段虚拟类型声明,让编辑器识别自定义的 InjectionKey

import { defineMonacoSetup } from '@slidev/types'

export default defineMonacoSetup((monaco) => {
  monaco.typescript.typescriptDefaults.addExtraLib(
    `
    import { InjectionKey } from 'vue'
    export interface UserInfo { id: number; name: string }
    export const injectKeyUser: InjectionKey<UserInfo> = Symbol()
    `,
    'file:///root/context.ts',
  )
})

从源码结构看,该 setup 文件的执行时机在 packages/client/setup/monaco.ts 中被统一管理。整个 Monaco 初始化被封装为单例 Promise(monaco.ts),流程大致为:

  1. 先注册 MonacoEnvironment worker 路由:json 使用 JsonWorkercss/scss/less 使用 CssWorkerhtml/handlebars/razor 使用 HtmlWorkertypescript/javascript 使用 TsWorker,其余语言回退到 EditorWorkerL26-L38);
  2. 设置 TypeScript 编译器默认选项:strict: truemoduleResolution: NodeJsmodule: ESNextL59-L65);
  3. 依次执行所有用户 setups/monaco.ts,并把各自返回的 editorOptions 合并进全局配置(L98-L102);
  4. 注册 Shiki 高亮(后文详述)。

此外还有一处细节:编辑器获得焦点时会调用 lockShortcuts() 锁定 Slidev 的全局快捷键,失焦时释放,避免在 Monaco 中输入时误触翻页等快捷键(L104-L114)。

TypeScript 类型:自动加载依赖类型

在幻灯片中使用 {monaco} 标记的代码块时,Slidev 会自动为代码中引用的依赖安装类型。例如:

```ts {monaco}
import { ref } from 'vue'
import { useMouse } from '@vueuse/core'

const counter = ref(0)
```

前提是确保 vue@vueuse/core 已作为依赖 / devDependencies 安装在本地,Slidev 会自动完成编辑器类型的工作。当项目以 SPA 形式部署时,这些类型也会被打入产物用于静态托管。

自动扫描的实现原理

这一能力由解析层与虚拟模块协作完成:

  • 解析阶段,packages/parser/src/core.ts 用正则 /\{monaco.*\}/ 检测页面是否包含 Monaco 代码块,并在命中时调用 scanMonacoReferencedMods(code) 扫描其中 import 的模块名(L163);
  • 构建阶段,虚拟模块 /@slidev/monaco-typesmonaco-types.ts 生成。它会:
    • 扫描用户项目 snippets/ 目录下所有 *.ts*.mts*.cts 文件,通过 addFile() 注入为额外 lib;
    • 把扫描到的依赖与 frontmatter 中 monacoTypesAdditionalPackages 合并、去重;
    • 通过 mapModuleNameToModule 做归一化:node: 前缀与 Node 内置模块统一映射为 nodelodash/identity 这类子路径取主包名(@scope/pkg 保留两段);
    • 过滤掉 monacoTypesIgnorePackages 中列出的包,最后为每个包生成对 /@slidev-monaco-types/resolve?pkg=... 的动态 import,由服务端在请求时解析本地 node_modules 中的类型并下发。

也就是说,类型来源默认是“本地 node_modules 扫描”,无需任何额外配置。

补充额外类型 monacoTypesAdditionalPackages

Slidev 会扫描幻灯片中所有 Monaco 代码块并自动导入被引用库的类型。若它遗漏了某些包(例如类型是通过间接方式引用),可以显式声明额外需要导入类型的包:

---
monacoTypesAdditionalPackages:
  - lodash-es
  - foo
---

与类型加载相关的前置项还包括 monacoTypesIgnorePackages(忽略某些包,避免误注入)与 monacoRunAdditionalDeps(为可运行代码补充本地依赖模块),二者在 frontmatter.ts 中均有类型定义,VS Code 扩展的 JSON Schema headmatter.json 也对其提供了完整的补全与说明。

自动类型获取 monacoTypesSource

可以切换到从 CDN 加载类型的模式,对应配置:

---
monacoTypesSource: 'cdn'
---

该配置取值为 'local' | 'cdn' | 'none'(默认 'local',见 config.ts 中的默认值与 headmatter.json 的枚举定义)。cdn 模式由 @typescript/ata 驱动,且完全运行在客户端:在 packages/client/setup/monaco.ts 中,仅当 configs.monacoTypesSource === 'cdn' 时才调用 setupTypeAcquisition,其 receivedFile 回调把拉取到的声明文件通过 defaults.addExtraLib 注入 Monaco 的 TypeScript 默认实例,并用 monaco.editor.createModel 建立对应模型;progress 回调还会以 [Typescript ATA] downloaded / total 的形式在控制台输出下载进度。本地模式下则直接由 monaco-types.ts 虚拟模块按包解析注入(前述流程)。

主题配置:复用 Shiki 主题

自 v0.48.0 起,Monaco 会复用你在 Shiki 配置文件 中配置的 Shiki 主题,由 @shikijs/monaco 驱动,无需单独为编辑器指定主题,从而保证 Monaco 编辑区与其余代码块高亮风格一致。

源码印证见 packages/client/setup/monaco.ts:初始化时会先通过 getEagerHighlighter() 获取 Shiki 高亮器并调用 shikiToMonaco(highlighter, monaco) 完成主题映射;随后根据 themeOption 的类型决定行为——

  • 若主题是一个固定字符串,直接 monaco.editor.setTheme(themeOption)
  • 若是 light/dark 双主题对象,则用 watchEffect 监听 isDark 状态变化,在深浅色间自动切换,缺省回退到 vitesse-dark / vitesse-light

因此你只需要维护 docs/custom/config-highlighter.md 中的 Shiki 主题配置,Monaco 编辑器的配色会自动跟随。

配置编辑器行为 editorOptions

自 v0.43.0 可用

如需自定义 Monaco 编辑器行为,可以传入一个符合 Monaco IEditorOptions 定义的 editorOptions 对象,作用范围有两种:

1. 单个代码块级别

直接在 Markdown 代码块的内联选项中声明:

```ts {monaco} { editorOptions: { wordWrap:'on'} }
console.log('HelloWorld')
```

2. 全局级别

希望所有 Monaco 实例都应用这些选项时,在 defineMonacoSetup 函数中返回它们:

import { defineMonacoSetup } from '@slidev/types'

export default defineMonacoSetup(() => {
  return {
    editorOptions: {
      wordWrap: 'on'
    }
  }
})

从源码看,全局 editorOptions 的合并在客户端初始化时进行:setup 循环中执行 Object.assign(editorOptions, result?.editorOptions)monaco.ts),最终随单例 setup 的返回值一同导出,供 Monaco.vue 等内置组件在创建编辑器实例时使用。

启用与禁用

自 v0.48.0 起,Monaco 编辑器默认启用,且仅在幻灯片中实际使用时才会被打包(按需引入,未使用 {monaco} 代码块时不会增加产物体积)。若想禁用它,可在幻灯片 frontmatter 中把 monaco 设为 false

---
monaco: false # can also be `dev` or `build` to conditionally enable it
---

monaco 的完整类型是 boolean | 'dev' | 'build'frontmatter.ts),默认为 trueconfig.ts):

  • true:开发与服务端渲染/构建均启用;
  • false:完全禁用;
  • 'dev':仅在开发模式启用;
  • 'build':仅在构建产物中启用。

严格模式 monacoRunUseStrict

自 v0.52.0 可用

默认情况下,Monaco 可运行代码以严格模式("use strict")执行。如果你的代码依赖非严格模式行为(例如隐式 this 或全局变量绑定差异),可以关闭:

---
monacoRunUseStrict: false
---

该选项的默认值为 trueconfig.ts 的解析默认值,以及 headmatter.json 中的 Schema 默认值一致)。配合前文提到的编辑器端编译器选项 strict: true,整个“编辑提示 + 实际运行”链路在默认配置下都保持严格的 TypeScript 语义。

配置代码运行器 Code Runners

关于 Monaco Runner 如何执行代码、以及如何为自定义语言添加运行支持,见 配置 Code Runners。可运行的本地代码块还可配合 monacoRunAdditionalDeps 选项注入额外的本地模块依赖(frontmatter.ts)。

Frontmatter 配置项速查

汇总当前仓库中 Monaco 相关的全部 frontmatter 配置项(依据 frontmatter.ts 的类型定义与 config.ts 的默认值):

配置项 类型 默认值 说明
monaco boolean | 'dev' | 'build' true 是否启用 Monaco,可按 dev/build 条件启用;未使用时代码不会被打包
monacoTypesSource 'local' | 'cdn' | 'none' 'local' 类型来源:本地 node_modules 或经 @typescript/ata 从 CDN 获取
monacoTypesAdditionalPackages string[] [] 自动扫描遗漏时,显式补充需要导入类型的包
monacoTypesIgnorePackages string[] [] 类型加载时需要忽略的包
monacoRunAdditionalDeps string[] [] 为可运行代码块补充的本地依赖模块
monacoRunUseStrict boolean true 可运行代码是否以严格模式执行

小结与延伸阅读

掌握以上内容后,你可以按需组合:用 setup/monaco.ts 做全局行为定制与额外类型声明,用 {monaco} 内联 editorOptions 做单块微调,用 monacoTypesSource / monacoTypesAdditionalPackages 精确控制类型来源,用 monacomonacoRunUseStrict 管理启用范围与运行语义,从而得到一套与幻灯片其余代码块视觉统一、提示完整的 Monaco 编辑环境。

登录后查看全文
热门项目推荐
相关项目推荐