静态资源
使用 field.asset() 声明带有校验的静态资源字段,限制路径和格式,并在读取时将其解析为公开可访问的 URL。
View as MarkdownScribe 将静态资源(目前主要是图片)视为一等公民,采用基于 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 并丢失元数据。资源字段始终是结构化的:资源路径绝不会发送给翻译系统。
| 选项 | 类型 | 含义 |
|---|---|---|
dir | string | 值必须位于其下的 Web 路径前缀。同时也声明了一个托管根目录。 |
template | string | 派生路径模板,例如 "/try-on/garments/{slug}/product.webp"。{slug} 是条目的英文 slug。设置后,frontmatter 字段可以完全省略,由加载器自动填充。显式值会覆盖模板(用于在条目之间有意共享资源)。 |
formats | string[] | 允许的扩展名(小写,不带点号)。违规将触发校验警告。 |
maxKB | number | 文件大小限制。违规将触发校验警告。 |
optional | boolean | 字段可以不存在(仅在没有 template 时有意义)。如果提供了值但文件丢失,仍然会报错。 |
Frontmatter 中的值是一个指向 assets.dir 的根相对 Web 路径。例如 /try-on/garments/denim-flare/product.webp,这与普通图片字符串的约定相同,不引入新的 URI 方案。在磁盘上,frontmatter 存储的是源引用(如果使用模板则不存储任何内容)。解析后的 URL 仅存在于运行时输出中。静态/原始导出和翻译系统看到的始终是源值。
Loader resolution
当运行时加载文档时,它会遍历 schema 寻找资源字段,并对每个字段执行以下操作:
- 如果 frontmatter 值不存在且字段有
template,则从模板生成路径({slug}会变成英文 slug)。 - 前置
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 墙。