news 2026/9/14 2:39:04

GraphiQL 5.x 演进全解析:Monaco 迁移、API 重构与插件系统变革(基于 `graphiql` 包 CHANGELOG 的深度解读)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
GraphiQL 5.x 演进全解析:Monaco 迁移、API 重构与插件系统变革(基于 `graphiql` 包 CHANGELOG 的深度解读)

GraphiQL 5.x 演进全解析:Monaco 迁移、API 重构与插件系统变革(基于graphiql包 CHANGELOG 的深度解读)

【免费下载链接】graphiqlGraphiQL & the GraphQL LSP Reference Ecosystem for building browser & IDE tools.项目地址: https://gitcode.com/GitHub_Trending/gr/graphiql

导读

graphiql包是 GraphiQL 图形化交互式浏览器端 GraphQL IDE 的核心发布单元,其 CHANGELOG.md 记录了从 0.13.x 到 5.4.0 的完整演进历史。本文以这份 2500 余行的变更日志为骨架,梳理 GraphiQL 近几个大版本的关键技术脉络:编辑器从 CodeMirror 迁移到 Monaco、React Context 状态管理重构为 zustand、插件体系从静态属性演变为可组合的独立包、以及大量 props 的增删改名。读完后,你将掌握 GraphiQL 5.x 的配置方式、迁移路径(尤其从 4.x/3.x/2.x 升级)、插件定制方法,以及这些变更背后的源码级实现依据。


一、版本演进主线:三个里程碑式重构

从 packages/graphiql/CHANGELOG.md 可以梳理出graphiql包(当前版本 5.4.0,见 packages/graphiql/package.json)的技术演进脉络,其中三次架构级重构定义了现代 GraphiQL 的形态:

版本类型核心变更
1.0.0里程碑Headers 编辑器加入,引入@graphiql/toolkitcreateGraphiQLFetcher支持@defer/@streamgraphql-ws
2.0.0破坏性GraphiQL重构为函数组件,移除全部静态属性,推出暗色主题与 settings 对话框,编辑器工具与插件可见性改为受控 props
3.x增量defaultTabsdisableTabsforcedThemeconfirmCloseTabclassNamedefaultTheme等 props 加入
4.0.0破坏性移除默认导出(改为命名导出{ GraphiQL })、支持 React 19、工具栏改为 render props、@graphiql/react全面迁移 React Context 到 zustand
5.0.0破坏性CodeMirror 迁移到 Monaco Editor,支持同页多个独立实例,移除 UMD 构建,新增initialQuery等 props
5.3.0 / 5.4.0增量customScalarSchemas支持、GraphQL 17 fragment arguments 实验性语法支持

CHANGELOG 中同时可以观察到包依赖关系的变化:graphiql聚合了@graphiql/react@graphiql/plugin-doc-explorer@graphiql/plugin-history@graphiql/toolkit在 5.x 移入 devDependencies)。这与 packages/graphiql/package.json 中dependencies字段一致。


二、GraphiQL 5.x:Monaco 编辑器迁移与新一代 IDE

2.1 从 CodeMirror 到 Monaco

5.0.0(PR #3234)完成了一次影响深远的编辑器底座替换:monaco-graphql取代codemirror-graphql,编辑器内核从 CodeMirror 换成 Monaco Editor。这一变更带来的直接收益包括:

  • Variables 与 Headers 编辑器支持注释(Monaco 的 JSONC 能力),此前仅支持严格 JSON;
  • 操作编辑器中点击类型引用打开文档的功能改为按住Cmd(macOS)或Ctrl(Windows/Linux)点击;
  • 移除了keyMapprop —— 如需 Vim/Emacs 键位,在 Monaco 生态中需借助社区插件(如 monaco-vim、monaco-emacs)。

在源码层面,迁移后的编辑器能力由 packages/graphiql-react/src/stores/editor.ts 与 packages/graphiql-react/src/utility/create-editor.ts 提供,而语言服务则由独立的 packages/monaco-graphql 包承载。

2.2 Monaco Web Worker 的三种配置方式

从 5.0.0 起,使用 GraphiQL 必须为 Monaco 配置 Web Worker(详见 docs/migration/graphiql-5.0.0.md):

Vite 项目:安装并配置vite-plugin-monaco-editor,同时声明editorWorkerServicejson两个内置 worker 和monaco-graphql的 GraphQL worker:

// vite.config.mjs import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import $monacoEditorPlugin from 'vite-plugin-monaco-editor' const monacoEditorPlugin = $monacoEditorPlugin.default ?? $monacoEditorPlugin export default defineConfig({ plugins: [ react(), monacoEditorPlugin({ languageWorkers: ['editorWorkerService', 'json'], customWorkers: [ { label: 'graphql', entry: 'monaco-graphql/esm/graphql.worker.js' } ] }) ] })

参考实现见 examples/graphiql-vite/vite.config.mjs。

Webpack / Turbopack 项目(含 Next.js):直接导入官方提供的 setup-workers 入口:

import 'graphiql/setup-workers/webpack';

ESM CDN(esm.sh):通过?worker查询参数将模块作为 Web Worker 加载,并配置globalThis.MonacoEnvironment.getWorker按 label 分发:

import createJSONWorker from 'https://esm.sh/monaco-editor/esm/vs/language/json/json.worker.js?worker'; import createGraphQLWorker from 'https://esm.sh/monaco-graphql/esm/graphql.worker.js?worker'; import createEditorWorker from 'https://esm.sh/monaco-editor/esm/vs/editor/editor.worker.js?worker'; globalThis.MonacoEnvironment = { getWorker(_workerId, label) { switch (label) { case 'json': return createJSONWorker(); case 'graphql': return createGraphQLWorker(); } return createEditorWorker(); }, };

完整示例见 examples/graphiql-cdn/index.html。该示例同时记录了两次与 esm.sh 缓存相关的版本修复(5.2.2、5.2.4):将monaco-editorpeer 依赖固定到>= 0.20.0 < 0.53(monaco-graphql 尚未支持0.53.0),并在 5.2.1 中精确固定到0.52.2

2.3 移除的 props 与源码级兜底

5.0.0 移除了queryvariablesheadersresponse四个受控 props,改用一次性初始化的initialQueryinitialVariablesinitialHeaders。同时被移除的还有readOnlykeyMapvalidationRules(自定义校验需借助 monaco-graphql 的自定义 worker 实现)。

这些已移除的 props 在 packages/graphiql/src/GraphiQL.tsx 中仍有防御性代码:一旦检测到toolbar.additionalContenttoolbar.additionalComponentkeyMapreadOnly传入,会直接抛出带迁移提示的TypeError,帮助开发者尽早发现升级遗漏。

另外,defaultQuery的语义在 5.0.0 中被修正:它只作用于第一个标签页,新建标签页时操作编辑器从空内容开始。

2.4 Next.js 服务端渲染与动态导入

5.1.0 起 GraphiQL 在内部动态导入monaco-editormonaco-graphql,因此在 Next.js App Router 中不再需要next/dynamic包裹:

-import dynamic from 'next/dynamic' -const GraphiQL = dynamic(() => import('graphiql').then(mod => mod.GraphiQL), { - ssr: false -}) +import { GraphiQL } from 'graphiql'

配套示例为 examples/graphiql-nextjs 以及新增的 examples/graphiql-vite-react-router(Vite + React Router +ssr: true)。SSR 相关的历史修复还包括 4.0.3 消除useLayoutEffect的 SSR 警告、2.4.7 修复 Next.js 中window is not defined、1.0.x 的一系列服务端渲染修复。


三、Props 演进全景:新增、移除与重命名

CHANGELOG 是 props 演进的完整档案。汇总如下:

3.1 新增 props(按引入版本)

版本Prop说明
5.0.0initialQuery/initialVariables/initialHeaders仅初始化第一个标签页
5.0.0externalFragments从查询外部提供 fragment 定义(替代被移除的validationRules
5.3.0customScalarSchemas透传给 monaco-graphql,覆盖自定义标量的 JSON Schema 校验
5.4.0experimentalFragmentArguments启用 GraphQL 17 fragment 参数语法的解析/校验/补全(默认false
4.0.0onPrettifyQuery自定义查询格式化回调
3.7.0defaultTheme设置默认颜色主题偏好
3.6.0confirmCloseTab控制关闭标签页时的确认行为
3.4.0className追加到 GraphiQL 容器元素的类名
3.3.0forcedTheme强制主题并隐藏主题切换器
3.1.0disableTabs禁用标签页(4.0.0 移除)
2.1.0defaultHeaders默认请求头
2.0.0onTabChange/visiblePlugin/onTogglePluginVisibility/defaultEditorToolsVisibility/isHeadersEditorEnabled/responseTooltip受控化 API
1.6.0onSchemaChangeschema 获取成功后回调
1.4.3maxHistoryLength历史记录最大条数(默认 20)

3.2 移除 / 重命名 props 对照

新 / 替代移除版本
默认导出import GraphiQL from 'graphiql'命名导出import { GraphiQL } from 'graphiql'4.0.0
query/variables/headers/responseinitialQuery/initialVariables/initialHeaders5.0.0
readOnly移除5.0.0
keyMap社区 Monaco 插件5.0.0
validationRulesmonaco-graphql 自定义 worker5.0.0
disableTabs移除(标签页恒启用)4.0.0
toolbar.additionalContent/additionalComponentGraphiQL.Toolbarrender props4.0.0
defaultVariableEditorOpen/defaultSecondaryEditorOpendefaultEditorToolsVisibilitytrue/false/"variables"/"headers"2.0.0
docExplorerOpen/onToggleDocs/onToggleHistoryvisiblePlugin/onTogglePluginVisibility2.0.0
headerEditorEnabledisHeadersEditorEnabled2.0.0
ResultsTooltipresponseTooltip2.0.0
tabs={{ onTabChange }}onTabChange直接作为 prop2.0.0
initialTabsdefaultTabs3.0.0
graphiql/graphiql.cssgraphiql/style.css(5.0.4 起额外提供不含字体与 monaco 样式的graphiql.css4.0.0

3.3 主题相关 props 的细节

  • defaultTheme(3.7.0):设置默认主题偏好,用户仍可在设置对话框中切换;
  • forcedTheme(3.3.0):强制锁定主题并隐藏切换器,适用于将 GraphiQL 嵌入到已有明暗色方案的宿主页面;
  • 2.0.0 起 GraphiQL 自带暗色主题,默认跟随系统设置。

3.4 schema 相关能力

  • 1.10.0 起允许直接向schemaprop 传入 introspection 数据;
  • 5.2.3 修复了传入IntrospectionQuery数据时仍触发网络 introspection 的问题 —— 现在会用buildClientSchema直接从数据构建 schema 并跳过 introspection,shouldIntrospect检查覆盖了原始 introspection 数据而非仅GraphQLSchema实例;
  • 4.1.0 修复 introspection 请求重试时请求头未携带的问题;
  • 1.9.11 修复onSchemaChange在 schema 获取后不再被调用的问题。

四、插件系统:从静态属性到可组合插件包

4.1 静态属性时代的终结

2.0.0 之前,GraphiQL.QueryEditorGraphiQL.VariableEditorGraphiQL.HeaderEditorGraphiQL.ResultViewerGraphiQL.ButtonGraphiQL.MenuGraphiQL.MenuItem等静态属性承载了 UI 扩展能力。2.0.0 全部移除,改为从@graphiql/react引入对应组件(QueryEditorVariableEditorHeaderEditorResponseEditorToolbarButtonToolbarMenu等);formatResultformatErrorfillLeafsmergeAstgetSelectedOperationName等工具函数与Fetcher系列类型则迁移到@graphiql/toolkit

4.2 Toolbar 的 render props 化

4.0.0 用GraphiQL.Toolbarrender props 取代了toolbar.additionalContent/toolbar.additionalComponent

<GraphiQL> <GraphiQL.Toolbar> {({ merge, prettify, copy }) => ( <> {prettify} {merge} {copy} <button>My button</button> </> )} </GraphiQL.Toolbar> </GraphiQL>

render props 还可以重新排序或移除默认按钮:

<GraphiQL> <GraphiQL.Toolbar> {({ prettify, copy }) => ( <> {copy /* Copy button will be first instead of default last */} {/* Merge button is removed from toolbar */} {prettify} </> )} </GraphiQL.Toolbar> </GraphiQL>

此外 4.0.0 为GraphiQL.Toolbar增加了children: ReactNode支持,工具栏实现位于 packages/graphiql/src/ui/toolbar.tsx。

4.3 插件独立分包与默认插件覆盖

4.0.x 起,文档浏览器(Doc Explorer)与历史记录(History)从@graphiql/react拆分为独立包@graphiql/plugin-doc-explorer@graphiql/plugin-history,并将@graphiql/react移入它们的peerDependencies(5.1.0)。至此graphiql聚合了三个官方插件能力,同时在 5.0.0 提供了覆盖全部默认插件的能力:

  • referencePlugin:负责选中类型时展示参考文档的插件,默认DOC_EXPLORER_PLUGIN
  • plugins:侧边栏插件数组,默认[HISTORY_PLUGIN]

从 packages/graphiql/src/GraphiQL.tsx 可以看到这两个默认值:

const GraphiQL_: FC<GraphiQLProps> = ({ maxHistoryLength, plugins = [HISTORY_PLUGIN], referencePlugin = DOC_EXPLORER_PLUGIN, ...

移除全部默认插件:

import { GraphiQL } from 'graphiql'; function App() { return ( <GraphiQL referencePlugin={null} // 移除 Doc Explorer plugins={[]} // 移除 History /> ); }

在保留默认插件的同时追加自定义插件(例如 Explorer):

import { GraphiQL, HISTORY_PLUGIN } from 'graphiql'; import { explorerPlugin } from '@graphiql/plugin-explorer'; const myPlugins = [HISTORY_PLUGIN, explorerPlugin()]; function App() { return <GraphiQL plugins={myPlugins} />; }

若使用自定义 Doc Explorer,必须传入referencePlugin(而非plugins数组),它会自动被包含并始终渲染在最前。GraphiQL 5 的公开导出(GraphiQLGraphiQLInterfaceGraphiQLPropsGraphiQLInterfacePropsHISTORY_PLUGIN)可见于 packages/graphiql/src/index.ts。

4.4 Hooks 体系重构

伴随 zustand 迁移,5.0.0 新增useGraphiQL/useGraphiQLActions,将 store 的状态与动作分离;同时废弃useThemeuseStorage(5.1.0)改为从useGraphiQL取值。4.x 时代经历过多轮 hooks 改名:

  • useExplorerContextuseDocExplorer/useDocExplorerActions(4.0.4);
  • useHistoryContextuseHistory/useHistoryActions(4.0.3);
  • useStorageContextuseStorageuseSchemaContextuseSchemaStoreusePluginContextusePluginStore(4.0.5);
  • useEditorContextuseEditorStoreuseExecutionContextuseExecutionStore(4.1.0);
  • 5.0.0 移除useQueryEditoruseVariableEditoruseHeaderEditoruseResponseEditor等底层 hooks,并将StorageContextProvider等重命名为StorageStoreEditorStoreSchemaStoreExecutionStoreHistoryStoreExplorerStore

五、状态管理重构:React Context 到 zustand

4.x 系列(4.0.3 至 4.1.2)分阶段将@graphiql/react的 React Context 迁移到 zustand store。CHANGELOG 中体现的关键动机是多实例隔离

  • 5.0.0 起允许同页存在多个相互独立的 GraphiQL 实例;
  • 5.0.3 为每个实例的存储键增加唯一后缀,例如第一个实例使用1-operation.graphql1-request-headers.json1-variables.json1-response.json,第二个实例则为2-前缀;
  • 5.1.0 确保storagethemestore 的值不在多个 GraphiQL 实例间共享;
  • 4.1.1 回退了先前破坏多实例支持的改动以恢复该能力。

状态 store 的实现分布在 packages/graphiql-react/src/stores(editor.tsexecution.tsplugin.tsschema.tsstorage.tstheme.ts等),仓库的__mocks__/zustand.mts表明测试环境也同步适配了 zustand。


六、主题、快捷键与命令面板

  • 主题:2.0.0 引入暗色主题与 settings 对话框,默认跟随系统;3.3.0forcedTheme、3.7.0defaultTheme进一步开放控制;3.3.2 修复 alpha 为 1 时使用hsl而非hsla的细节。
  • 快捷键:5.2.0 新增Cmd/Ctrl + ,打开设置对话框;5.0.0 按操作系统修正运行查询快捷键的文案显示(macOS 与 Windows/Linux 不同);3.7.1 将文档搜索框占位符中的⌘ K修正为非 mac 设备显示Ctrl K(改用navigator.userAgent判断);2.4.6 起通过useMemo/useCallback减少不必要的渲染。
  • 命令面板:5.2.0 调整了命令面板宽度、边框并移除box-shadow;5.0.0 将 F1 命令作为快捷键表首项,并将命令面板聚焦项前景色设为 GraphiQL 主色。
  • 编辑器体验:5.0.2 为 monaco 编辑器启用字体连字(font ligatures),同时修复 Windows 上光标位置错误;5.2.0 为操作编辑器增加初始加载指示器。

七、性能、体积与分发形态

  • 体积优化:5.0.6 将prettier改为动态导入,避免将其打进主包。CHANGELOG 记录的 Vite 示例打包结果从4,911.53 kB (gzip 1,339.77 kB)降至4,221.28 kB (gzip 1,145.58 kB);5.0.4 新增不含字体和 monaco 样式的graphiql.css以便按需引入。
  • 构建迁移:4.0.0 从 webpack 迁移到 Vite,CSS 导出从graphiql/graphiql.css变为graphiql/style.css,CDN 路径从graphiql/graphiql.js等变为graphiql/dist/index.umd.js(Umd 产物已 minify);5.0.0 彻底移除 UMD 构建,CDN 用户改用 esm.sh 加载 ESM(见 examples/graphiql-cdn/index.html)。
  • tree-shaking 友好:5.2.3 为package.json增加"*.css"sideEffects,允许 Webpack 工程安全地import 'graphiql/style.css';5.4.0 的 packages/graphiql/package.json 中sideEffects["dist/setup-workers/*", "*.css"]
  • 内部实现:5.0.3 用 jsonc 解析器(开启allowTrailingComma)同步解析 introspection 请求头,并用 prettier 统一格式化操作编辑器;5.0.0 将onClickReference存入 query editor 的 React ref,并从变量编辑器移除该回调。
  • 多包联动:4.0.0 支持 React 19(peer 范围变为^18 || ^19)、移除 React 16/17 支持,同时弃用ReactDOM.render,改用createRoot(...).render();依赖的@radix-ui@headlessui/react同步升级。3.9.0 起graphiql包本身迁移到 Vite + React Compiler。

八、安全修复与兼容性

  • introspection schema 模板注入(XSS):1.4.7 发布了针对 GraphiQL introspection schema 模板注入攻击的CRITICAL SECURITY PATCH,相关漏洞背景与防护可参考 docs/security/2021-introspection-schema-xss.md。
  • 依赖安全:1.8.1 用set-value替换存在原型污染漏洞的dset(该风险仅在启用实验性@stream/@defer且 schema 含prototype/constructor等恶意字段名时被利用);1.4.3 移除含漏洞的subscriptions-transport-ws
  • 版本支持矩阵:当前 packages/graphiql/package.json 的 peer 依赖为graphql: ^15.5.0 || ^16.0.0 || ^17.0.0react/react-dom: ^18 || ^19。3.5.0 起支持graphql-js@17.0.0-alpha.2及后续版本,包含最新增量交付(incremental delivery)响应格式;5.4.0 进一步以experimentalFragmentArguments: true开启 GraphQL 17 fragment 参数语法(解析、校验、类型信息、补全、hover 与编辑器集成全链路),并修复变量补全对操作/fragment 作用域的限制。
  • fetcher 能力:1.4.0 起createGraphiQLFetcher支持@defer/@streamgraphql-ws订阅;1.4.1 允许传入legacyClient以兼容graphql-transport-ws;1.3.0 起 fetcher 可返回Promise<Observable>Promise;1.2.0 增加 AsyncIterable 支持。

九、配套资源与迁移路径

升级到现代 GraphiQL 时可参考以下仓库内资源:

  • 迁移指南:docs/migration/graphiql-2.0.0.md(类组件→函数组件、静态属性→组件/hooks、插件 props 重构)、docs/migration/graphiql-4.0.0.md(默认导出→命名导出、Toolbar render props)、docs/migration/graphiql-5.0.0.md(Monaco worker 配置、props 移除清单、插件覆盖)。
  • 示例工程:examples/graphiql-vite、examples/graphiql-nextjs、examples/graphiql-cdn、examples/graphiql-webpack、examples/graphiql-vite-react-router。
  • 测试保障:单元测试使用 vitest(3.8.0 由 jest 迁移),端到端测试使用 Cypress,覆盖 docs、errors、graphql-ws、headers、history、incremental-delivery、init、keyboard、lint、prettify、tabs、theme 等场景,测试用例位于 packages/graphiql/cypress/e2e。

结语

透过graphiql包的 CHANGELOG,可以清晰地看到 GraphiQL 从 CodeMirror 单文件 IDE 演进为基于 Monaco、zustand 与插件化架构的现代 GraphQL 开发工具的完整轨迹。对使用者而言,最关键的三个升级抓手是:5.0.0 的 Monaco worker 配置与initial*props4.0.0 的命名导出与 Toolbar render props、以及2.0.0 的静态属性移除与受控插件 API。掌握这些变更及其在 packages/graphiql/src/GraphiQL.tsx 等源码中的落点,即可在自有产品中平稳完成 GraphiQL 的版本升级与深度定制。

【免费下载链接】graphiqlGraphiQL & the GraphQL LSP Reference Ecosystem for building browser & IDE tools.项目地址: https://gitcode.com/GitHub_Trending/gr/graphiql

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 2:37:37

机器学习算法源码实战:从DCGAN到DDPG的工程解析

简介&#xff1a;一套基于Python的机器学习算法设计源码&#xff0c;面向机器学习开发者、学生及科研人员&#xff0c;覆盖数据预处理、特征工程、经典监督/无监督学习和深度学习模型&#xff0c;既可作为算法学习的配套代码&#xff0c;也能帮助快速搭建实验原型。压缩包共35个…

作者头像 李华
网站建设 2026/9/14 2:36:30

猕猴桃遗传转化技术研究与应用

1. 猕猴桃遗传转化的背景与意义猕猴桃作为一种经济价值极高的水果作物&#xff0c;其遗传改良一直是农业生物技术领域的研究热点。传统育种方法周期长、效率低&#xff0c;而遗传转化技术能够直接导入目标基因&#xff0c;大幅缩短育种周期。我在实验室从事猕猴桃遗传转化研究已…

作者头像 李华
网站建设 2026/9/14 2:35:55

基于LSTM的蔬菜价格预测:从数据预处理到模型部署全流程解析

简介&#xff1a;这是一份面向计算机专业毕业设计及课程设计场景的深度学习实战资源&#xff0c;聚焦基于LSTM的蔬菜价格预测任务。项目包含Python源码、项目说明文档与真实蔬菜价格数据集&#xff0c;能够覆盖数据预处理、模型训练、评估与预测的完整流程&#xff0c;适合正在…

作者头像 李华
网站建设 2026/9/14 2:33:52

1989-2020年中国滨海滩涂湿地遥感数据集处理与面积统计指南

简介&#xff1a;针对中国北纬18度以北沿海滩涂湿地&#xff0c;这份数据集收录了1989—2020年间32个年份的分布时空变化信息&#xff0c;适合生态学、地理学、环境科学及城市规划领域的研究人员&#xff0c;用于分析湿地面积增减、岸线迁移与退化恢复趋势。压缩包内共256个文件…

作者头像 李华
网站建设 2026/9/14 2:33:39

AI模型配置统一管理:从混乱到契约的实践指南

1. 为什么“装了好几个AI工具”反而让模型配置成了新负担我上周帮一位做智能硬件原型的同事排查一个奇怪问题&#xff1a;他在 VS Code 里用 Cursor 调用 Claude 3.5 时响应飞快&#xff0c;但切到 JetBrains 的 IDE AI Assistant 同样请求却卡在“加载中”&#xff0c;等三分钟…

作者头像 李华
网站建设 2026/9/14 2:32:02

Sangfor PWE卸载不干净?服务、驱动、注册表残留的完整清理指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华