跳转到主要内容

Oink 0.5.0 — 组件 API v5 与收敛后的配置

Oink 0.5.0 用原生 Markdown 形态取代大多数 shortcode,把全部配置键与 front matter 键收敛到三条规则上,删除 0.x 兼容层,并附带把 0.4 站点改写到位的迁移工具。 每一个旧键、旧形态、旧 shortcode 都会让构建失败并指出替代写法,而不是被静默忽略。

Oink 0.5.0 是 API 冻结版本。它包含 1.0 线将要冻结的全部变更:组件 API v5 (原生 Markdown 形态优先,29 个 shortcode 作为完整形态)、按三条规则收敛的配置键与 front matter 键、主题产出物统一的命名空间、0.x 兼容层与无人使用的 Docsy 遗留物的 删除,以及能把 0.4 站点改写到位的迁移工具。任何被退役的键、形态或 shortcode 都会让构建失败,并在错误信息里给出替代写法。

对每一个 0.4 站点来说这都是破坏性升级。请先看概览, 再看迁移指南;中间的参考章节逐项列出每一处变化的新旧形态。

概览

  • 内容:大多数组件直接用 Markdown 写——> [!TYPE] 提示块、{.steps} / {.cards} 列表、{.fields} / {.matrix} / {caption=} / {#id num=} / {tab=} 表格、```filetree / ```gallery / ```echarts / ```infographic / ```checksums 数据围栏、相邻代码围栏成标签页、 带属性行的 Markdown 图片。0.4.2 的 53 个 shortcode 中 32 个删除或改名、8 个新增, 剩下 29 个作为完整形态。scripts/migrations/oink06.py 负责改写内容。
  • 配置:三条规则——开关就是裸的特性名、单键 map 压平、front matter 键 = 站点键去掉 ui.。约四十个键改名或改形,每个旧键都会让构建失败并指出替代。 主题的全部默认值都声明在主题的 hugo.yaml 里。
  • Front matter:不再有 ui: 块;页面覆盖用裸键(section_index: cards), page_context_menu 与站点 map 同形,manualLink* 改为 manual_link*hide_* / exclude_search 删除。
  • 命名空间:主题 class 一律 td-*、data 属性 data-td-*、自定义属性 --td-*、 JS 全局 Oink*oink-* 一族和 Docsy 遗留(leafhas-childnav-* …) 消失。提示块文案改为 callout_* i18n 键。
  • 删除home/** 适配 partial、outputformat.htmltd/render-heading.html、 Docsy community 页面与 params.linkstd/code-dark / td/color-adjustments-dark / td/gcs-search-dark / td/extra 这些 Sass 文件、.td-box*-bg-* 调色 class、 Prism、Open Sans、click-to-copy.jsswaggerui(改名 swagger)。
  • 行为:标题带自链接;print 内容每次构建只渲染一次(修了一个真实的竞态); 三个可缓存的 JS bundle;print 页面加载 8 KB JS 而不是 100 KB;shell 动效在结构上 遵守 reduced-motion;giscus 调色板随主题发布并且只在渲染评论的页面加载。
  • 迁移:内容与 front matter 走 oink06.py report → migrate --write → check, 然后构建——报错就是配置清单。
  • 发布加固:API 冻结前进行了两轮对抗性评审,修复了客户端命名空间迁移、 动作注册表加载顺序、迁移输入 fail-closed、多实例 OpenAPI 嵌入、通用属性与图片 URL 策略,以及消费站配置预检。

组件 API v5

原生形态优先

v5 的原则:Markdown 块能表达的组件就用 Markdown 写;shortcode 只为块表达不了的 情形存在。渲染钩子识别原生形态,所有钩子共用一套属性策略。

组件:原生形态与完整形态

Callout 提示块 , native

> [!NOTE] Title 引用块;[!TYPE]- 折叠 / [!TYPE]+ 展开;可选 {icon="fa-solid fa-x"};类型 note tip important warning caution success danger question example quote details。没有 shortcode。

Tabs 标签页 , native + shortcode

原生:相邻围栏(或表格)加 {tab= group= value=}

Shortcode:tabs group= default= label= tab label= value=/tab /tabs

Steps 步骤 , native + shortcode

原生:1. 列表 + {.steps}

Shortcode:steps 加标题——唯一用 % 分隔符书写的 shortcode(正文是页面级 Markdown);步骤里的标题会进入页内目录。

Cards 卡片 , native + shortcode

原生:链接列表 + {.cards}

Shortcode:cards card title= link= icon= badge= image= image_alt=|decorative= 正文 /card /cards

Fields 字段 , native + shortcode

原生:表格 + {.fields [caption=] [id=] [meta="type required default -"]}——第一列是名称,最后一列是说明,中间列是元数据 chip。

Shortcode:fields label= id= class= field name= type= required= default= 正文 /field /fields——用于块级说明(本列表就是)。两种形态渲染同样的 chip;每个条目有 #field-<name> 锚点。

FileTree 文件树 , native

```filetree {title=} 围栏,每个条目一行 - name[/] # comment {icon= tone= open= type=};2/4 空格、tab 或 tree 缩进。CSS + 原生 <details>;注释列在构建期对齐。没有 shortcode。

Image 图片 , native

![alt](src "title") 加属性行 {#id num= caption= width= height= link= command= options=},承担图注、编号、链接与 Hugo 图片处理。imgproc 退役;没有图片 shortcode。

表格族 , native

{.full-width} {.fields} {.matrix} {caption=} {#id} {#id num= caption=} {tab= group= value=};站点 class 透传。互斥:fields ⟂ matrix / full-width / num;num ⟂ tab。

Fig / Tbl / Eq / Eg , native + shortcode

原生:图片 / 表格 / $$ 块 / 围栏 + {#id num= caption=}(默认 id fig-tbl-eq-eg-<num>)。

Shortcode:fig tbl eq egeg 必须有图注)。

Xref 交叉引用 , native + shortcode

原生:普通 Markdown 链接(不带 kind)。

Shortcode:xref fig|tbl|eq|eg="…" [page=] [anchor=]

Book 索引 , shortcode

book-toc book-figures book-tables book-equations book-examples——没有 kind= 参数。

代码围栏 , native

围栏属性 {title copy wrap collapse label id tab group value num caption lineNos hl_lines lineNoStart anchorLineNos tabWidth};只有 Chroma。

数据围栏 , native

mermaid plantuml markmap math chem echarts infographic checksums filetree galleryecharts 只做声明式配置,$fn:<name> 回调来自 window.OinkEchartsFunctions

叶子组件 , shortcode

kbd badge param include comment contributors asciinema(原生 <kbd> 同样可用);badge 没有 outlineparam 只接受标量。

Release / OpenAPI , shortcode

release-card release-assets download / swagger redocchecksums 围栏是发布信息的原生形态。

29 个 shortcode:核心 14(tabs tab steps cards card fields field include kbd badge param comment contributors asciinema)、Book 10(fig tbl eq eg xref book-toc book-figures book-tables book-equations book-examples)、Release 3、 OpenAPI 2。嵌套名(tabcardfield)只在父级里合法;每个 shortcode 都校验 参数,未知参数导致构建失败(0.4 里 asciinemaredocswaggerparamcommentsteps 会静默接受任何参数)。

删除的 shortcode 与替代

每个条目上的 chip 是迁移工具键(scripts/migrations/oink06.py migrate --only <key>); manual 表示报告会列出、需要人工修改。

删除的 shortcode 与替代

alert · details · td-page-notice , callout

0.4:alert color=… title=…detailstd-page-notice(都是 % shortcode)、原生 <details><summary>

0.5.0:> [!TYPE] title 提示块,折叠块用 > [!DETAILS]-

tabpane · tab · code-group · code-tab , tabs

0.4:tabpanetab header=…(都是 % shortcode)、code-groupcode-tab

0.5.0:相邻围栏加 {tab= group= value=}(纯代码面板),或 tabstab(混合内容)。

filetree · filetree/folder · filetree/file , filetree

0.4:filetreefiletree/folderfiletree/file;过渡期的 {.filetree} 列表标记。

0.5.0:```filetree 围栏——label 改为 titleopeniconcolorcommentlink 保留。

echarts · infographic , datafence

0.4:echartsinfographic shortcode。

0.5.0:同名数据围栏;$fn: 回调不变,js 子围栏改到 window.OinkEchartsFunctions

imgproc , image

0.4:imgproc …(以及发布前短暂存在的 image …)。

0.5.0:![alt](src) + 属性行 {command= options= caption=}

readfile , include

0.4:readfile file=…

0.5.0:include file=… [code=true lang=…]——依次查页面资源、assets、content 相对路径。

围栏 filename= , fencetitle

0.4:围栏上的 {filename="x"}

0.5.0:{title="x"}

badge outline= , badge

0.4:badge … outline=…

0.5.0:去掉 outline——只有一种徽章外观。

example · book-figures kind= , eg

0.4:自闭合的 example … + 围栏;book-figures kind="tbl"

0.5.0:eg/egbook-tablesbook-equationsbook-examples

fields · field(百分号形态) , fieldsdelim

0.4:用 % 分隔符书写的 fields / field(从未发布)。

0.5.0:fields / field

_param · iframe · conditional-text · netlify · 不带 kind 的 xref , reportonly

file:line 报告,人工处理;_param 占位符由 param_placeholders 变换处理。

swaggerui , manual

改名为 swagger;改调用名即可。

pageinfo , manual

改写为 > [!NOTE] 提示块。

td/site-build-info/netlify.md , manual

删除,无替代。

相对 0.4.2 新增:tabscardsincludeegbook-tablesbook-equationsbook-examples,以及改名而来的 swaggercardtab 名字未变,但现在是 cards / tabs 的子元素,契约不同。

没有图片 shortcode:渲染钩子统一为 Markdown 图片、fig 与配置里的图片来源解析页面 资源、栏目资源、全局 assets 以及 static / 远程路径,并把图注、编号、链接与 Hugo 图片处理(commandoptions)都放在属性行上——imgproc 能做的它都能做。

块属性策略

所有渲染钩子(表格、图片、代码块、passthrough、引用块、标题)共用一套策略: 白名单键由钩子消费,class 经 token 校验后透传,data-*aria-* 透传, styleon* 与任何未知键让构建失败。内容上的站点 CSS class 仍然合法; 内联样式和事件处理器永远到不了输出。

代码围栏

  • {filename="x"} 改为 {title="x"};同一围栏上 titlefilename 互斥。
  • Prism 路径删除。params.prism_syntax_highlightingstatic/js/prism.jsstatic/css/prism.css 不复存在;Chroma 加 params.highlight_classes(默认 true)是唯一的高亮器。Prism 无法与 tabgroupvaluenumcaption 共存,任何用了标签页或编号示例的 0.4 站点一开启它就已经构建失败。
  • 复制控件依次遵循围栏上的 copy=all|command|true|false、会话类 lexer 默认值 (consoleshell-sessioncommand)、再是 allparams.ui.code_copy: false 只改站点默认值;显式写了 copy 的围栏仍按自己的写法。旧键 disable_click2copy_chroma 会静默压过作者的显式值。
  • Docsy 的 click-to-copy.js(0.3 起从未加载)及其 .td-click-to-copy 样式删除。

配置

三条规则

  1. 布尔开关就是裸的特性名:ui.annotation: true,不是 ui.annotation.enable, 也不是 ui.annotation_enabled。仅存的 _enabled 后缀是 ui.navbar_enabledui.sidebar_enabledui.sidebar_root_enabled——它们的裸名会与同族兄弟键冲突。
  2. 单键 map 压平成标量。只有拥有多个子设置的特性才保留 map——commentsui.feedbackui.page_context_menuui.dark_modeui.command_paletteui.alt_sitetaxonomyprintsearchplantumldrawiomermaidcopyrightui.taxonomy_icons——其中开关型的同时接受裸布尔 (comments: falseplantuml: falsedark_mode: truefeedback: truepage_context_menu: false)。
  3. front matter 键 = 站点键去掉 ui. 前缀,没有例外(见 Front matter)。

键名一律 snake_case、正向、按用途命名。camelCase 只在原样透传给外部运行时的地方 保留(comments.giscus.* 是 giscus 自己的属性名,mermaid.* 交给 mermaid.initialize())。

任何旧键或旧形态都会让构建失败并指名替代——站点配置由 layouts/_partials/config-legacy.html 负责,页面由 layouts/_partials/front-matter-legacy.html 负责——升级就是按报错逐条替换。 没有任何东西被静默忽略。

改名与改形的站点键

0.4 0.5.0 说明
offlineSearchofflineSearchIndexofflineSearchMaxResultsofflineSearchOnServeofflineSearchSummaryLength offline_searchoffline_search_indexoffline_search_max_resultsoffline_search_on_serveoffline_search_summary_length 环境变量覆盖写 HUGOxPARAMSxOFFLINE_SEARCH_ON_SERVE=true(Hugo 的备用分隔符 x_ 无法定位含下划线的键)
ui.showLightDarkModeMenutrue / false / "enable-only (experimental)" ui.dark_mode——true,或 { enable, show_menu } show_menu: true 隐含 enable
ui.scrollSpy.disable ui.scroll_spy 取反;默认 false
ui.no_left_sidebar ui.sidebar_enabled 取反
ui.breadcrumb_disable ui.breadcrumb 取反;默认 true
print.disable_toc print.toc 取反;默认 true
disable_click2copy_chroma ui.code_copy 取反;只设默认值
ui.readingtime.enable ui.reading_time 裸布尔
ui.ul_show ui.sidebar_expand_levels 默认 2
Taxonomy.taxonomyCloud.taxonomyCloudTitle.taxonomyPageHeader taxonomy.cloud.cloud_title.page_header 一个小写 map
ui.annotation.enableui.image_zoom.enableui.keyboard_nav.enable ui.annotationui.image_zoomui.keyboard_nav 裸布尔
ui.typography.preset ui.typography technical | system;环境变量覆盖 HUGO_PARAMS_UI_TYPOGRAPHY=system
ui.pager.types ui.pager_types [docs, book, blog]
markmap.enable markmap 裸布尔
content_widthslim | norm | wide reading_widthslim | normal | wide Book 正文测量;body class td-book-content--normal,令牌 --td-book-content-normal
ui.docs_root ui.docs_sidebar_root section | home
github_url github_repo 编辑、历史、Issue 链接由仓库推导
algolia_docsearch search.algoliaappIdapiKeyindexName 构建失败
rss_sections 删除 从未被读取
params.links.user[] / .developer[] 删除 Docsy community 页面已删
plantuml.enabledrawio.enable 不变,且 map 接受 plantuml: false / drawio: false
comments.enable 不变,且接受 comments: false
comments.giscus.lightTheme / darkTheme 默认不设 默认使用主题自带调色板(见样式与资源

主题的全部默认值现在都在主题 hugo.yaml 里声明并附取值域注释。以前只是模板回退、 现在正式声明的有:offline_search: falseoffline_search_summary_length: 70ui.breadcrumb: trueui.reading_time: falseui.dark_mode: falseui.docs_sidebar_root: sectionui.sidebar_icon_policy: allui.section_index_columns: 2ui.code_copy: trueprint.toc: trueprint.section_break_wordcount: 50markmap: falseplantuml.enable: falsedrawio.enable: falsegithub_branch: main。两个默认值保持派生并如此记录: ui.quick_links(来自 docs_sectionblog_section)和 ui.taxonomy_icons (内置 categories/tags 图标)。ui.sidebar_expand_levels(2)与 ui.sidebar_menu_truncate(2000)的模板回退与声明值一致。

保持不变、继续可用的 Docsy 键:github_repogithub_project_repogithub_branchgithub_subdirpath_base_for_github_subdirtime_format_blogtime_format_defaultversionversionsversion_menuversion_menu_pagelinksarchived_versionurl_latest_versioncopyrightdescriptionauthorgcs_engine_idsearch.algolia.*mermaidplantuml.*drawio.*ui.sidebar_menu_compactui.sidebar_menu_foldableui.sidebar_menu_truncateui.sidebar_cache_limitui.sidebar_root_enabledui.feedback.{enable,reasons}

大声失败,而非静默

同时配置多个搜索后端(offline_searchgcs_engine_idsearch.algolia)现在会让 构建失败(以前只警告)。PlantUML 不设 plantuml.svg_image_url、Diagrams.net 不设 drawio.drawio_server、Algolia 缺任一凭据,与 0.4 一样构建失败。构建错误遵循同一 形状——<component>: <subject> <expectation>; got <value> at <position>——全小写、 位置只用一个介词、配置错误给出完整的 params. 路径;不再指向文档 URL。

Front matter

页面键 = 站点键去掉 ui. 前缀,front matter 里不再有 ui: 块。栏目 cascade 同理 (cascade: { params: { section_index: cards } } 或直接裸键)。一个解析器 (ui-param.html)为每个可按页覆盖的 params.ui.* 设置先读页面值、再读站点值: sidebar_menu_compactsidebar_menu_foldablesidebar_expand_levelssidebar_width_minsidebar_width_maxsidebar_item_overflowsidebar_headingssidebar_enabledsection_indexsection_index_columnslastmod_commitbreadcrumbscroll_spycode_copykeyboard_navbook_draft_banner;再加上显式页面键 navbar_enablednavbar_autohidefooter_styleannotationfeedbackimage_zoomreading_timepage_context_menucommentspage_widthreading_width

0.4 front matter 0.5.0
params: { ui: { <key>: … } }(任何键) 顶层(或 params: 下)的 <key>: …
params.ui.image_zoom.enable image_zoom: true | false
params.ui.keyboard_nav.enableparams.ui.annotation.enable keyboard_navannotation(裸布尔)
annotation: { enable: … } annotation: true | false
context_menu page_context_menutrue | false,或 { enable, assistant_links }
assistant_links(顶层) page_context_menu: { assistant_links: false }——页面只能收窄站点策略
hide_readingtime: true reading_time: false
hide_feedback: true feedback: false
exclude_searchexcludeSearch search_exclude
content_width: norm reading_width: normal
manualLinkmanualLinkTitlemanualLinkTargetmanualLinkRelref manual_linkmanual_link_titlemanual_link_targetmanual_link_relref
body_class: td-no-left-sidebar sidebar_enabled: false
contributingUrl 随 community 页面删除
Icon icon(Hugo 不区分大小写;主题按小写读取)

未变的页面键:toc_hidetoc_rootnotocno_printno_listsimple_listhide_summarysidebar_root_forsidebar_dividersidebar_expandedsidebar_root_menusidebar_root_link_selfsearch_keywordssearch_boostpagerlandingsectionsbook_numberbook_statusreleaserelease_productsrelease_group_by_productupstream_attributiondownstream_modifiedbylineauthorbody_class

scripts/migrations/oink06.py migrate --only frontmatter 会改写以上全部页面键, 包括 cascade: map 与列表里的。

模板、partial 与布局

删除项,以及复制或调用过它们的站点应改用什么:

0.4 0.5.0
_partials/home/**(18 个适配器)、_partials/home-data.html _partials/landing/**landing/home-data.html
_partials/outputformat.html .Store.Get "tdOutputFormat"html | print | markdown | rss,每个 base 模板都会设置)
_partials/td/render-heading.html 以及调用它的站点侧 _markup/render-heading.html 主题自己的 _markup/render-heading.html——删掉站点覆盖
layouts/community/list.htmllayouts/docs/community.html_partials/community_links.html 无——Docsy community 页面已删
_partials/taxonomy_terms_article.htmltaxonomy_terms_article_wrapper.htmltaxonomy_terms_cloud.html taxonomy-terms-article.htmltaxonomy-terms-article-wrapper.htmltaxonomy-terms-cloud.html
_partials/taxonomy_terms_clouds.htmlcode/markdown-escape.html 0.4 里就已是死文件;活的是 shell/taxonomy-terms-clouds.htmlcontent/markdown-escape.html
_shortcodes/swaggerui.html _shortcodes/swagger.html
从 0.4 复制的 layouts/_default/_markup/render-* 保留任何覆盖前先与 0.5.0 对比——每个钩子都变了

有覆盖的站点还应知道的模板层变化:

  • 侧栏两个来源——内容树与显式的 data/docs_nav.json——每一行都经 shell/sidebar-node.html 渲染。shell/config.html 仍是品牌、logo、栏目配置的 唯一解析器。
  • 每个渲染内容的布局都调用 content/render.html 而不是 .Content (图片缩放候选扫描在那里进行)。
  • Print:print/page-content.html 通过 partialCached 让每页的 print 内容在一次 构建里只渲染一次;print/render.htmlprint/content.htmlbook/print.html 与各 single.print.html 布局都读它。复制过 0.4 print 模板的站点应删掉副本—— 0.4 的流水线在"本身是 section 的章节被父级再次聚合"时会在页面 store 上竞态。
  • 标题渲染钩子归主题所有。每个标题带 id 与悬停显示的自链接 (.td-heading-self-link,文案 ui_heading_self_link);print 与 RSS 会剥掉链接。
  • DocSearch 容器只有一个 #td-docsearch;写死的 #docsearch-0/1 两个 id 没有了。

样式与资源

一个命名空间

主题产出的一切都有前缀,scripts/check-namespace.py 守着这条线。站点里挂在旧名字 上的 CSS 或 JS 必须迁移:

类别 0.4 0.5.0
class oink-*(landing 子系统)、leafhas-childactive-pathis-openis-activeis-hiddenis-disabledlanding-headerlanding-navlanding-containerarticle-metapageinfonav-*taxonomy-*ul-N 全部 td-*;站点页头与导航是 td-site-headertd-site-navtd-site-container
data 属性 data-oink-* data-td-*
自定义属性 --oink-*--term-* --td-*
JS 全局 oink* / echartsFunctions window.OinkActionsOinkEchartsFunctionsOinkLandingOinkSearchEngineOinkSurfaceCoordinator
作者标记(无前缀,不变) {.steps} {.cards} {.fields} {.matrix} {.full-width}

Sass 与令牌

删除的 Sass 文件(站点 _styles_project.scss 若仍 import 会编译失败): td/code-darktd/color-adjustments-darktd/gcs-search-darktd/extratd/extra/bs-defaultstd/extra/buttonstd/extra/main-containertd/extra/navbartd/boxes.td-box.td-box--<color>.td-box--height-*)、 td/colors.-bg-<name>.-text-<name>)。删除的变量:$td-box-colors$td-print-font-name$td-enable-webfonts

改名或新增的令牌:--td-book-content-norm--td-book-content-normal.td-book-content--norm--normal);--td-print-font-family 角色保留但在 两种预设下都跟随 --td-body-font-family;新增 --td-motion-duration-fast (100 ms)、--td-motion-duration(150 ms)、--td-motion-duration-slow(250 ms), shell 的每个过渡都引用它们,prefers-reduced-motion: reduce 把它们置零。

排版:UI 与正文使用 Inter(可变字重,Latin/Latin-ext/西里尔/希腊/越南语子集按 unicode-range 提供;CJK 与 emoji 回落到平台字体栈)、无边框行内代码、安静的代码 卡片加悬停显示的复制控件、Mintlify 风格字段行、页末两个文本链接的翻页器、卡片式 栏目索引上方的分隔线。Open Sans(18 个 woff2 子集、652 KB,为一个仅打印用的字体 发布到每个站点)已删除;想在纸面上换字体的站点自己在样式表里设 --td-print-font-familysystem 预设依旧不请求任何品牌字体。

shell 图标改为由 shell/icon.html 分发的 Font Awesome class 对 (<i class="td-shell-icon td-shell-icon--<name> fa-solid fa-…">)而不是内联 SVG;--td-shell-icon-size 设置尺寸盒。

发布的资源

  • 三个 JavaScript bundle 取代按特性组合生成的单个 bundle:js/actions.jsjs/core.js 在每一页字节相同、可以缓存;只有一个小的 js/page-<hash>.js 随页面变化。ECharts 单独一个 <script>。print 输出加载 7.9 KB 而不是 100 KB。
  • static/css/giscus-oink-{light,dark}.css 没有了。调色板以 assets/css/giscus-{light,dark}.css 随主题提供,只在渲染评论的页面发布, 并且是 comments.giscus.lightTheme / darkTheme 的默认值;指向旧路径的站点 删掉那两行即可(或写 giscus 内置主题名 / 自己的样式表 URL)。
  • 删除:static/js/prism.jsstatic/css/prism.cssstatic/webfonts/open-sans/assets/js/click-to-copy.jsVENDOR.json 与 vendor 目录哈希已重新生成。

i18n

  • 提示块文案改为带命名空间的键:callout_notecallout_tipcallout_importantcallout_warningcallout_cautioncallout_successcallout_dangercallout_questioncallout_examplecallout_quotecallout_details。 主题不再占用 noteexamplequote 这类裸顶层键;在自己 i18n/ 里覆盖过 这些键的站点需要改名。
  • 删除:community_joincommunity_introducecommunity_learncommunity_usingcommunity_developcommunity_contributecommunity_how_tocommunity_guideline
  • 新增:ui_heading_self_linkui_field_self_link(各语言英文兜底;中文变体已审校)。
  • 32 个语言文件保持键完全一致(174 个键)。

数据文件

  • data/home/<lang>.yaml(或 data/home.yaml)必须列出 sections;隐式的 hero → metrics → capabilities → principles → cta 顺序没有了,缺失会构建失败。
  • 胖页脚只读 data/footer/<lang>.yaml(或 data/footer.yaml)。data/home 里的 footer 键会构建失败并指出新位置。
  • data/landing/<key>/<lang>.yamldata/docs_nav.jsondata/download/<key>.yamldata/brand.yaml 不变。

行为与输出变化

  • 标题带悬停显示的自链接;print 与 RSS 输出剥掉锚点,Markdown 输出 (RenderShortcodes)不受影响。
  • print 聚合每次构建对每页内容只渲染一次。0.4 里"本身是 section 的章节"会被自己的 print 输出和父级的 print 输出并发渲染两次,两次渲染在页面 store 上竞态——可见 症状是 _print/ 里偶发重复的 td-code-… id。
  • <main> 不再带 role="main";侧栏 <aside> 不再重复内层 <nav> 的 “Section navigation” 标签。
  • ui.dark_mode: true 同时开启暗色调色板与 System / Light / Dark 菜单; 单独的 show_menu: true 隐含 enable
  • ui.code_copy: false 只设默认值(见代码围栏)。
  • 首页渲染导航栏;提示块标题满足对比度;Gallery 条目与其它图片同等享有缩放; 标签页运行时保住运行边界、唯一同伴 id 与 print 标题;FileTree 与整个 shell 遵守 prefers-reduced-motion
  • 表格渲染钩子也在 print 与 RSS 输出里运行,表格在交互式 HTML 之外也保留图注、 编号与滚动容器;两种形态的 fields 产出同一渲染,每个条目都有 #field-<name> 锚点。
  • llms.txt 读取 params.ui.docs_section,并带描述列出文档页面。
  • 图片解析器的错误按调用方标注(Markdown 图片是 image:fig 是 shortcode 名), 配置里的图片来源与内容遵循同一 URL 策略。

发布候选加固

最终评审发现了一个系统性迁移缺口:模板已经输出新的 data-td-* 契约,若干运行时与 测试 mock 却仍读取旧 dataset 名称;动作清单还位于同步动作注册 bundle 之后,注册表 可能以空状态初始化。这两项现已修复,并新增结构检查阻止回归。页面动作、命令面板搜索、 代码复制与折叠、反馈页面标识、折叠控件文案、Giscus 主题、图片缩放标签与 Asciinema 计时标签,现在会在测试与真实渲染 DOM 中使用同一组属性。

同一轮加固还完成了以下修正:

  • reportmigratecheck 遇到不存在、空、不可读或非 UTF-8 的目标时直接失败, 不再给出误导性的“无残留”结果;JSON front matter 改用 JSON 解码器解析;
  • Markdown、RSS 与聚合打印输出都会执行旧 front matter 检查,页面评论等覆盖项严格 校验布尔值与 map 形态;
  • 数据围栏与提示块会保留允许的 data-* / aria-* 属性,同时图表布尔参数保持严格;
  • 每个 Swagger 与 ReDoc 嵌入都有唯一实例,不再覆盖 window.onload 或发布 window.ui
  • shell Logo、Wordmark 与配置型 Featured Image 统一使用共享 URL 策略;
  • 新增 scripts/check-site-markup.py,从消费站解析后的配置中检查原生形态必需的三项 Goldmark 设置。

迁移指南

顺序很重要:先内容(工具默认 dry-run 且幂等),再让构建错误驱动配置与布局的修改。

改写内容前,先确认消费站能够渲染原生形态:

python3 path/to/oink/scripts/check-site-markup.py --site ~/pgsty/example.com

1. 盘点

python3 scripts/migrations/oink06.py report --sites ~/pgsty/example.com --md report.md --json report.json

报告逐站列出工具会改写的每一个 0.4 结构、不会碰的(带 file:line 与原因), 以及改写之后仍会被标记的残留。

2. 内容与 front matter

python3 scripts/migrations/oink06.py migrate --site ~/pgsty/example.com          # dry run:diff + 计数
python3 scripts/migrations/oink06.py migrate --site ~/pgsty/example.com --write  # 原子改写
python3 scripts/migrations/oink06.py migrate --site ~/pgsty/example.com --write  # 第二次:changed 0
python3 scripts/migrations/oink06.py check   --site ~/pgsty/example.com          # 残留旧语法 → exit 1

变换按应用顺序:frontmatter(页面键,含 cascade:)、calloutparam_placeholderstabsfiletreegallerydatafencecardsfieldsdelimimageincludefencetitlebadgeegreportonly--only <key> 选子集。围栏内的文本永远不改写;TOML/JSON front matter 只报告不改写。 在 11 个自有站点上,front matter 变换触及 628 个文件、零 finding。

报告会列出需要人工处理的项:swaggeruiswaggerpageinfo → 提示块、 _param 占位符、iframe/conditional-text/blocks/*、不带 kind 的 xref, 以及必须改成 window.OinkEchartsFunctions 条目的 echarts js 子围栏。

3. 配置

构建站点。每个旧键都会带着替代写法失败:

ERROR params.offlineSearch was renamed: use params.offline_search
ERROR params.ui.typography.preset was flattened: use params.ui.typography: technical | system
ERROR params.ui.showLightDarkModeMenu was renamed: use params.ui.dark_mode.show_menu
ERROR params.print.disable_toc was renamed: use params.print.toc (inverted)
ERROR params.rss_sections was removed: the key was never read; delete it

一份典型的 0.4 hugo.yaml 变成:

params:
  offline_search: true
  offline_search_on_serve: true
  offline_search_index: summary
  offline_search_summary_length: 70
  offline_search_max_results: 10
  reading_width: normal            # 原 content_width: norm
  markmap: true                    # 原 markmap: { enable: true }
  print:
    toc: true                      # 原 disable_toc: false
  comments:
    enable: true
    type: giscus
    giscus:
      repo:  # lightTheme / darkTheme 两行删除
  ui:
    typography: technical          # 原 typography: { preset: technical }
    dark_mode: true                # 原 showLightDarkModeMenu: true
    sidebar_expand_levels: 2       # 原 ul_show: 2
    scroll_spy: false              # 原 scrollSpy: { disable: true }
    reading_time: false            # 原 readingtime: { enable: false }
    image_zoom: true               # 原 image_zoom: { enable: true }
    keyboard_nav: true             # 原 keyboard_nav: { enable: true }
    annotation: true               # 原 annotation: { enable: true }
    pager_types: [docs, book, blog] # 原 pager: { types: [...] }
    docs_sidebar_root: section     # 原 docs_root
    breadcrumb: true               # 原 breadcrumb_disable: false
    sidebar_enabled: true          # 原 no_left_sidebar: false
    code_copy: true                # 原 disable_click2copy_chroma: false(顶层)

删除 params.linksprism_syntax_highlightingrss_sectionsgithub_url (改用 github_repo)、algolia_docsearch,以及 giscus 的 lightTheme / darkTheme URL。

4. cascade 与栏目索引

设置过 params.ui.*cascade 改为裸键——_index.md 里的由变换处理, hugo.yaml 里手写的 cascade 要自己检查:

cascade:
  type: blog
  params:
    sidebar_menu_compact: false    # 原 params.ui.sidebar_menu_compact
    sidebar_expand_levels: 3       # 原 params.ui.ul_show

5. Sass、布局与站点脚本

  • assets/scss/_styles_project.scss:删掉 @import 'td/color-adjustments-dark''td/code-dark''td/extra''td/extra/bs-defaults''td/gcs-search-dark'; 去掉针对 .td-navbar-cover.td-navbar-transparent.td-box*-bg-*oink-*--oink-* 的规则。
  • assets/scss/_variables_project.scss:去掉 $td-print-font-name$td-enable-webfonts$td-box-colors
  • layouts/partial "home-data.html" / "home/section.html" 换成 landing/…partial "outputformat.html" 换成 .Store.Get "tdOutputFormat";删掉调用 td/render-heading.html_markup/render-heading.htmltaxonomy_terms_* 调用改名;其它复制过的 partial 或钩子在保留前先与 0.5.0 对比。
  • 站点 JS 与测试:oink-* id 与 data-oink-* 属性改为 td-* / data-td-*; 动作清单是 #td-action-manifest;每页 bundle 是 js/page-<hash>.js,旁边是 js/actions.jsjs/core.js
  • 站点 i18n/ 覆盖:notetip… 改名为 callout_notecallout_tip…。

6. 数据

footer: map 从 data/home/<lang>.yaml 移到 data/footer/<lang>.yaml; 确认 data/home/<lang>.yaml 列出了 sections

7. 校验

hugo --printPathWarnings --panicOnWarning
python3 scripts/check-output-security.py --public public --base-url https://example.com/

然后检查变化最大的几个面:一个有代码标签页与提示块的文档页、一个有图片的页面 (缩放开与关)、一个 Book 章节及其 _print/ 聚合、index.md Markdown 输出、 一个 RSS feed、首页 landing、暗色调色板。v0.5.0 标签推送后再固定它:

hugo mod get github.com/pgsty/[email protected]
hugo mod tidy

兼容性

  • Hugo Extended 0.160.1 仍是最低版本;CI 跑 0.160.1 与 0.164.0,并新增以 Hugo Module 模式构建消费站点。
  • 模块路径仍是 github.com/pgsty/oink;消费站点仍不需要 Node.js、CDN 或构建期下载。
  • 对 0.4 没有兼容层:改名的键、形态、shortcode、partial、class 要么构建失败要么 直接消失,这是有意的。旧键报错就是迁移指南;其中源自 Docsy 的条目同样服务 从 Docsy 迁来的站点。
  • 合理的 Docsy 键保持不变(见配置下的清单);sidebar_* 一族名字未动。
  • 交互特性仍然默认关闭:offline_searchui.image_zoomcommentsui.feedbackui.dark_modepage_context_menu.assistant_links 需要站点主动开启。

验证

主题 CI:34 个检查脚本(i18n 键一致、分类法、字体令牌、导航 / 组件 / 内容原语 / Book 契约、运行时隔离、侧栏图标、搜索、动作、命令面板、阅读、发布资产、下载、 landing、Book 迁移、共享场景、键盘、shell、命名空间、参数、vendor 清单、输出结构 与安全、30 个面的四态 goldens、代码块、内容与媒体原语、图片缩放、Gallery、组件)、 浏览器运行时单测、迁移工具测试(85)、在 Hugo 0.160.1 与 0.164.0 上无警告构建的 fixture 站点、system 排版预设、遗留 Sass 覆盖、非法预设构建失败,以及新增的 Module 模式消费站点构建。scripts/check-params.py 为每个退役键各构建一个站点 (32 个站点键、14 个页面键),断言每个都失败并指名替代。

本站按上述迁移后在 0.5.0 上无警告构建。最终门禁在 Hugo 0.160.1 与 0.164.0 上各跑 一遍完整矩阵;媒体断言允许各支持版本使用不同的不透明派生缓存哈希,同时仍严格检查 渲染 URL 结构、尺寸、alt 语义与 Zoom 排除。源码校验、本地附注标签、远端标签发布、 消费站固定版本与部署仍是可独立审计的门禁。

完整变更集

完整源码差异见 v0.4.2 到 v0.5.0 与主题的 CHANGELOG.md