Skip to content

管线阶段

tbdocs构建管线中每个阶段的完整接口参考。每节覆盖一个模块:其入口点签名、从前置阶段读取的数据、为后续阶段写入的数据,以及每个导出符号。

设计理念和叙述性描述见tbdocs构建器。要添加新阶段或markdown-it插件,请参阅扩展构建器

数据模型

管线通过每个阶段传递两个可变数据结构。

页面对象(pages[]

discover为每个具有可解析YAML frontmatter的.md.html源文件创建一个页面对象。后续阶段添加新字段;没有阶段会删除或重命名早期阶段设置的字段。后续阶段可以安全地假设早期阶段的所有字段都已存在。

字段添加者类型描述
srcPath阶段1string源文件的绝对文件系统路径。
srcRel阶段1string相对于srcRoot的POSIX风格路径,例如Reference/Core/Dim.md
ext阶段1string小写文件扩展名:.md.html
frontmatter阶段1object已解析的YAML frontmatter。所有frontmatter键可在此访问(例如frontmatter.titlefrontmatter.parentfrontmatter.nav_order)。
rawContent阶段1stringfrontmatter块之后的正文文本。
permalink阶段1stringURL路径,取自frontmatter.permalink或从srcRel派生。
destPath阶段1string输出根目录中的文件系统路径,例如Reference/Core/Dim.html
layoutDefault阶段1boolean当frontmatter没有显式layout:键时为true
imageScope阶段1booleansrcRel包含Images/段时为true。阶段3使用此字段验证图片路径。
navPath阶段2(nav)string斜杠连接的导航链:grand_parent / parent / title。仅在有非空title的页面上设置。
navLevels阶段2(nav)object侧边栏树中的位置索引。阶段4使用此字段生成每页激活CSS。
breadcrumbs阶段2(nav)Page[]从根到当前页面的祖先链,最近者优先。
children阶段2(nav)Page[]导航顺序中的直接子页面。
seoTitle阶段2(seo)stringHTML剥离、空白折叠的页面标题,用于<title>og:title
seoFullTitle阶段2(seo)string非首页为"<seoTitle> -- <siteTitle>";首页等于seoTitle
seoCanonical阶段2(seo)string绝对规范URL(scheme + host + baseurl + permalink)。
seoIsHome阶段2(seo)boolean当页面的permalink是已知主页URL时为true(例如/)。
renderedContent阶段3stringmarkdown-it生成的HTML正文。尚未包裹站点布局。
html阶段4string完整的HTML文档,可直接写入磁盘。layout: book-combined页面无此字段,由阶段8管理。

站点对象(site

在阶段2末尾构建并原样传递给每个后续阶段。

字段类型描述
configobject已解析的_config.yml,已应用CLI覆盖(--baseurl--url)。
navTreeobjectnav.mjs生成的顶级导航层次结构。
seoSiteTitlestringconfig.title渲染的站点标题。
seoLogoUrlstring站点logo的绝对URL。
buildInfoobject来自git的{ commit: string, commitDate: string }。两者在git仓库之外均回退到"unknown"
bookDataobject|null已解析的_book.yml,章节选择器已解析为Page引用。文件缺失时为null。参见Book配置
dataobject_book.yml加载为{ book: … },缺失时为{}
markdownMarkdownIt共享markdown-it实例,在阶段2设置期间构建一次,由阶段2的SEO处理和阶段3的渲染处理复用。

静态文件(staticFiles[]

同样由阶段1生成。每个不是页面的文件——图片、字体、预构建的CSS/JS,以及任何没有frontmatter的.md/.html文件——都成为静态文件对象。此数组在阶段1之后不再增长。

字段类型描述
srcPathstring绝对源路径。
srcRelstring相对于srcRoot的POSIX路径。
destRelstring输出根目录内的相对路径(当前与srcRel相同)。
sizenumber发现时的文件大小(字节)。

预阶段:mermaid.mjs

在阶段1之前运行,以便任何新生成的.svg文件出现在阶段1的静态文件清单中。

入口点

js
regenerateMermaid(srcRoot: string): Promise<{
  processed: number,
  regenerated: number,
  failed: number,
  setupSkipped?: true,
}>

枚举<srcRoot>/assets/images/mmd/*.mmd,比较修改时间与同路径下的.svg兄弟文件,并直接驱动puppeteer + mermaid包将每个过期的.mmd渲染为.svg。一次浏览器启动覆盖整个批次。当没有.mmd文件过期时,调用为空操作。

渲染在页面内page.evaluate中运行,通过请求拦截源(https://tbdocs-mermaid.invalid)动态导入mermaid.esm.mjs。拦截将请求映射回node_modules/mermaid/dist/;需要源技巧是因为Chromium在file://上加载时阻止了mermaid.esm.mjs触发的import()链。IIFE包(mermaid.min.js)可以避开该约束,但会内联+压缩经过补丁的dagre块(参见Mermaid Dagre补丁),因此带拦截的ESM路径是保持补丁生效的唯一方式。

两种失败模式区分:

  • 设置失败puppeteer / mermaid未安装,Chrome运行时缺失)返回{ ..., setupSkipped: true },警告一次,并保留磁盘上的SVG。编排器不会翻转退出码。
  • 每图渲染失败(损坏的.mmd,mermaid渲染抛出异常)不会中止批次——循环继续以便每个损坏的图在单次运行中暴露,每个失败图保留先前的SVG,编排器根据failed计数翻转process.exitCode = 1

读取: <srcRoot>/assets/images/mmd/*.mmd及其.svg兄弟文件;node_modules/mermaid/dist/**(通过import.meta.url根的createRequire解析)。 写入: 过期.mmd源旁边的.svg文件。

所有导出

符号签名描述
regenerateMermaid(srcRoot) → Promise<{ processed, regenerated, failed, setupSkipped? }>主入口点。

阶段1:discover.mjs

遍历源树并生成后续每个阶段消费的pagesstaticFiles数组。

入口点

js
discover(srcRoot: string, ignore: string[]): Promise<{ pages: Page[], staticFiles: StaticFile[] }>

srcRoot运行单次fast-glob调用,使用从_config.yml读取并由编排器传入的exclude:列表。对于每个.md.html文件,尝试解析YAML frontmatter。具有可解析frontmatter的文件成为页面对象;其他所有内容成为静态文件对象。页面按基本名排序(镜像Jekyll的读取器);静态文件按相对路径排序。

读取: srcRoot下的源文件。 写入(页面字段): srcPathsrcRelextfrontmatterrawContentpermalinkdestPathlayoutDefaultimageScope

所有导出

符号签名描述
discover(srcRoot, ignore) → Promise<{ pages, staticFiles }>主入口点。

阶段2:计算

阶段2按顺序运行多个模块(captureBuildInfo并行运行)。它们共同构建site对象并向每个页面添加导航、SEO和书籍章节数据。

从每个页面的titleparentgrand_parent frontmatter键计算导航树。阶段2中唯一可能中止构建的子步骤——它在孤立或模糊的parent:声明上抛出异常。

入口点

js
computeNav(pages: Page[], config: object): { navTree: object }

按顺序运行六个子步骤:导航路径、导航完整性检查、共享状态构建(byTitle / byParentTitle映射、topLevel列表、orderedChildren映射)、导航树、导航级别、面包屑、子页面。返回站点对象的导航树;直接在每个页面对象上写入导航相关字段。

读取: frontmatter.titlefrontmatter.parentfrontmatter.grand_parentfrontmatter.nav_orderfrontmatter.nav_excludepage.permalinkconfig.nav_sortconfig.case_insensitive写入(页面字段): navPathnavLevelsbreadcrumbschildren

所有导出

符号签名描述
computeNav(pages, config) → { navTree }主入口点。

seo.mjs

为每个页面和整个站点预计算SEO元数据。

入口点

js
precomputeSeo(pages: Page[], config: object, markdown: MarkdownIt): { seoSiteTitle: string, seoLogoUrl: string }

对于每个页面,将标题通过renderTitle(markdown-it渲染 → 剥离HTML → 折叠空白 → 转义HTML实体)并写入四个SEO字段到页面对象。返回seoSiteTitleseoLogoUrl给站点对象。要求共享的markdown-it实例已通过createMarkdownIt构建。

读取: frontmatter.titlefrontmatter.permalinkpage.permalinkconfig.titleconfig.urlconfig.baseurlconfig.logosite.markdown写入(页面字段): seoTitleseoFullTitleseoCanonicalseoIsHome

所有导出

符号签名描述
precomputeSeo(pages, config, markdown) → { seoSiteTitle, seoLogoUrl }主入口点。
renderTitle(text: string, markdown: MarkdownIt) → string将一个标题字符串通过完整的markdown-it + 剥离HTML管线。
stripHtml(s: string) → string从字符串中剥离所有HTML标签。为search.mjs重新导出。
absoluteUrl(input: string, config: object) → string使用config.urlconfig.baseurl将根相对路径解析为绝对URL。为sitemap.mjsredirects.mjs重新导出。
relativeUrl(input: string, config: object) → stringconfig.baseurl前缀添加到根相对路径。

book.mjs --- 阶段2部分

_book.yml章节选择器解析为具体的Page数组,使阶段8无需再进行页面查找。

阶段2入口点

js
resolveBookChapters(bookData: object | null, pages: Page[]): void

遍历bookData.front_matterbookData.parts(及其chapters子数组)中的每个条目,将每个选择器解析为Page[],并将结果存储为entry._chapters。预解析landing_pageforeword_page URL为其Page引用。就地操作;不返回任何值。选择器模式参见Book配置

读取: bookData(由data.mjs加载)、page.permalinkpage.navPath写入: 每个bookData条目上的entry._chapters(非页面字段)。在声明了landing_page: / foreword_page:的条目上设置_landing_foreword引用。

阶段8的assembleBook位于同一模块中;参见下面的阶段8

所有导出

符号签名描述
loadBookData(srcRoot: string) → Promise<object|null>向后兼容包装器,直接加载_book.yml。优先使用data.mjs
resolveBookChapters(bookData, pages) → void阶段2入口点。
sortByNavOrder(input: Page[]) → Page[]对页面数组排序:索引页(URL以/结尾)优先,然后按nav_order升序并以标题作为决胜,然后按标题字母顺序。
chapterAnchorFromUrl(url: string, fallbackTitle?: string) → string将页面URL转换为用于书内交叉引用的ch-…锚点slug。
bookChapterTransform(body: string, baseurl: string, headingShiftN: number, chapterAnchor: string) → string对渲染后的HTML字符串应用所有每章节正文转换:baseurl前缀剥离、<details> / <summary>解包、pagedjs分页的空白包裹、标题级别偏移和章节锚点前缀添加。
assembleBook(site: object, pages: Page[]) → string阶段8入口点。返回已组装的book.html字符串。
rewriteBookHrefs(html: string, site: object, pages: Page[]) → string将书内绝对href="/X"引用重写为页内href="#ch-X"片段锚点。

build-info.mjs

为PDF标题页捕获git提交哈希和日期。

入口点

js
captureBuildInfo(): Promise<{ commit: string, commitDate: string }>

发起两个并行的git shell调用(rev-parse --short HEADlog -1 --format=%cs)。在任何失败时回退到"unknown",使构建在git仓库之外永不中止。编排器在阶段1之后立即启动此promise,使shell调用与CPU密集的导航计算重叠。

读取: 本地git仓库状态。 写入: 不向页面写入(结果直接返回给编排器)。

所有导出

符号签名描述
captureBuildInfo() → Promise<{ commit, commitDate }>主入口点。

data.mjs

srcRoot加载_book.yml

入口点

js
loadData(srcRoot: string): Promise<object>

返回{ book: <parsed YAML> },文件不存在时返回{}。编排器将结果存储在site.data,并将site.data.book暴露为site.bookData

读取: <srcRoot>/_book.yml写入: 不向页面写入(结果直接返回)。

所有导出

符号签名描述
loadData(srcRoot) → Promise<object>主入口点。

阶段2设置 --- 共享markdown-it实例

在阶段2完成之前,编排器构建共享的markdown-it实例,阶段2的SEO处理和阶段3的渲染处理都复用此实例。按顺序调用render.mjs中的三个函数:

js
const highlighter = await initHighlighter();
const linkTables  = buildLinkTables(pages);
const markdown    = createMarkdownIt({ highlighter, linkTables, baseurl, staticFiles });

这些函数的文档在下面的阶段3中,因为它们定义在render.mjs中。这里在阶段2期间调用它们仅为了让SEO处理能共享相同配置的管线。


阶段3:render.mjs

通过markdown-it将每个页面的rawContent渲染为HTML。

入口点

js
renderPhase(pages: Page[], site: object, staticFiles?: StaticFile[]): Promise<void>

使用共享的site.markdown实例将每个页面的rawContent渲染为page.renderedContent。跳过layout: book-combined的页面(阶段8管理这些)。

读取: page.rawContentpage.frontmatterpage.imageScopesite.markdownsite.config.baseurlstaticFiles(用于图片路径验证)。 写入(页面字段): renderedContent

所有导出

符号签名描述
renderPhase(pages, site, staticFiles?) → Promise<void>主入口点。
createMarkdownIt({ highlighter, linkTables, baseurl, staticFiles }) → MarkdownIt配置并返回一个已应用所有插件和渲染规则覆盖的markdown-it实例。如何添加插件参见扩展构建器
initHighlighter() → Promise<{ render, themeCss }>使用捆绑的twinBASIC语法初始化Shiki(内部委托给highlight.mjs)。render(code, lang)返回高亮HTML;themeCss是生成的tb-highlight.css字符串,未加载主题时为null
buildLinkTables(pages: Page[]) → { byPath, byUrl, byRedirect }构建以srcRelpermalinkredirect_from条目为键的查找表。供相对链接插件在渲染时将源内[X](Y.md)链接解析为绝对URL使用。
kramdownSlug(text: string) → string将标题文本转换为kramdown兼容的锚点slug:小写、剥离非单词字符、用-1-2等去重。
rewriteAdmonitions(src: string) → string预渲染文本遍:将GFM > [!NOTE] / [!IMPORTANT] / [!WARNING] / [!TIP] / [!CAUTION]块转换为markdown-alert markdown-alert-<type>类结构。

阶段4:template.mjscompress.mjs

阶段4将每个页面的renderedContent包裹在完整站点布局中,然后压缩生成的HTML。

template.mjs

入口点

js
templatePhase(pages: Page[], site: object): Promise<void>

预计算每次构建的静态侧边栏HTML一次,然后通过直接JS模板字面量拼接(无模板引擎)将每个页面的renderedContent包裹在just-the-docs布局中。在存储结果之前对每个页面的输出调用compressHtml。跳过layout: book-combined页面。

读取: 阶段1--3设置的所有页面字段、所有site字段。 写入(页面字段): html

所有导出

符号签名描述
templatePhase(pages, site) -> Promise<void>主入口点。
navActivationCss(page: Page) → stringpage.navLevels生成每页的<style id="jtd-nav-activation">块。阶段12的开发服务器在修补SSE重载脚本时调用此函数。
injectAnchorHeadings(html: string) → string在每个有id属性的标题旁添加<a class="anchor-heading">

compress.mjs

templatePhase内部调用compressHtml。该函数也为独立使用而导出。

入口点

js
compressHtml(html: string): string

<pre>…</pre>块分割,在非<pre>段中折叠ASCII空白为单个空格并修剪。使用显式字符类[ \t\n\r\f\v]+而非\s以保留&nbsp;缩进中的不间断空格。

所有导出

符号签名描述
compressHtml(html) → string压缩<pre>块外的空白。

阶段5:write.mjs

将内存中的页面集和静态文件实体化到磁盘。

入口点

js
writePhase(
  pages: Page[],
  staticFiles: StaticFile[],
  {
    destRoot: string,
    dryRun?: boolean,
    generatedAssets?: { rel: string, content: string }[],
    baseurl?: string
  }
): Promise<{ pages: { written, skipped }, theme: { copied }, staticFiles: { copied } }>

清除然后重新创建destRoot,然后并行运行三个操作:将每个page.html写入其destPath;将vendor的just-the-docs JS从builder/vendor/just-the-docs/assets/复制到<destRoot>/assets/;复制每个staticFiles[]条目(包括现在位于docs/assets/下的项目自有主题文件)。CSS url() baseurl重写运行在两个复制路径和生成的CSS资产上,使根绝对url("/path")引用在非空baseurl下正确解析。并行批次之后,writeGeneratedAssets顺序写入generatedAssets[](SCSS编译的CSS和高亮主题CSS),使它们在相对路径冲突时获胜。跳过page.htmlundefined的页面。

读取: page.htmlpage.destPathstaticFile.srcPathstaticFile.destRel写入: <destRoot>/**(在线树)。

所有导出

符号签名描述
writePhase(pages, staticFiles, opts) → Promise<stats>主入口点。
WRITE_LIMIT64runLimited的并发上限。阶段6、7和8将此值传递给自己的runLimited调用以实现一致的I/O节流。
isUnderProject(destRoot: string) → boolean仅当destRoot是项目根目录的后代时返回true。阶段7和8用作防止破坏性--dest值的守卫。
mkdirRec(dir: string) → Promise<void>带有进行中去重缓存的递归mkdir。由阶段6、7和8共享。
runLimited<T>(items: T[], limit: number, fn: (T) → Promise<any>) → Promise<void>以最多limit个并发操作运行每个项上的fn
writeFileMkdirp(filePath: string, content: string|Buffer) → Promise<void>content写入filePath,按需创建父目录。
safeWrite(dest: string, fn: () → Promise<any>) → Promise<void>包装写入回调,在回调抛出时在错误消息中包含dest重新抛出。

阶段6:辅助模块

阶段6并发运行三个写入器。都不写入页面对象;都写入<destRoot>/

redirects.mjs

入口点

js
writeRedirects(pages: Page[], site: object, destRoot: string): Promise<{ written: number }>

对于每个有redirect_from: frontmatter条目的页面,为每个源URL写入一个HTML存根。每个存根使用<script>location=…</script><meta http-equiv="refresh"><link rel="canonical"><meta name="robots" content="noindex">和可见的<a>回退,以支持无脚本/无meta-refresh环境。

读取: page.frontmatter.redirect_frompage.permalinksite.config写入: <destRoot>/下的重定向存根HTML文件。

所有导出

符号签名描述
writeRedirects(pages, site, destRoot) → Promise<{ written }>主入口点。
deriveRedirectStubs(pages, site) -> Array<{ from, to, destPath }>存根列表的纯推导,不写入磁盘。导出以便offline.mjs可以在不重新运行推导的情况下读取列表。

sitemap.mjs

入口点

js
writeSitemap(pages: Page[], site: object, destRoot: string): Promise<{ entries: number }>

按jekyll-sitemap规则过滤页面(删除sitemap: false/404.html),按绝对URL字母顺序排序以实现字节相同的重复运行,并输出sitemap.xml。同时写入带Sitemap:引用的robots.txt

读取: page.permalinkpage.frontmatter.sitemapsite.config写入: <destRoot>/sitemap.xml<destRoot>/robots.txt

所有导出

符号签名描述
writeSitemap(pages, site, destRoot) → Promise<{ entries }>主入口点。
deriveSitemapUrls(pages, site) -> string[]返回将出现在站点地图中的已排序绝对URL列表,不写入磁盘。
extractSitemapUrls(xml: string) → string[]解析现有sitemap.xml字符串并提取其<loc>值。用于比较两次构建。
renderRobotsTxt(config: object) → string生成robots.txt内容字符串。

search.mjs

入口点

js
writeSearchData(pages: Page[], site: object, destRoot: string): Promise<{ entries: number }>

将每个有标题且非search_exclude的页面按标题分割,为每个标题限定段发出一个搜索索引条目,并写入Lunr兼容的JSON索引。

读取: page.renderedContentpage.frontmatter.titlepage.frontmatter.search_excludepage.permalinkpage.seoTitlesite.config写入: <destRoot>/assets/js/search-data.json

所有导出

符号签名描述
writeSearchData(pages, site, destRoot) → Promise<{ entries }>主入口点。
deriveSearchEntries(pages, site) -> object[]返回搜索索引条目数组,不写入磁盘。

阶段7:offline.mjs

<destRoot>/镜像到<destRoot>-offline/,将每个URL重写为页面相对路径,使树可在file://下打开。

入口点

js
writeOffline(
  pages: Page[],
  staticFiles: StaticFile[],
  site: object,
  destRoot: string,
  { auxStats?: object, profileOffline?: boolean }
): Promise<{ html, css, redirects, statics, assets, excluded, unresolved }>

读取阶段5和6写入的每个文件,将绝对URL重写为相对路径,并写入<destRoot>-offline/。通过AST(acorn)修补just-the-docs.js,用离线兼容的实现替换navLinkinitSearch。写入search-data.js,将搜索索引包装为window.SEARCH_DATA赋值,使离线搜索在file://下工作(浏览器在那里阻止XMLHttpRequest)。offline_exclude模式同等应用于页面、静态文件和主题资产;search-data.json列在offline_exclude中,在离线树中不存在——只有.js包装器存在。

读取: <destRoot>(在线树)下的所有文件、auxStats.redirects(来自阶段6的重定向存根列表)。 写入: 所有文件到<destRoot>-offline/

所有导出

符号签名描述
writeOffline(pages, staticFiles, site, destRoot, opts) → Promise<stats>主入口点。
buildOfflineState(pages, staticFiles, site, destRoot, { stubs? }) → Promise<OfflineState>构造所有离线推导函数使用的状态对象(站点路径集、解析缓存、每目录导航缓存)。
deriveOfflinePage(page: Page, state: OfflineState) → string为离线使用重写一个页面的HTML。
deriveOfflineRedirect(stub, state: OfflineState) → string为离线使用重写一个重定向存根的HTML。
deriveOfflineCss(cssIn: string, themeRel: string, state: OfflineState) → string将CSS文件中的url()引用重写为页面相对路径。
deriveOfflineJtdJs(src: string) → string通过AST修补just-the-docs.js:用离线兼容的实现替换navLinkinitSearch。构建时的解析失败是重新提取产生不可读源的信号。
deriveOfflineSearchDataJs(jsonBytes: Buffer) → stringsearch-data.json包装为window.SEARCH_DATA = …并进行压缩。

阶段8:pdf.mjs + book.mjs

生成render-book.mjs渲染为PDF的稀疏<destRoot>-pdf/树。

入口点

js
writePdf(
  pages: Page[],
  staticFiles: StaticFile[],
  site: object,
  destRoot: string,
  { tolerateMissingImages?: boolean }
): Promise<{ bookBytes, css, images, missing }>

调用book.mjsassembleBook(site, pages)生成book.html,复制print.csstb-highlight.css,并收集book.html中引用的每张图片。默认将缺失图片报告为构建错误;--tolerate-missing-images将其降级为警告。

读取: site.bookData(章节选择器已由阶段2的resolveBookChapters解析)、所有页面的page.htmlstaticFiles写入: <destRoot>-pdf/book.html<destRoot>-pdf/*.css<destRoot>-pdf/中的图片副本。

book.mjs阶段8入口点

js
assembleBook(site: object, pages: Page[]): string

遍历site.bookData,发出标题页,然后按顺序遍历front_matterparts。对于每个章节,调用bookChapterTransform应用五种正文转换。然后运行rewriteBookHrefs将书内绝对href转换为#ch-…片段锚点。返回完整的book.html HTML字符串。

所有导出(pdf.mjs

符号签名描述
writePdf(pages, staticFiles, site, destRoot, opts) → Promise<stats>主入口点。
deriveBookOutputs(pages, site) -> { bookHtml: string, images: string[] }纯计算版本:返回已组装的HTML和图片路径列表,不写入磁盘。
extractImagePaths(html: string) → string[]从HTML字符串中提取所有图片src / href路径。

book.mjs的导出参见上面的阶段2 book.mjs


阶段12:serve.mjs

长期运行的开发服务器,通过tbdocs --serve激活。这是一次性构建的独立生命周期;跳过阶段7(离线)和阶段8(PDF)。

入口点

js
runServe(opts: BuildOpts): Promise<void>

运行初始一次性在线构建(预阶段、阶段1--5),然后在opts.port(默认4000)上启动HTTP服务器,递归源树监视器和/_tbdocs/reload的SSE端点。300毫秒防抖在文件更改时触发重建。重建成功后,向每个连接的浏览器标签页发送重载事件。

所有导出

符号签名描述
runServe(opts: BuildOpts) → Promise<void>主入口点。BuildOptsrunBuild接受的对象相同。

共享辅助模块

paths.mjs

所有导出

符号签名描述
permalinkToDestPath(permalink: string) → string将permalink URL转换为目标文件路径。/index.html/foo/foo/index.html;带.html.htm.xml扩展名的路径保持不变;所有其他路径追加.html。由阶段1和阶段6使用。

highlight-theme.mjs

highlight.mjs中的initHighlighter内部调用;通常不被其他阶段直接调用。

所有导出

符号签名描述
loadHighlightTheme(themesDir?: string) → Promise<{ scopeToClass, css }>读取Light.themeDark.theme,按其(light-props, dark-props)对将TextMate作用域分组,为每个唯一对分配一个CSS类,并返回作用域到类的查找和生成的tb-highlight.css内容。

tbdocs.mjs --- 编排器

编排器排序所有阶段并组装site对象。它本身不是一个阶段。

所有导出

符号签名描述
runBuild(opts: BuildOpts) → Promise<{ pages, staticFiles, site, destRoot }>运行完整管线(预阶段、阶段1--8)。返回最终状态以便外部线束可以链接额外工作。
makeTimer() → { lap(label: string): void, summary(): string }轻量计时器。lap(label)记录自上次计时以来的毫秒数;summary()"label=Nms …"字符串返回所有计时。

BuildOpts字段:

字段默认值描述
src"docs"源根目录,相对于cwd
destnull目标根目录。默认为<src>/_site
baseurlnull覆盖config.baseurl
urlnull覆盖config.url
dryRunfalse跳过所有文件系统写入。
skipOfflinenull跳过阶段7。null_config.yml读取also_build_offline
skipPdfnull跳过阶段8。null_config.yml读取also_build_pdf
tolerateMissingImagesfalse在阶段8中将缺失图片错误降级为警告。
profileOfflinefalse在控制台输出中发出阶段7的每子步骤计时。
servefalse启动阶段12而非一次性构建。
port4000阶段12的HTTP端口。

另见

AI生成

twinBASIC及其LOGO版权为作者"韦恩"所有