ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Slidev 可写 Monaco 编辑器:用 {monaco-write} 在幻灯片中现场改码并直接保存回源文件

Slidev 可写 Monaco 编辑器:用 {monaco-write} 在幻灯片中现场改码并直接保存回源文件 Slidev 可写 Monaco 编辑器用 {monaco-write} 在幻灯片中现场改码并直接保存回源文件【免费下载链接】slidevPresentation Slides for Developers项目地址: https://gitcode.com/GitHub_Trending/sl/slidev可写 MonacoWritable Monaco是 Slidev 代码块增强体系中非常特别的一个能力它把「展示代码」升级为「编辑真实文件」。通过在代码块上追加{monaco-write}指令幻灯片内会渲染一个与磁盘文件双向关联的 Monaco 编辑器演讲者可以在演示live coding过程中直接修改代码并按下Ctrl/Cmd S将内容实时写回源文件。读完本文你将掌握导入语法与{monaco-write}的组合用法、可叠加的全部选项、其仅在开发服务器下生效的边界条件以及从 Markdown 解析到 WebSocket 写盘这一完整链路的底层实现原理。一、这是什么从只读展示到真写盘默认情况下无论是ts {monaco}内联代码块还是导入的代码片段幻灯片里的 Monaco 编辑器都只是「读取文件内容后展示」编辑内容不会触碰原始文件刷新页面即还原。{monaco-write}指令打破了这条边界。它的核心语义由官方文档定义为三条将 Monaco 编辑器链接到文件系统上的真实文件Links Monaco editor to actual file on filesystem编辑器内的修改直接保存到该文件Changes are saved directly to the file该能力专为现场编码演示设计Useful for live coding demonstrations。对应的功能说明见 docs/features/monaco-write.md该特性以since: v0.49.5版本引入。结合 import-snippet 导入语法since: v0.47.0即可让一段代码同时具备「高亮展示 实时可编辑 可持久化」三重身份非常适合技术演讲中的即兴改码、培训实操以及录屏演示。二、快速上手最小示例与运行前提{monaco-write}并不能直接作用于ts这种内联代码块它必须搭配代码片段导入语法使用。在任意一张幻灯片里写入 ./some-file.ts {monaco-write}然后以开发模式启动演示即可npm run dev打开对应幻灯片你会看到一个完整的 Monaco 编辑器其中的代码正是some-file.ts的当前内容。直接修改任意代码按Ctrl/Cmd S改动会被写回./some-file.ts刷新浏览器、切换到其他幻灯片再回来内容保持一致。运行前提与生效范围需要特别强调的是这个特性只在开发服务器模式下生效原因有三个均可以从源码确认负责写盘的 Vite 插件slidev:monaco-write声明了apply: serve即只挂载到开发服务器构建/导出slidev build、导出 PDF 等产物中不存在该写盘通道。见 monacoWrite.ts。客户端保存动作通过 HMR 通道import.meta.hot.send(...)发送未运行 dev server 时不存在 HMR socket。见 Monaco.vue。客户端可写开关本身由__DEV__编译宏约束writable !readonly __DEV__三者同时满足才允许保存。见 Monaco.vue。因此{monaco-write}是为演讲现场本地slidev开发预览准备的不要指望它作用于构建后的静态部署页面。三、语法全解路径、语言、region 与可叠加选项由于{monaco-write}建立在代码导入语法之上它天然继承了 snippet 导入的全部书写能力。以下形态均可用1. 路径写法相对路径 ./some-file.ts {monaco-write}相对于当前slides.md所在目录解析根目录别名 /snippets/snippet.js {monaco-write}指向幻灯片项目的根目录。官方建议把可写片段放在/snippets下便于与 Monaco 编辑器配合。2. 显式指定语言导入路径的扩展名会被自动识别为高亮语言也可以手动覆盖 /snippets/code.js ts {monaco-write}3. 只取文件的某一段region 过滤如果源文件很大只想让某一 region 出现在编辑器中保存时仍写回整个文件可以使用 VS Code 风格的#region标记 /snippets/snippet.js#region-name {monaco-write}解析器会从文件中裁剪出#region region-name到#endregion region-name之间的内容作为编辑器初始代码支持嵌套 region 与多种语言的注释风格//、/* */、#、!-- --、--、#pragma、(* *)等对应实现见 snippet.ts 中的 markers 与 findRegion。4. 与其他代码块特性叠加{monaco-write}会从 meta 中被单独剥离其余代码块选项原样传给 Monaco 组件因此可以自由组合 /snippets/snippet.js {monaco-write}{lines:true}{height:auto}{lines:true}为编辑器开启行号其余行为遵循全局lineNumbersheadmatter{height:auto}编辑器高度随输入内容自动增长也可用{height:300px}、{height:100%}等 CSS 单位固定高度更多编辑器层面的配置可参考 配置 Monaco 编辑器。叠加顺序不限{monaco-write}被识别后即从 meta 中移除剩余 JSON 通过v-bind绑定到Monaco组件见 snippet.ts 的实现。5. 与普通 Monaco 的对照ts {monaco}只读编辑体验改动不落盘用于展示与现场尝试ts {monaco-diff}双代码块差异对比编辑用~~~分隔原始与修改版本 path {monaco-write}真正的改真文件模式三种能力的对比如下表指令来源可编辑保存回文件适用场景{monaco}内联代码块内容是仅内存否现场演示、代码讲解{monaco-diff}内联代码块内~~~两侧是仅内存否展示改动前后差异{monaco-write}导入的真实文件是是现场改码、边讲边改并落地四、底层原理从 Markdown 行到磁盘写入的完整链路理解{monaco-write}的完整行为需要沿一条调用链走通四个环节对应仓库中的三处核心源码。第 1 步MarkdownIt 插件识别并改写代码块Markdown 解析阶段由 markdown-it 插件MarkdownItSnippet处理snippet.ts。当某行匹配^导入语法正则RE_SNIPPET_IMPORT时插件先按规则解析出文件路径、region、语言与 meta随后判断 meta 中是否包含{monaco-write}若包含则执行三件事把该文件路径登记进monacoWriterWhitelist白名单将文件内容经lz-string的compressToBase64压缩编码最后向文档流插入一段自定义 HTML tokenMonaco writable... code-lz... lang... v-bind... /。也就是说{monaco-write}实际是语法糖最终会编译为一个携带可写文件路径的 Monaco 组件。对应实现见 snippet.ts。代码以 Base64 压缩串内联进 HTML 是刻意的设计——编辑器即使尚未与文件系统交互也能立即渲染初始内容不依赖额外请求。第 2 步客户端 Monaco 组件注册保存动作浏览器侧内置组件 Monaco.vue 负责渲染编辑器并接管交互组件 Props 中包含writable?: string要写回的文件路径与readonly挂载后编辑器注册了一个名为slidev-save的动作绑定Ctrl/Cmd S快捷键Monaco.vue触发保存时若isWritable即writable !readonly __DEV__不成立会输出警告this monaco editor is not writable, save action is ignored并忽略本次操作条件满足则通过 HMR 通道向开发服务器发送自定义消息import.meta.hot.send(slidev:monaco-write, { file: writable, content: editor.getValue() })其中file是 slides 里书写的文件路径content是编辑器当前全部文本。需要留意编辑器自动高度与行号等选项同样作用于该组件见 Monaco.vue 的 Props 定义与默认值。第 3 步服务端插件校验并写盘开发服务器一侧Vite 插件 monacoWrite.ts 中名为slidev:monaco-write的插件通过configureServer监听每个 WebSocket 连接上的消息monacoWrite.ts白名单校验消息必须携带{ file, content }且file必须出现在monacoWriterWhitelist中——该集合只由解析阶段使用过{monaco-write}的文件填充从而保证只有幻灯片里显式声明过的文件才允许被写入非法文件会被拒绝并打印[Slidev] Unauthorized file write越界防护将路径path.resolve(userRoot, file)解析后用path.relative(userRoot, filepath)判定是否仍在项目根目录内若rel以..开头或为绝对路径即解析后逃逸出项目根目录则拒绝写入并打印Refusing monaco write outside project root真实写盘通过校验后打印[Slidev] Writing file: path日志并以utf-8编码调用fs.writeFile将内容写回磁盘。第 4 步插件注册与生命周期createMonacoWriterPlugin被统一挂载在 vite/index.ts 返回的插件数组里与 Monaco 类型加载、远程资源、HMR 补丁等插件并列。由于插件设置了apply: serve因此只参与 dev server 的插件管线——这再次印证了第一节提到的仅开发模式生效约束。五、安全须知与实用建议写入是立即且直接落盘的与「保存到内存、刷新即丢」的普通 Monaco 不同{monaco-write}一旦保存成功源文件立刻被覆盖不经过暂存区也没有撤销通道。官方文档给出的警告非常明确使用前务必备份相关文件Back up files before using - changes are saved directly。对于参加现场演示的版本库建议演示前对要修改的文件建立副本或提交一次 git commit便于一键还原演示用的片段与正式代码尽量隔离例如单独维护/snippets/下的演示文件明确告知听众/协作者保存动作会真实改动工作区避免误操作污染共享分支。服务端做了哪些保护可以从源码确认白名单机制只有写入了{monaco-write}指令、并成功解析出的文件才可被写入见 monacoWrite.ts 与 snippet.ts目录逃逸防护写盘目标被强制约束在userRoot项目根之内无法通过路径拼接写任意位置保存被readonly覆盖若同一代码块同时带只读选项isWritable计算会将其关闭保存动作被静默忽略仅在控制台告警。常见问题排查按Ctrl/Cmd S没有反应确认正在运行slidev开发服务器非构建产物预览、编辑器未处于只读状态、且代码块确实通过语法导入而非内联书写想让它自动保存而无需按键当前实现为手动Ctrl/Cmd S触发源码中没有自动定时写回逻辑如需此能力可在社区讨论或自行扩展客户端 action只想展示、禁止误改去掉{monaco-write}改回{monaco}即可恢复只读内存态。六、总结{monaco-write}是 Slidev 把「编辑器」与「代码仓库」打通的关键特性适合一切需要真实改码的演示与教学场景。它由三部分协作完成MarkdownIt 阶段的导入与白名单登记、客户端 Monaco 的Ctrl/Cmd S保存动作与 HMR 消息发送、服务端插件的白名单/越界校验与最终落盘。理解这条链路你就能在幻灯片里安全、可靠地做 live coding同时清楚何时不可用构建产物、如何防误改备份与只读。延伸阅读仓库内可写编辑器的功能说明见 docs/features/monaco-write.md导入语法全解见 docs/features/import-snippet.md普通 Monaco 与 diff 编辑器见 docs/features/monaco-editor.md编辑器全局配置见 docs/custom/config-monaco.md。【免费下载链接】slidevPresentation Slides for Developers项目地址: https://gitcode.com/GitHub_Trending/sl/slidev创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表