ARTICLE DETAIL

资讯详情

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

dbt v2 文档静态化架构实战:dbt-docs-server 如何用 parquet + DuckDB-WASM 构建零服务端文档站点

dbt v2 文档静态化架构实战:dbt-docs-server 如何用 parquet + DuckDB-WASM 构建零服务端文档站点 dbt v2 文档静态化架构实战dbt-docs-server 如何用 parquet DuckDB-WASM 构建零服务端文档站点【免费下载链接】dbtdbt enables data analysts and engineers to transform their data using the same practices that software engineers use to build applications.项目地址: https://gitcode.com/GitHub_Trending/db/dbt本文围绕仓库内 .agents/dbt-docs-server.md 展开系统讲解 Rust dbt v2 运行时中新一代文档系统dbt-docs-server的完整架构dbt docs generate如何把项目编译产物导出为一份无进程、无状态的静态站点dbt docs serve如何退化为纯静态文件托管浏览器又如何通过 DuckDB-WASM 直接查询 parquet。读完本文你将掌握 dbt v2 文档站点的数据流、命令行用法、部署方式、能力门控机制、前后端技术栈以及在此基础上新增 UI 与查询的完整工作流。一、定位从 v1 的生成 服务到 v2 的导出 托管dbt-docs-server是 dbt Core v1 时代dbt docs generatedbt docs serve的继任者为 Rust dbt v2 运行时重写是一个 Apache 2.0 许可的 crate位于 crates/dbt-docs-server/随 dbt v2 二进制一同发布也可用容器自托管见其 README.md。理解这个 crate 只需抓住一句话dbt docs generate写出一份静态站点全程没有任何服务端查询引擎也没有 HTTP API。crate 只负责把 parquet 工件导出到 React SPA 旁边浏览器从 CDN 加载 DuckDB-WASM每一个查询都在浏览器里执行输出目录可以在任何普通文件托管平台上运行——GitLab Pages、GitHub Pages、S3 都行没有进程、没有状态。而dbt docs serve只是一个本地预览用的静态文件托管器当站点缺失或比索引更旧时它会先生成站点然后原样托管。它只是一个便利工具不是必需组件——生产环境完全没有它的位置。关键红线不读 manifest.json该 crate 有一个被反复强调的关键约束它不读取manifest.json——Rust 侧不读浏览器侧也不读。数据全部来自dbt information schema即target/info_schema/vn/目录下的dbt.*.parquet加生成的views.sql。导出器通过dbt-index-core::Backend具体实现为DuckDbInfoSchemaBackend读取它浏览器通过 HTTP 拉取同一批文件。浏览器绝不自行编写视图 SQL。它拉取views.sql并只执行自己需要的语句实现见 web/src/shared/data-sources/duckdb/viewsSql.ts因此页面查询的关系与旁边 parquet 生成的关系严格一致。文档特别警告在客户端写CREATE VIEW曾让这个应用成为 schema 的第二份定义即跨语言的那一半 fs#13788 问题绝对不要重新引入这种做法。二、数据流全景一份从项目到浏览器的链路关联文档给出了完整数据流这是理解整个系统的主干dbt project │ dbt compile [--static-analysis strict] │ …或什么都不做docs generate 自己会跑编译除非 --no-compile ▼ target/private/metadata/** ← epoch 文件 │ write_info_schema从 epoch 视图 COPYArrow 兜底 ▼ target/info_schema/vn/ ← dbt.*.parquet views.sql注意不是 manifest.json │ dbt docs generate — 把内嵌的 SPA 写到旁边仅此而已 ▼ target/index.html assets/ ← 站点本体数据留在 info_schema/vn/ │ views.sql 拉取一次之后按需整份拉取工件 ▼ DuckDB-WASM来自 jsDelivr CDN运行在页面里 ▼ React SPAhash 路由、相对资源基准路径其中有两个容易踩坑的点值得单独强调列级血缘是编译期产物且默认缺席。编译时加--static-analysis strict才会产出列级血缘没有它导出时不会写出dbt.column_lineage.parquet。这是常态而非边界情况——自动编译docs generate合成的编译刻意只跑普通--write-index不强制 strict。因此列级血缘始终需要通过显式编译来选择加入。信息模式在编译之后构建。详见下一节。三、dbt docs generate每次生成都编译与 v1 一致dbt docs generate无条件编译。它合成一次compile --write-index调用交给普通的 phase 流水线执行build_index_for_docs入口见 crates/dbt-main/src/dbt_lib.rs随后再从 metadata 构建信息模式build_info_schema_for_docs。因此一个全新 checkout 只需一条命令而不是两条。为什么信息模式要在编译之后构建dbt docs generate特意在编译及 metadata ingest 完成之后才构建信息模式而不是交给编译自带的--generate-info-schema。原因是invocation 记录invocation record是在那个时间点之后才写入的如果提前构建就会漏掉它导致站点的 timings 与 status 面板一片空白。这也正是相关 ingest 会执行两次的原因源码注释见 crates/dbt-main/src/dbt_lib.rs。刻意不做工件存在性检查早期版本只在index_dir/没有工件时才编译结果是当天第二次执行docs generate会发布第一次编译的旧产物——无论文档怎么写这读起来都像缓存 bug。现在采用的原则是--no-compile已经明确表达了使用磁盘上现有内容无需任何推断这正好与 v1 的无条件编译行为一致。合成调用的两个关键字段合成出来的调用携带EvalArgs::command Compile因为 phase 流水线在大约二十多处分支依赖这个值换成任何其他值都会静默产出接近空的索引command_entrypoint Docs让调用来源保持可见正是这个字段抑制了--write-index的静态分析建议——否则系统会提示用户去给一条他们根本没运行过的命令加参数。参数速查参数行为--no-compile跳过编译退化为纯导出器此时缺失索引属于错误而非触发编译--compile接受但作为隐藏的 no-op仅为 v1 脚本兼容而存在--output-dir dir导出一份自包含目录索引以逐字节副本随行位于dir/index/--duckdb-cdn-base url覆盖 DuckDB-WASM 的 CDN 基地址默认见 src/export/mod.rs 中的DEFAULT_DUCKDB_CDN_BASE当前锁定为 jsDelivr 上的duckdb/duckdb-wasm1.32.0注意发布target/目录会把其中所有内容都发布出去——manifest.json、run_results.json、编译后的 SQL甚至target/data/下存储的测试失败记录。需要一份只含站点本身的自包含目录时请用--output-dir dir。导出器实现要点导出逻辑集中在 src/export/mod.rs值得关注的实现细节拒绝写出零资源站点通过SELECT COUNT(*) FROM dbt_internal.resources检查资源数为 0 时报EmptyIndex错误——因为空的资源并集永远意味着输入有问题而不是项目真的缺少某种资源类型无索引时报NoIndex错误信息会同时点名dbt build与dbt docs generate两条可产生工件的命令data_dir()动态推导站点数据目录是info_schema/vn/其中版本号vn属于写入方dbt-index-core的INFO_SCHEMA_VERSION因此由函数推导而非硬编码避免写入方版本前进后站点还在服务旧v1has_column_lineage问的是行数table_has_rows(dbt.column_lineage)——用的是后端同时是浏览器会问的同一个问题所以进度消息与站点展示不会互相矛盾详见能力门控一节复制而非投影copy_info_schema把 parquet 与views.sql逐字节复制到站点目录文件保持原名、原列、原内容保证自包含站点与原位站点读到的契约完全一致。四、dbt docs serve一个没有路由的路由器服务端实现浓缩在 src/server.rs它的形态本身就是架构的宣言// 没有任何路由。站点是静态的index.html、哈希化资源、浏览器自行查询的 parquet。 // 曾经由 /api/v1/* 处理器计算的一切现在都在客户端对着这些 parquet 执行 // 所以除了文件之外已经没有任何东西需要服务了。 let app Router::new();关键点只有一个静态 fallback。若指定了site_dir即已生成的站点则从该目录提供文件serve_site_dir否则退回到内嵌 bundleserve_assets。生成站点优先于内嵌 bundle因为只有生成站点才带有注入的 bootstrap 和旁边的 parquet 工件默认监听127.0.0.1:8580启动后自动尝试打开浏览器macOS 用openLinux 用xdg-openWindows 用cmd /C start可用--no-open关闭优雅关闭有 25 秒排水上限低于 Kubernetes 典型terminationGracePeriodSeconds30 秒保证在 SIGKILL 前干净退出。关机时无需冲刷任何事件缓冲——遥测由浏览器直发收集端ADR-10服务器不持有缓冲事件。数据目录解析resolve_info_schema_dir见 src/lib.rs按如下顺序解析站点数据目录--target-path若提供→target_path/info_schema/vn/否则当前工作目录下./target/info_schema/vn/。与索引不同信息模式不在target/private/之下它是站点自己的数据目录要通过 HTTP 对外服务所以必须可发布。五、能力门控特性靠检测不靠假设dbt-docs-server只依赖dbt-index-core的公开 trait。哪些 parquet 存在取决于索引如何生成因此特性是检测出来的而不是假设出来的——而且检测现在发生在浏览器里。has_column_lineage的判定逻辑是整个系统最精巧的一处看行数不是看文件在不在信息模式会写入每一张表即使 0 行恰恰是为了让views.sql总能解析成功所以dbt.column_lineage.parquet这个文件永远都在大小也不是信号在一个真实项目上有数据的和空的两份文件都实测为 1552 字节所以按大小判断的方案会误报没有列级血缘相关注释见 src/export/mod.rs导出器的进度消息与浏览器问的是同一个行数问题二者不可能互相矛盾。两条由此推导出的铁律文档明确记录两者都咬过人缺席必须看起来是刻意的。降级路径就是默认路径因此一个被门控的表面如果渲染成空列表 侧边栏非零计数会被读作数据丢失。必须使用useSourceQuery上的isSupported以及不支持表面unsupported-surface提示消息信息模式写入每一张表空表也写 schema-only因此客户端 SQL 可以假定所有关系都存在无需视图可能缺失的变体分支。客户端不再有任何空关系 DDL也就没有需要与其保持同步的东西。被门控的表面渲染的是 upsell/回退状态——没有 412没有错误。并且门控必须在查询之前进行绝不能在 catch 异常时判定把一次查询抛错映射成被门控会把 SQL 里的每一个错误都渲染成一张升级卡片。六、工件集Artifact Set信息模式即契约信息模式定义于 crates/dbt-index-core/src/info_schema/schema.rs由 crates/dbt-index-core/src/info_schema/views.rs 渲染为视图。不存在导出的工件集站点按原样读取target/info_schema/vn/——无投影、无拆分、无复制。window.__DBT_DOCS__.data_dir携带目录含版本号因为版本属于写入方--output-dir则原样复制它含views.sql所以独立站点读取的是同一批文件。命名对照索引 vs 信息模式下面这些名字不是索引里的名字务必记牢索引index信息模式information schemadbt.nodes每种资源类型一张表dbt.models、dbt.seeds……由dbt_internal.resources并集dbt.docs/block_contentsdbt.docs_blocks/contentdbt.test_metadata折入dbt.data_testsdbt.source_freshnessdbt_rt.freshnessdbt.catalog_tables EAVdbt.catalog_statsdbt_rt.relations每个关系一行、类型化dbt.generationdbt.project.last_full_parse_ataccess_level、group_name、patch_path、declared_type、from_*/to_*access、group、properties_yml_file_path、data_type_declared、parent_*/child_*三个值得知道的后果dbt_internal.resources会读取每一份资源工件。当资源类型已知时请用类型化表——列表与详情都是这么做的。并集视图只服务于真正跨类型的表面计数、文件树、搜索、血缘元数据。dbt.dag_nodes不是替代品它只有三列、只保留启用行、只含 DAG 类型。resources_statement用UNION ALL BY NAME而非UNION ALL拼装各分支因为各分支列集不同缺列的会以 NULL 呈现而非绑定失败见 crates/dbt-index-core/src/info_schema/views.rs。首帧渲染不能使用views.sql。此时 DuckDB 尚未就绪所以 web/src/shared/data-sources/duckdb/bootstrap.ts 用 hyparquet 逐个读取各资源工件并拼接。这份列表是应用里唯一还在 TypeScript 中直接点名信息模式表的地方某个资源类型如果漏在这里症状是侧边栏某段静默为空。每张表都会写入空表写 schema-only。工件缺失意味着站点坏了而不是一个信号——与索引恰恰相反这也是为什么客户端不再有任何空关系 DDL。当前不可用的数据UDF/函数资源在 dbt v2 写出 UDF parquet 之前计数恒为 0Catalog 数值row_count、bytes、last_modified需要dbt run或dbt build——catalog 拉取被这两个命令门控而docs generate合成的是compile且 DuckDB 根本不报告 catalog 统计因此要端到端验证该列需要 Snowflake 或 BigQuery。七、技术栈前端与后端各司其职前端路径相对 crates/dbt-docs-server/web/React 19 TypeScript Vite独立 pnpm 项目不属于任何 workspace路由react-router-dom的HashRouter Vitebase: ./LinkPrefixProvider prefix/路由器独占#。三者缺一不可共同支撑子路径无关的静态托管普通文件宿主不做任何重写如果走真实路径深层链接刷新就会 404而 hash 永不抵达服务器从而保证document.baseURI稳定可用于解析数据目录数据tanstack/react-query包着MetadataDataSource适配器在src/shared/。createDuckDbDataSource是唯一的生产实现样式Tailwind配置于 tailwind.config.cjs带 sourdough 与 dbt-dag 预设外加src/app.css 中手写、以 BEM 风格类前缀如locate-pane__为键的 CSS。两者并存——新增样式前先查app.css并优先使用 sourdough 的 CSS 自定义属性var(--fgMain)、var(--bgMainHover)等而非字面颜色图标dbt-labs/sourdoughRyecon与dbt-labs/dbt-dagDbtResourceIconsrc/shared/是 fork它是 dbt-ui 中dbt-labs/metadata-shared的 docs-v2 切片。布局与 barrel 与上游镜像便于 diff。请把它当 vendored 代码对待倾向增量式本地修改并预期上游漂移私有依赖dbt-labs/sourdough、dbt-dag、biga来自 GitHub Packages因此pnpm install需要带read:packages权限的GITHUB_TOKEN。cargo build则不需要——web/dist/是提交入库的。后端路径相对 crates/dbt-docs-server/Rustaxumtokioarrow-arrayrust-embed依赖清单见 Cargo.tomlsrc/export/ ——整个产品的核心工件选择、COPY … TO、bootstrap 注入src/server.rs —— 一个没有路由的路由器只有静态 fallbacksrc/state.rs ——AppState索引目录 provider trait 对象。关键文件地图文件职责src/export/mod.rs导出器data_dir()零资源拒绝写出血缘按行数判定src/export/bootstrap.rswindow.__DBT_DOCS__注入//转义以防载荷操纵 HTML tokenizersrc/server.rs静态托管。无路由src/state.rsAppState数据目录 providersweb/src/main.tsx唯一的生产数据源构造点bootstrap 缺失则抛错web/src/types.ts比 API 活得更久的共享线缆词汇NodeSummary、遥测事件联合web/src/lib/siteBootstrap.ts读取并版本检查window.__DBT_DOCS__基于document.baseURI解析data/web/src/lib/vortexSink.ts浏览器 Vortex 生产者拒绝同意时enabled: false任何调用点都无法泄漏web/src/shared/data-sources/duckdb/viewsSql.ts拉取并解析随附的views.sql、engine.tsCDN 加载、registerFileBuffer、按需注册、bootstrap.tshyparquet 首帧、sql.ts、lists.ts、details.ts、search.tsweb/src/shared/data-sources/duckdb/realArtifacts.test.ts应用内每个查询绑定真实信息模式的测试。可选启用DBT_DOCS_REAL_ARTIFACTStarget/info_schema/v1 pnpm testweb/src/shared/data-sources/mappers/fromWire.ts唯一的映射层46 个测试。每个 SQL 投影里的列名必须与这些 mapper 读取的一致——这就是防漂移的守卫web/src/shared/data-sources/conformance.test.ts与协议无关的MetadataDataSource套件把 fake 与 DuckDB 源约束在同一契约下web/src/shared/typings/domain/领域类型Asset、ModelSummary、Capabilities……web/src/lib/resourceType.tsx资源类型顺序、标签、图标、徽章颜色的唯一事实源web/src/components/LocatePane.tsx侧边栏AssetMode、TreeMode、FilterModeweb/src/app.css手写 CSS与 TSX 中的 Tailwind 工具类并存web/dist/提交入库的构建产物由rust-embed嵌入改动后用pnpm build重新生成八、典型本地循环与部署实践最小本地循环dbt docs generate # 先编译再写入 target/ cd target python3 -m http.server # 一个无 SPA rewrite、无 range 请求的宿主文档特别强调最后一步是承重检查——如果它在http.server下能用那么在 GitLab Pages 上也能用。需要列级血缘或想免编译迭代导出器dbt compile --generate-info-schema --static-analysis strict dbt docs generate --no-compile两种路径的取舍dbt docs generate不带--no-compile从干净 checkout 一条命令搞定一切dbt compile --write-index --static-analysis strict或dbt build --write-index …显式产出带列级血缘的索引随后dbt docs generate --no-compile原样导出两步式也适用于仓库不可达、或希望导出保持廉价只读的场景--no-compile且无索引时命令报错而非触发编译。生成的站点布局target/index.html SPA 入口注入 window.__DBT_DOCS__ target/assets/ 哈希化的 JS/CSS target/index/ 站点数据从引擎索引复制的 parquetindex.html落在 dbt Core v1 曾经写它的同一位置因此既有发布target/的流水线可以不加改动地继续工作。Docker 与 Docker Compose仓库自带 docker-compose.yml 与 Dockerfile# docker compose把 DBT_TARGET_PATH 指向项目的 target/建议绝对路径 DBT_TARGET_PATH/abs/path/to/project/target docker compose up --build # 打开 http://localhost:8580 # 钉住 dbt 版本 DBT_VERSION2.0.0-beta.2 DBT_TARGET_PATH/abs/path/to/project/target docker compose up --build # 纯 Docker构建 docker build -t dbt-docs-server crates/dbt-docs-server docker build -t dbt-docs-server --build-arg DBT_VERSION2.0.0-beta.2 crates/dbt-docs-server # 运行必须挂载工件目录否则容器启动即退出 docker run --rm -p 8580:8580 \ -v $PWD/target:/data/target:ro \ dbt-docs-server # 用命名卷持久化 ADBC 驱动缓存支持离线运行 docker run --rm -p 8580:8580 \ -v $PWD/target:/data/target:ro \ -v dbt-adbc-cache:/var/cache/dbt \ dbt-docs-server两点提示Dockerfile 从该仓库的 GitHub Releases 下载已发布二进制并对照SHA256SUMS校验多阶段 BuildKit 构建无需 cargo 工具链由于默认构建参数不变Docker 会复用缓存层升级版本请显式传参或--no-cache。另外 ADBC DuckDB 驱动不内置于镜像首次运行需出网下载缓存目录/var/cache/dbt。dbt docs serve命令行参数Flag环境变量默认值含义--target-path DIRDBT_DOCS_TARGET_PATH./target持有private/index/parquet 的目录--host HOSTDBT_DOCS_HOST127.0.0.1绑定地址--port PORTDBT_DOCS_PORT8580监听端口--no-open—关闭不自动打开浏览器标签从源码构建与重建 UI后端构建完全不需要 JavaScript 工具链cargo build -p dbt-cli会原样嵌入提交入库的web/dist/。只有改动web/下的代码才需要重建 UIcd crates/dbt-docs-server/web pnpm install pnpm build # 写入 web/dist/ pnpm dev # vite dev server:3002设 DBT_DOCS_DEV_SITE已生成的站点 读取真实数据 pnpm test # vitest pnpm typecheck pnpm lint # eslint prettier重要任何web/源码改动都必须在同一变更里执行pnpm build并提交web/dist/。没有任何 CI 任务或 git hook 强制这一点只提交源码会静默发布一个过期的 UI。定制外观无需 React 知识强调色编辑 web/src/styles/tokens.css 中的--bgBrand*自定义属性浅色/深色变体都在该文件页面/标签标题编辑 web/index.html 的titleFavicon默认未设置在web/public/下加图标文件并在web/index.html加link relicon。改完同样要pnpm build并提交web/dist/。九、契约与 ADR那些仍然有效的架构决策API-CONTRACTS.md 记录了完整的设计决策史。需要特别说明的是这些 ADR 写于静态化重构之前以 REST 端点为语境但决策本身依然有效——它们约束的是UI 拿到什么数据、以什么形状。阅读时把endpoint理解为该表面背后的查询即可。决策规则何时重新审视类型化详情查询每种资源类型一个投影不做通用任意节点详情查找MCP 加入 dbt-docs-server 时execution_info位置嵌套在资源详情上运行结果缺席时为 null需要运行历史最近 N 次时共享基础投影类型化详情查询组合公共节点字段而非逐条重述永不移除只能扩展字段命名mapper 读到的每个列都用snake_caseCC-1永不嵌套对象保留 Discovery API 形状的嵌套对象不扁平化CC-2仅扁平化单例包装能力门控可空字段由能力标志门控绝不用查询变体CC-3永不测试折叠test 详情把test.*与unit_test.*作为resource_type上的判别联合一并服务两者渲染在同一页面ADR-3单元测试与通用测试需要独立详情页时execution_info字段命名只留裸名status、completed_at、error。无last_run_*或阶段前缀——这是快照不是历史ADR-4需要多运行历史时浏览器直发遥测事件客户端编码后直 POST 到 Vortex无中继ADR-10取代 ADR-9同意机制需要重新引入服务端权威时关于execution_info的三种形态契约文档在数据形状上做过三次演进值得单独理解ADR-2放置位置——内联在资源详情中dbt_rt.run_results中没有该资源行时为 nullADR-4字段命名——只用裸名。dbt-docs-server 是快照服务器而非历史服务器不存在上一轮Discovery API 的lastRunStatus、executeCompletedAt、lastRunError等前缀暗示存在倒数第二轮在此全部去掉lastKnownResult直接丢弃ADR-5省略——对从不产生dbt_rt.run_results行的资源类型exposure、group、macro、metric、saved_query、semantic_modelexecution_info整个省略而非 null否则就是一个构造上即死的字段。相应地NodeBase拆分为NodeBase所有资源共有、RunnableNodeBase加tags、fqn、execution_info与DefinitionNodeBase加tags、fqn、created_atGroup 因dbt.groups无fqn而直接组合NodeBase。列表契约ADR-6 游标分页所有列表端点统一为 Relay 风格的游标分页?firstafterpage_info理由有三dbt-ui 本就讲游标语言只读 parquet 快照使写入期间游标不稳定这一最难的性质无需防御每个资源都有unique_id作为稳定的决胜键(sort_val, unique_id)复合游标无歧义DuckDB 原生支持元组比较。分页信封形如{ data: [ /* 条目摘要 */ ], page_info: { total_count: 42, start_cursor: eyJzIjoibW9kZWwuYWxwaGEiLCJpIjoibW9kZWwuanMuYWxwaGEifQ, end_cursor: eyJzIjoibW9kZWwub3JkZXJzIiwiaSI6Im1vZGVsLmpzLm9yZGVycyJ9, has_next_page: true } }end_cursor是不透明的 base64 载荷客户端原样回传服务器保留随时更改内部形状的权利。游标只在当前dbt docs serve进程生命周期内有效重启即失效被篡改或越界的游标必须 400 失败关闭绝不静默当作首页请求重新解释。ADR-8统一搜索端点跨资源搜索是 ADR-1类型化端点原则的唯一文档化例外用户只输入一个查询、UI 只渲染一个混合类型结果列表因此采用统一的GET /api/v1/searchhit以resource_type判别。除它之外的任何端点都不允许以该例外为由新增。ADR-10浏览器直发 Vortex 遥测静态站点没有服务器ADR-9 的服务端中继机制不复存在选择是浏览器直发或干脆不发。三项原反对意见逐一重审同意导出时解析并内联进window.__DBT_DOCS__——这是唯一能回答同意问题的位置因为同意存在于项目与 profile 中只有运行dbt docs generate的机器能读取拒绝时生产者配置为enabled: false静默丢弃所有事件任何调用点都无法绕过CORS已对收集端实测验证无需基础设施改动事件内容与中继时代完全一致同 8 个事件、同字段传输层变了schema 没变。原中继服务端补全的字段dbt_version、distribution、is_logged_in、dbt_cloud_*上下文改为导出时从DistInfoProvider::telemetry_hydration()烘焙进 bootstrap。代价也记录在案摄取 URL 进入了发布产物补全字段不再是权威托管者可以编辑 bootstrap同意在生成时固化撤销同意需要重新生成站点无投递保证标签页中途关闭仍会丢事件与 ADR-9 的202姿态相同。十、新增 UI 或查询的六步工作流合约与 ADR 都在 API-CONTRACTS.md。给这个站点加 UI 或查询时遵循以下流程这是该 crate 内部实践的高度浓缩先读API-CONTRACTS.md——检查既有 ADR任何设计提案都不得重开已关闭的 ADR接 SQL 之前先对着真实 parquet 跑一遍。这是本 crate 杠杆率最高的习惯原始移植中的 9 个 bug 都是列名问题不存在的n.language、JSON 字符串而非 struct 的列meta、或与直觉不同的命名dbt.project存的是project_name而非name迁移到信息模式又添了 2 个。类型系统与 fixture 测试都抓不到这类问题。realArtifacts.test.ts以机械化方式完成同样的事dbt compile --generate-info-schema --static-analysis strict DBT_DOCS_REAL_ARTIFACTSproject/target/info_schema/v1 pnpm test让投影列名与fromWire.ts读取的保持一致——mapper 就是契约改列名会静默把字段置 null可空数据用工件存在性门控绝不用构建标志或查询变体图标统一用DbtResourceIcon resource{type}来自dbt-labs/dbt-dag覆盖所有资源类型含 group无需特例CSS 用 sourdough 变量沿用app.css中既有的 BEM 类前缀。十一、图标参考每种资源类型用什么图标DbtResourceIcon来自dbt-labs/dbt-dag是所有资源类型的权威图标组件其resourceIconMap把每个类型映射到dbt-labs/sourdough的一个 Ryecon 图标资源类型resourceIconMap条目备注modelRyeconModelsourceRyeconDatabasetest、unit_testRyeconClipboardSuccessUI 中 unit_test 折叠进 testexposureRyeconMetergroupRyeconGroupmetricRyeconChartColumnsemantic_modelRyeconGraphNodesseedRyeconSeedmacroRyeconFilesnapshotRyeconCamerasaved_queryRyeconSavefunctionRyeconFunction计数为 0直到 dbt v2 写出 UDF parquetanalysisRyeconCrosshair为旧项目兼容保留DbtResourceIcon的resourceprop 期望一个特定的联合类型若 TypeScript 报错可用resource{t as any}断言并用cargo xtask check-llm -p dbt-docs-server验证。十二、遥测事件从浏览器直发 Vortex遥测栈为dbt-labs/vortexdbt-labs/protobufbuild/protobuf事件在客户端编码后直发 Vortex 收集端ADR-10 的推理与对 ADR-9 的取代关系见 API-CONTRACTS.md。同意承载于window.__DBT_DOCS__.telemetry.enabled导出时解析——只有运行dbt docs generate的机器能读项目和 profile不可读的 bootstrap 默认拒绝同意fail closed补全dbt_version、distribution、is_logged_in、dbt_cloud_*上下文从DistInfoProvider::telemetry_hydration()在导出时烘焙进 bootstrapdbt-labs/vortex在PLATFORM nodejs的 dev 分支里会await import(node:fs)——浏览器安全但 Vite 每次构建都会对外部化的node:fs告警。不要通过 vendoring 生产者来修复它事件 schema 继承自中继且单独评审不要把 UI 改动顺带加进字段。总结dbt-docs-server用一次彻底的去服务端化重构把 dbt 文档系统从生成 服务变成了导出 托管Rust 侧只做两件事——把信息模式与 SPA 写成一个静态目录src/export/mod.rs以及在本地预览时提供一个无路由的静态宿主src/server.rs所有查询能力全部下沉到浏览器内的 DuckDB-WASM数据契约收敛为信息模式自身dbt.*.parquetviews.sql。在此基础上按行数判血缘、按工件存在门控能力、客户端不作者化 SQL、导出时烘焙同意等决策共同保证了站点在任何普通文件宿主上的一致性表现——正如文档反复强调的那句承重检查如果它在python3 -m http.server下能用它就能在任何静态托管平台上运行。【免费下载链接】dbtdbt enables data analysts and engineers to transform their data using the same practices that software engineers use to build applications.项目地址: https://gitcode.com/GitHub_Trending/db/dbt创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表