Visual Studio Code 原生 Notebook:从 Jupyter 体验到开放扩展生态的进化之路 文档教程【免费下载链接】vscode-docsPublic documentation for Visual Studio Code项目地址https://gitcode.com/gh_mirrors/vs/vscode-docs点击查看免费下载2021 年 8 月Visual Studio Code 团队正式宣告其 Notebook 支持迈入成年期——原生 Notebook 体验在 Stable 版本中面向全部用户开放编辑器核心能力、快捷键、主题与扩展体系全面贯通。这篇文章以 VS Code 团队官方博客《The Coming of Age of Notebooks》为主线结合本仓库的 Notebook API 文档、Jupyter Notebooks 用户指南与 1.59 版本发布说明梳理原生 Notebook 的设计理念、UI 变迁、API 架构与自定义扩展路径帮助读者理解VS Code 中的 Notebook 为什么长这样以及如何用 API 构建自己的 Notebook 体验。背景Notebook 的前世今生与数据科学团队协作Notebook——将文本、可执行代码与代码输出融为一体的一种文档形式——并不是一个新概念。1984 年Donald Knuth 提出文学编程Literate Programming思想1988 年Wolfram Mathematica 引入基于 Kernel 的 Notebook UI。真正让 Notebook 走向大众的是过去十年数据科学浪潮中 Jupyter Notebook 的崛起它成为数据科学社区的事实标准工具被用于虚拟草稿纸、数据准备任务乃至复杂的机器学习模型开发。与此同时一个显著趋势正在发生数据科学正从个人工作变成团队协作。开发者越来越多地与数据科学家并肩作战——共同准备模型训练数据集、把探索性代码重构为生产级代码、将模型推理集成到核心产品中。VS Code 团队自身也是如此他们每天用 Jupyter 扩展分析海量使用数据、验证假设还用领域专属的 GitHub Issues Notebook 跨仓库追踪 issue 与工作项评估每个版本的上线就绪度。可以说Notebook 已经成为 VS Code 项目自身运转的关键工具。原生 Notebook 支持从插件到内核级能力VS Code 团队很早就开始在核心core中构建 Notebook 支持目标明确更快、更安全并且让 VS Code 的扩展生态在 Notebook 中正常工作。在此之前Notebook 在 VS Code 中更像一个外挂体验而现在团队希望它成为工具不可分割的一部分。迁移过程与用户反馈Insiders 先行Insiders 版本用户得以持续跟进体验的演进。Stable 渐进Stable 版本上线时已有 40% 的用户在使用新的 Notebook 体验反馈总体积极。全员切换团队决定像 Nigel Tufnel 一样把音量调到 11将全部用户迁移到新实现上。遗憾的是这次切换几乎没有给用户任何预警。很多用户早上打开 VS Code发现自己熟悉的 Jupyter Notebook 界面变样了。团队在博客中为此公开致歉并承认有更好的变更发布方式——让用户清楚知道发生了什么、为什么、何时发生。这段经历也给所有平台型产品的团队留下一条经验重大 UI 变更需要更透明的发布节奏与更充分的用户告知而不是静默切换。为什么不一样让 Notebook 融入 VS Code 的心智模型最初的 Notebook 实现刻意贴近经典 Jupyter 体验——外观和行为都差不多这是一个温暖、熟悉的合理起点。但随着对 VS Code 用户工作方式的深入了解团队意识到两种体验应当相似多于差异。核心原则是Notebook 在 VS Code 中应该让人感觉自然让用户能在编写代码文件和用 Python 建模宇宙之间无缝切换。这意味着 Notebook 要尽可能复用 VS Code 的内置隐喻与熟悉快捷键在代码单元格中编写代码体验应与完整文本编辑器一致无论使用何种语言设置不应是 Notebook 专属的一套快速修复Quick Fixes、大纲Outline、源操作Source Actions、重构Refactorings、多光标Multiple-cursors、自动换行Word Wrapping、收缩/展开选区Shrink and Expand Selection、列选择模式Column Selection Mode、大小写转换Change Casing等编辑器能力完全一致用户熟悉的编辑器扩展如 Bracket Pair Colorizer、Snippets应开箱即用应能像比较源文件一样对 Notebook 进行图形化的并排差异比较。面向 Notebook 的扩展生态团队设想了一个丰富的 Notebook 扩展生态用户可以像发现主题和新的语言支持一样在 Marketplace 中搜索 Kernel 或自定义可视化器。API 甚至支持为全新领域创建非 Jupyter 的自定义 Notebook。博客中提到的两个实例REST Book扩展可编写并持久化 REST 调用输出支持自定义可视化JSON、HTML 以及自定义文档GitHub Issues Notebooks扩展基于不同的 issue 查询创建 Notebook 来管理项目VS Code 团队自身也用它来组织发布流程仓库内的endgame.github-issuesNotebook 即用于发布终局追踪。在本仓库中完整的 API 指南位于 Notebook API 文档它详细定义了扩展如何打开 Notebook 文件、执行代码单元格并以多种丰富、交互式格式渲染输出。Notebook API 架构Serializer、Controller 与 Renderer一个 Notebook 由一系列单元格cells及其输出outputs构成。单元格分为Markdown 单元格与代码单元格由 VS Code 核心渲染输出格式多样——纯文本、JSON、图片、HTML 等由 VS Code 核心渲染应用专属数据或交互式小程序则交由扩展渲染。三大核心组件各司其职组件职责NotebookSerializer从文件系统读取 Notebook 的序列化字节并反序列化为NotebookData单元格列表也负责把NotebookData再序列化写回文件系统NotebookController接收代码单元格内容执行后产生零个或多个输出格式涵盖纯文本、格式化文档、交互式小程序NotebookRenderer针对特定 mimetype 的输出数据提供渲染视图应用专属格式与交互式小程序由它负责三者协作关系序列化器 ⇄ 文档数据、控制器 → 输出、渲染器 → 展示详见 Notebook API 架构总览图。Serializer读写 Notebook 文件NotebookSerializer负责双向转换把 Notebook 文件的字节反序列化成包含 Markdown 与代码单元格的NotebookData以及反向把NotebookData序列化为字节落盘。注册方式先在package.json的contributes.notebooks声明 Notebook 类型与文件选择器再在扩展激活时调用vscode.workspace.registerNotebookSerializer。官方文档给出了一个以.notebook扩展名打开 Jupyter 格式文件的完整示例见 Notebook API 文档的 Serializer 章节核心代码如下{ contributes: { notebooks: [ { type: my-notebook, displayName: My Notebook, selector: [ { filenamePattern: *.notebook } ] } ] } }class SampleSerializer implements vscode.NotebookSerializer { async deserializeNotebook(content: Uint8Array, _token: vscode.CancellationToken): Promisevscode.NotebookData { var contents new TextDecoder().decode(content); let raw: RawNotebookCell[]; try { raw (RawNotebookJSON.parse(contents)).cells; } catch { raw []; } const cells raw.map(item new vscode.NotebookCellData( item.cell_type code ? vscode.NotebookCellKind.Code : vscode.NotebookCellKind.Markup, item.source.join(\n), item.cell_type code ? python : markdown )); return new vscode.NotebookData(cells); } async serializeNotebook(data: vscode.NotebookData, _token: vscode.CancellationToken): PromiseUint8Array { let contents: RawNotebookCell[] []; for (const cell of data.cells) { contents.push({ cell_type: cell.kind vscode.NotebookCellKind.Code ? code : markdown, source: cell.value.split(/\r?\n/g) }); } return new TextEncoder().encode(JSON.stringify(contents)); } }注意该示例仅序列化单元格文本不会持久化输出要保存输出还需在NotebookData中一并序列化/反序列化单元格的输出。要真正执行单元格则需要实现NotebookController。Controller执行代码单元格NotebookController负责执行代码单元格并产生输出。它与某个序列化器/Notebook 类型直接绑定——创建控制器时设置notebookType属性并在扩展激活时将其推入订阅列表。核心实现要点完整示例见 Notebook API 文档的 Controller 章节class Controller { readonly controllerId my-notebook-controller-id readonly notebookType my-notebook; readonly label My Notebook; readonly supportedLanguages [python]; private readonly _controller: vscode.NotebookController; private _executionOrder 0; constructor() { this._controller vscode.notebooks.createNotebookController(this.controllerId, this.notebookType, this.label); this._controller.supportedLanguages this.supportedLanguages; this._controller.supportsExecutionOrder true; this._controller.executeHandler this._execute.bind(this); } private async _doExecution(cell: vscode.NotebookCell): Promisevoid { const execution this._controller.createNotebookCellExecution(cell); execution.executionOrder this._executionOrder; execution.start(Date.now()); // 记录执行开始时间 /* 此处为实际执行逻辑 */ execution.replaceOutput([new vscode.NotebookCellOutput([vscode.NotebookCellOutputItem.text(Dummy output text!)])]); execution.end(true, Date.now()); } }若将提供NotebookController的扩展与其序列化器分开发布建议在package.json的keywords中加入notebookKernelViewTypeUpperCamelCased形式的关键词例如为github-issuesNotebook 类型提供替代内核时添加notebookKernelGithubIssues以提升扩展在打开对应类型 Notebook 时的可发现性。输出类型Text、Error 与 RichKernel 输出的格式分为三类一次单元格执行可产生多个输出并以列表展示详见 Notebook API 文档的输出类型章节Text Output最简单的输出格式仅含text字段按纯文本渲染类似常见 REPLvscode.NotebookCellOutputItem.text(This is the output...)Error Output以一致、易读的方式展示运行时错误支持标准Error对象try { /* Some code */ } catch (error) { vscode.NotebookCellOutputItem.error(error) }Rich Output最高级的输出形态同一输出可携带多种按 mimetype 区分的表示。例如一个表示 GitHub Issue 的输出可同时包含text/html格式化视图、text/x-json机器可读视图与application/github-issue供NotebookRenderer使用的交互视图execution.replaceOutput([new vscode.NotebookCellOutput([ vscode.NotebookCellOutputItem.text(bHello/b World, text/html), vscode.NotebookCellOutputItem.json({ hello: world }), vscode.NotebookCellOutputItem.json({ custom-data-for-custom-renderer: data }, application/custom), ])]);VS Code 核心默认可渲染以下 mimetypeapplication/javascript、text/html、image/svgxml、text/markdown、image/png、image/jpeg、text/plain而text/x-json、text/x-javascript、text/x-html、text/x-rust等text/x-LANGUAGE_ID格式则以内置编辑器Monaco中的代码形式渲染。若要渲染其他 mimetype则必须注册对应的NotebookRenderer。Renderer自定义输出可视化Notebook 渲染器负责接收特定 mimetype 的输出数据并提供渲染视图复杂度可从简单静态 HTML 到完全交互的 applet。官方建议用 Yeoman 模板快速起步npm install -g yo generator-code后运行yo code并选择New Notebook Renderer (TypeScript)。渲染器通过contributes.notebookRenderer声明详见 Notebook API 文档的 Renderer 章节{ contributes: { notebookRenderer: [ { id: github-issue-renderer, displayName: GitHub Issue Renderer, entrypoint: ./out/renderer.js, mimeTypes: [ ms-vscode.github-issue-notebook/github-issue ] } ] } }关键实现细节输出渲染器始终运行在独立iframe中与 VS Code 其余 UI 隔离避免相互干扰或拖慢 VS Codeentrypoint指向单个脚本文件可手写或用 Webpack/Rollup/Parcel 等打包器生成入口脚本需导出ActivationFunction来自vscode-notebook-rendererTypeScript 用户可安装types/vscode-notebook-renderer在 VS Code 就绪后渲染 UIimport type { ActivationFunction } from vscode-notebook-renderer; export const activate: ActivationFunction (context) ({ renderOutputItem(data, element) { element.innerText JSON.stringify(data.json()) } })复杂 UI 可手动创建 DOM 或用 Preact 等框架渲染进输出元素若持有 iframe 外的元素或异步过程可用disposeOutputItem清理输出被清空、单元格被删除或为新输出渲染前触发注意同一 Notebook 的所有输出都渲染在同一个 iframe 的不同元素中使用document.querySelector时必须限定在具体输出元素如element.querySelector内避免互相冲突。交互式 Notebook渲染器可通过 preload 脚本与控制器通信——VS Code 会在 iframe 中同时加载该脚本暴露全局函数postKernelMessage与onDidReceiveMessage。控制器用rendererScripts注册脚本渲染器在package.json中通过dependencies声明脚本依赖脚本侧通过postKernelMessage发送命令、onDidReceiveKernelMessage接收回包控制器侧则监听NotebookController.onDidReceiveMessage事件响应。渲染器还应先检查控制器暴露的全局对象是否存在其他 Notebook/控制器未必实现再做降级处理。与扩展宿主通信当渲染器与控制器分属两个扩展、需要向扩展宿主发起请求如打开独立编辑器时将contributes.notebookRenderer中的requiresMessaging设为optional可选值always必须消息、optional有则更佳但不强依赖、never不需要。后两者更优可保证渲染器在无扩展宿主的环境中也具备可移植性。渲染器内通过context.postMessage发送扩展宿主通过notebooks.createRendererMessaging(renderer-id)的onDidReceiveMessage接收。两个注意点扩展应添加onRenderer:your renderer id到activationEvents以保证消息送达前已在扩展宿主中激活渲染器发给扩展宿主的消息不保证全部送达用户可能在消息到达前关闭 Notebook。调试支持某些控制器如编程语言内核可能希望支持逐单元格调试。Notebook kernel 可基于调试适配器协议DAP实现直接实现 DAP或委托/转换协议给现有 Notebook 调试器如vscode-simple-jupyter-notebook样例更简单的做法是复用现有未修改的调试扩展并即时转换 DAP如vscode-nodebook样例。本仓库的 调试器扩展指南 提供了完整的调试扩展开发说明。从 1.59 版本看 Notebook 的落地形态博客发布于 2021 年 8 月正值 VS Code 1.59 版本发布周期。结合 1.59 版本发布说明 可以还原该时期的 Notebook 功能状态内置 Jupyter Notebook 支持读取*.ipynb文件的代码从 Jupyter 扩展移入新的内置扩展。这意味着在干净安装的 VS Code 中即可直接打开 Jupyter Notebook无需安装完整 Jupyter 扩展但若要执行单元格或查看使用 ipywidgets 等复杂渲染类型的输出仍需安装 Jupyter 扩展。Notebook 布局改进窗口过窄时Notebook 编辑器工具栏的次要操作会移入溢出菜单...notebook.undoRedoPerCell默认值改为true逐单元格撤销/重做代码单元格更新默认样式并新增背景色以区分单元格主题可通过notebook.cellEditorBackground自定义该颜色notebook.globalToolbarShowLabel可切换工具栏文本标签的显示。Jupyter Interactive Window升级版内置 Interactive Window 在 1.59 成为默认界面支持主题、自定义键位、Snippets 与扩展兼容旧界面可通过jupyter.enableNativeInteractiveWindow: false保留。Run By LineJupyter Notebook 的逐行运行功能简化版调试模式仍属实验特性需设置jupyter.experimental.debugging: true、安装 ipykernel 6并在单元格工具栏选择Run By Line。自定义 Notebook 布局与体验博客最后提示用户可通过设置自定义 Notebook 体验在设置编辑器中搜索tag:notebookLayout即可找到相关设置。除上面提到的notebook.undoRedoPerCell、notebook.cellEditorBackground、notebook.globalToolbarShowLabel之外Notebook 大纲Table of Contents相关设置包括notebook.outline.showMarkdownHeadersOnly、notebook.outline.showCodeCells、notebook.outline.showCodeCellSymbols具体可参见 Jupyter Notebooks 用户指南。延伸阅读Jupyter Notebooks 用户指南与数据科学工作流对用户侧的使用而言本仓库的 Jupyter Notebooks 用户指南 是配套的实操文档覆盖了完整工作流环境设置与Workspace Trust、创建/打开 Notebook、运行单个/多个/分区单元格、保存与导出、代码单元格的编辑创建、模式切换、增删移动、撤销、代码/Markdown 切换、清空输出/重启内核、行号开关、大纲Table of Contents、Notebook 中的 IntelliSense、变量浏览器与数据查看器Data Viewer、绘图保存、自定义 Notebook 差异比较diffing、Notebook 调试Run by Line、Debug Cell以及连接远程 Jupyter 服务器。数据科学方向还可参考 数据科学教程、Python 交互窗口 与 Jupyter 内核管理。结语Notebook 的成年礼用团队自己的话说VS Code 中的 Notebook 已经走过了尴尬的少年期进入自信而强健的年轻成年期。从 Jupyter 迁移过来的用户可能需要一点适应时间但换来的是Notebook 与 VS Code 编辑器体验的深度统一、内置的 Jupyter 支持、以及通过 Notebook APISerializer Controller Renderer构建任意领域自定义 Notebook 的完整能力。无论是用 Jupyter Notebook 做数据探索还是为全新领域打造自定义 Notebook 体验Notebook API 文档 都是继续深入的最佳起点——正如团队在文末所说Happy Notebooking!赞分享文档教程【免费下载链接】vscode-docsPublic documentation for Visual Studio Code项目地址https://gitcode.com/gh_mirrors/vs/vscode-docs点击查看免费下载相关推荐从工具到生态Jupyter Notebook的商业化演进之路从工具到生态Jupyter Notebook的商业化演进之路 Jupyter Notebook作为一款强大的交互式笔记本工具已从简单的代码编辑工具发展成为一后端前端数据科学推荐使用Visual Studio Code的Jupyter扩展推荐使用Visual Studio Code的Jupyter扩展 在这个数据科学与编程的时代拥有一个强大的代码编辑器和灵活的笔记本工具至关重要。这就是我们要开发工具Visual Studio Code 扩展指南全景从 Hello World 到生产级扩展的 API 使用地图Visual Studio Code 扩展指南全景从 Hello World 到生产级扩展的 API 使用地图 本篇技术指南对应 Visual Studio文档教程上一篇.NET 配置体系实战深入 Microsoft.Extensions.Configuration.Ini INI 配置提供程序下一篇Apache SkyWalking UI 部署与配置指南启动方式、连接参数与 Docker 环境变量详解创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考