Scribe

静态资源

使用 field.asset() 声明带有校验的静态资源字段,限制路径和格式,并在读取时将其解析为公开可访问的 URL。

View as Markdown

Scribe 将静态资源(目前主要是图片)视为一等公民,采用基于 schema 声明的引用,而不是松散的字符串。其核心原则是:组件绝不能通过字符串拼接来构建资源 URL。 Frontmatter 存储规范的源引用,运行时则在加载时将其解析为实际提供的 URL。正是这种单一的中间层机制,使得 publicPath、CDN 以及内容哈希都可以通过配置来引入,无需修改代码库。

Configuration

assets 配置组声明了源文件的存放位置及其提供方式。之前简单的 assetsDir 仍然可以作为 { dir: assetsDir } 的弃用别名继续使用。

export default defineConfig({
  // ...
  assets: {
    dir: "public",            // 源文件在磁盘上的存放位置,相对于 rootDir。默认为 "public"。
    publicPath: "/",          // 提供服务时的 URL 前缀。可以是一个路径("/static/")或 CDN 源。默认为 "/"。
    managedDirs: ["/blog-images"], // 额外的由 Scribe 管理的 Web 路径根目录,不属于任何 field.asset() 覆盖范围
  },
});

publicPath 遵循 webpack/Vite 中对该概念的约定。managedDirs 条目是源根目录:即在 MDX 正文中引用,但并未绑定到特定资源字段的目录。

field.asset()

import { field } from "scribe-cms";

const garmentSchema = z.object({
  title: field.translatable(z.string()),
  productImage: field.asset({
    dir: "/try-on/garments",   // 值必须位于该 Web 路径下
    formats: ["webp"],          // 允许的扩展名列表
    maxKB: 150,                 // 大小限制(会触发警告)
    optional: false,            // 默认值
  }),
});

field.relation() 一样,约束条件必须写在配置对象中,而不是通过 Zod 方法链式调用。链式调用会克隆 schema 并丢失元数据。资源字段始终是结构化的:资源路径绝不会发送给翻译系统。

选项类型含义
dirstring值必须位于其下的 Web 路径前缀。同时也声明了一个托管根目录。
templatestring派生路径模板,例如 "/try-on/garments/{slug}/product.webp"{slug} 是条目的英文 slug。设置后,frontmatter 字段可以完全省略,由加载器自动填充。显式值会覆盖模板(用于在条目之间有意共享资源)。
formatsstring[]允许的扩展名(小写,不带点号)。违规将触发校验警告。
maxKBnumber文件大小限制。违规将触发校验警告。
optionalboolean字段可以不存在(仅在没有 template 时有意义)。如果提供了值但文件丢失,仍然会报错。

Frontmatter 中的值是一个指向 assets.dir根相对 Web 路径。例如 /try-on/garments/denim-flare/product.webp,这与普通图片字符串的约定相同,不引入新的 URI 方案。在磁盘上,frontmatter 存储的是源引用(如果使用模板则不存储任何内容)。解析后的 URL 仅存在于运行时输出中。静态/原始导出和翻译系统看到的始终是源值。

Loader resolution

当运行时加载文档时,它会遍历 schema 寻找资源字段,并对每个字段执行以下操作:

  1. 如果 frontmatter 值不存在且字段有 template,则从模板生成路径({slug} 会变成英文 slug)。
  2. 前置 assets.publicPath(拼接时不产生双斜杠,支持绝对域名的 publicPath)。

因此,调用方无需任何额外调用即可获取最终的 URL:

const garment = scribe.garment.get("denim-flare");
garment.frontmatter.productImage;
// "/try-on/garments/denim-flare/product.webp"                       (publicPath 为 "/")
// "https://cdn.example.com/try-on/garments/denim-flare/product.webp" (CDN publicPath)

解析过程在结构化字段合并到本地化文档之后进行,确保每个本地化版本都能从英文源获得解析后的值。

scribe.assets.url(ref)

这是为 MDX 正文图片和临时情况提供的应急方案,可将 publicPath 应用于原始引用:

scribe.assets.url("/blog-images/hero.webp"); // 已应用 publicPath

你也可以在 MDX 正文中通过 asset 内联标记 直接引用资源,它会在读取时以相同方式进行解析。

Validation

scribe validate 会检查已声明的资源字段:

  • 必填资源字段的文件丢失:错误(会阻断构建,就像失效的必填关系一样)。
  • 有值的 optional 字段的文件丢失:也是错误。optional 的意思是字段可以不存在,而不是说可以填一个虚假的路径。
  • 值超出了字段的 dir 范围:错误。
  • 扩展名不在 formats:警告。
  • 文件大于 maxKB:警告。
  • 模板字段会校验生成的路径。即使 frontmatter 省略了该值,文件也必须存在。

提示信息会包含字段归属,例如 garment/denim-flare: productImage → 未找到 /try-on/garments/denim-flare/product.webp。另外,启发式地从 frontmatter 和 MDX 正文收集的类似图片的字符串如果在丢失时仍会报告警告,这样能够在无需迁移的情况下覆盖正文图片。

Studio

Studio 以只读方式展示资源:

  • Entry inspector 将资源字段渲染为图片预览,包含解析后的 URL、文件大小和尺寸。丢失的文件会显示红色徽章。
  • Asset browser/assets)为每个托管根目录显示一个缩略图网格。每个资源都会显示其路径、大小、尺寸以及一个“被引用”列表,列出所有指向它的条目和字段。徽章会标记未引用的资源(候选孤儿文件)、存在引用但文件丢失的资源、过大的资源以及格式不符的资源。
  • Gallery view 允许任何带有资源字段的类型将其条目列表渲染为卡片网格,非常适合作为生成图像的 QA 墙。
静态资源 · Scribe