@farm.js / strapi
用于Farm.js应用的Strapi 5 CMS集成。它配置了官方的Strapi客户端, 展开类型化的集合读取,从生成的上传变量构建响应式图像道具,以及 接收经过身份验证的webhook,以便在编辑器发布后刷新缓存的内容。
看到 稳定性和支持 因为这个包裹保证了什么。
安装
pnpm add @farm.js/strapi @strapi/client
@strapi/client 是对等依赖项,因此应用程序和集成使用一个客户端版本。
配置
import { defineConfig } from "@farm.js/core";
import { strapi } from "@farm.js/strapi";
export default defineConfig({
integrations: {
cms: strapi(),
},
});
在没有选项的情况下,值来自环境:
| 变量 | 目的 |
|---|---|
STRAPI_API_URL | 内容API基础URL,包括 /api. |
STRAPI_MEDIA_URL | 可选的公共媒体来源。默认为API URL的源。 |
STRAPI_API_TOKEN | 用于非公共内容的可选服务器专用API令牌。 |
STRAPI_WEBHOOK_SECRET | 一旦配置了webhook无效,就需要。 |
当配置加载时,而不是在第一个内容请求时,缺少API URL失败。
阅读内容
构建一次客户机,然后在集成和应用程序服务器代码中重用它。
// src/lib/cms.server.ts
import {
createStrapiClient,
createStrapiCollection,
resolveStrapiConfig,
type StrapiDocument,
} from "@farm.js/strapi";
interface Article extends StrapiDocument {
title: string;
slug: string;
}
export const cms = createStrapiClient(resolveStrapiConfig({}));
export const articles = createStrapiCollection<Article>(cms, "articles");
// farm.config.ts
integrations: {
cms: strapi({ instance: cms }),
}
将集合读入 createServerQuery 来验证和缓存结果。助手接受了
官方客户的 populate, fields, filters, sort, pagination, locale, status
查询选项并展开REST data 信封。
import { createServerQuery } from "@farm.js/core";
import { articles } from "./cms.server";
export const postsQuery = createServerQuery({
key: () => ["strapi", "articles"],
staleTime: "5m",
handler: () =>
articles.find({
fields: ["title", "slug"],
populate: ["cover"],
sort: ["publishedAt:desc"],
status: "published",
}),
});
泛型描述应用程序期望的字段。在服务器上保持运行时验证
因为Strapi返回的字段仍然依赖于权限和 populate.
发布时无效
Strapi可以给每个webhook发送一个固定的头。Farm在解析之前验证共享密钥 并询问应用程序该事件影响哪些缓存条目。
strapi({
instance: cms,
webhook: {
onChange(payload) {
if (payload.model !== "article") return;
const entry = payload.entry as { documentId?: string; slug?: string };
return {
keys: [
["strapi", "articles"],
...(entry.documentId ? [["strapi", "article", entry.documentId] as const] : []),
],
paths: ["/articles", ...(entry.slug ? [`/articles/${entry.slug}`] : [])],
};
},
},
});
在Strapi中,创建一个webhook 设置> Webhooks:
- URL:
https://your-app.example/api/strapi/webhook - 事件:映射处理的条目和媒体事件
- 标题名称:
x-farm-webhook-secret - 头值:显示的值
STRAPI_WEBHOOK_SECRET
两者都可以改变 webhook.path 和 webhook.secretHeader. Strapi不签名或重试webhook
交付,所以使用 staleTime 作为新鲜度的退步,而不是仅仅依靠webhook。
提供图片
getStrapiImageProps 选择最小的生成变量,至少与请求的宽度相同
构建一个 srcset 从那个线人的真实变种中。它从不创建转换URL。
import { getStrapiImageProps, type StrapiMediaAsset } from "@farm.js/strapi";
export function Cover({ asset }: { asset: StrapiMediaAsset }) {
return (
<img
{...getStrapiImageProps(asset, {
mediaUrl: process.env.STRAPI_MEDIA_URL ?? process.env.STRAPI_API_URL,
width: 800,
sizes: "100vw",
})}
/>
);
}
绝对的上传提供者url被保留。相对url被解析 mediaUrl,这
可以与Content API主机不同。
生产笔记
- 保持
STRAPI_API_TOKEN而官方客户端仅在服务器模块中。不要从 浏览器输入。 - Farm的默认数据缓存位于每个进程的内存中。配置分布式缓存适配器 Webhook必须使每个服务器实例失效。
- Strapi 5的草案状态需要一个可以读取内容类型的API令牌。不要打草稿 选择依赖于不可信的查询参数;将其置于应用程序拥有的预览授权之后。
选项
| 选项 | 默认的 | 笔记 |
|---|---|---|
apiUrl | STRAPI_API_URL | 内容API基础URL,包括 /api. |
mediaUrl | API的起源 | 相对上传url的公共来源。 |
token | STRAPI_API_TOKEN | 服务器只。 |
instance | 现有的 StrapiClient;跳过API URL验证。 | |
webhook.secret | STRAPI_WEBHOOK_SECRET | |
webhook.path | /api/strapi/webhook | |
webhook.secretHeader | x-farm-webhook-secret | 在Strapi中配置相同的自定义头。 |
webhook.onChange | 将有效负载映射到 { keys?, paths? }. | |
log | 集成生命周期日志记录器。 |