内容个性化分析
Next.js SDK 适应器
@contentful/optimization-nextjs 是 Next.js 应用程序的稀疏适配器。 它组成了节点
服务器帮助器, React Web root, 和边缘安全核心通过器; 这不是一个新的优化
运行时间。 包根有意没有运行时间导出 。 导入文件之一
子路径这样服务器,客户端,路由器,和边缘边界保持清晰.
[大
从v1升级? 跟着 v1-v2 迁移指南 在更改软件包版本之前.
这个软件包提供了什么
| 运行时间 | 导入路径 | 责任 |
|---|---|---|
| App 路由器服务器 | @contentful/optimization-nextjs/app-router/server | 服务器绑定、请求模式和明确的交接助手 |
| App 路由器客户端 | @contentful/optimization-nextjs/app-router/client | App 路由器客户端组件的客户端绑定 |
| 缓存中间软件 | @contentful/optimization-nextjs/cache-middleware | 下一个代理或中间软件 公用配置缓存重写 |
| 页面路由器 | @contentful/optimization-nextjs/pages-router | Pages 路由器客户端绑定和反应根 |
| 页面服务器 | @contentful/optimization-nextjs/pages-router/server | 页面路由器 getServerSideProps 请求移交 |
| 边缘 | @contentful/optimization-nextjs/edge | 边际运行时间请求和公转交接工具 |
| 客户端 | @contentful/optimization-nextjs/client | 路由器中性 React SDK 提供者、 钩子、 根 |
| 示马斯 | @contentful/optimization-nextjs/api-schemas | 共享 API 类型、 计划、 结构守护 |
| 服务器 | @contentful/optimization-nextjs/server | 节点 SDK 配置、 请求绑定、 包装 |
| 请求处理器 | @contentful/optimization-nextjs/request-handler | 下一个中件/ 代理请求上下文转发 |
| 跟踪 | @contentful/optimization-nextjs/tracking-attributes | 安全部门改革 data-ctfl-* 跟踪属性 |
安装
pnpm add @contentful/optimization-nextjs contentful
Next.js,React,和React DOM是应用程序拥有的同级依赖关系. 适配器使用运行时间
已经由您的应用程序安装, 而不是安装自己的副本 。 这个 contentful 软件包是
用于获取实例的管理条目的应用程序拥有的 CDA 客户端.
约束 OptimizationProvider 处理 React Web 内容 SDK 上下文,浏览器交接,
水分化模式, 和有管理的进取预置子树。 使用约束 OptimizationRoot 路线
根,因为它增加了初始的页面事件线条通过 routeKey, (中文(简体) ), buildPagePayload,或
initialPagePayload。不要将这些页面活动道具传递给 OptimizationProvider。 。 。 .
对于手动服务器和边缘请求,通过 profileId 经验连续性或全经验
Profile 结束 profile 为"洞察力"送货.
请求地点
设定 api.location 在普通的 App 路由器、 Pages 路由器、 服务器或 Edge SDK 配置中.
客户端绑定在初始化期间将它传给他们拥有的 React Web 运行时间 :
const optimization = bindNextjsAppRouterServerOptimization({
spaceId: 'space-id',
api: { location: { countryCode: 'DE', city: 'Berlin' } },
})
用于特定请求地点 experienceOptions.location 现有人工请求
帮助: App 路由器 createRequestHandoff(),页路由器 createRequestHandoff(context, options), (中文(简体) ),
边缘 createEdgeRequestHandoff(),或 /server 请求帮助者,例如
bindNextjsOptimizationRequest()。例如,在手动 App 路由器流中:
const handoff = await optimization.createRequestHandoff({
cache: { scope: 'private-request' },
hydration: 'preserve-server',
pagePayload: { properties: { route: '/products' } },
request: incomingRequest,
experienceOptions: { location: { countryCode: 'FR', city: 'Paris' } },
})
请求值取代整个配置的默认值 。 使用 experienceOptions: { location: {} }
用于明确的空默认,而不是 API 地理定位。 活动 context.location 优先排序
超过匹配请求字段。 位置适用于经验突变;可信任的交接文件
Get retrach 不应用它。 服务器位置不是以后浏览器的永久配置锁定
请求; 配置浏览器 api.location 当运行时间需要相同的默认时,则单独进行.
空位置无法清除现有的配置文件位置 。 见
位置输入和简介更新。 。 。 .
应用路由器设置
使用明确的 /app-router/server 财务报告和审定财务报表 /app-router/client 输入点使每个模块有一个
运行时间和类型表面. bindNextjsAppRouterServerOptimization() 返回时
NextjsAppRouterServerOptimization· ; bindNextjsAppRouterClientOptimization() 返回时
NextjsAppRouterClientOptimization。 。 。 .
要求个性化快速启动
将服务器SDK装入一次只装在服务器模块中. 被窝住 optimization.request 家庭就是我们
个人化请求的默认表面 :
import 'server-only'
import { bindNextjsAppRouterServerOptimization } from '@contentful/optimization-nextjs/app-router/server'
import { contentfulClient } from './contentful'
import { getAppConsent } from './consent'
export const optimization = bindNextjsAppRouterServerOptimization({
spaceId: 'space-id',
environment: 'master',
locale: 'en-US',
contentful: { client: contentfulClient },
consent: {
server: ({ cookies }) => (getAppConsent(cookies) ? { events: true, persistence: true } : false),
clientDefaults: { consent: false, persistenceConsent: false },
},
})
export const {
NextAppAutoPageTracker: RequestNextAppAutoPageTracker,
OptimizationProvider: RequestOptimizationProvider,
OptimizationRoot: RequestOptimizationRoot,
OptimizedEntry: RequestOptimizedEntry,
} = optimization.request
配置请求处理器, 因此 Server 组件接收静态请求上下文 。 下一个.js 16
用途 proxy.ts 带有 proxy 输出。 下一个.js 13至15个用途 middleware.ts 带有 middleware
导出; 处理器正文相同 :
import { createNextjsOptimizationContextHandler } from '@contentful/optimization-nextjs/request-handler'
export const proxy = createNextjsOptimizationContextHandler()
在请求边界外保留公共 shell 内容 。 把请求的运行时间,跟踪器,和
内部个性化岛屿 Suspense; 跟踪器读取 Next.js 搜索参数。 根预选
并向浏览器交接提供管理下的基线 :
import { AppShell } from '@/components/AppShell'
import { Hero } from '@/components/Hero'
import {
RequestNextAppAutoPageTracker,
RequestOptimizationRoot,
RequestOptimizedEntry,
} from '@/lib/optimization'
import { Suspense } from 'react'
const heroEntryId = 'hero-entry-id'
function PersonalizedContentFallback() {
return <section aria-busy="true">Loading featured content…</section>
}
export default function Page() {
return (
<AppShell>
<Suspense fallback={<PersonalizedContentFallback />}>
<RequestOptimizationRoot prefetchManagedEntries={[heroEntryId]}>
<RequestNextAppAutoPageTracker />
<RequestOptimizedEntry entryId={heroEntryId}>
{(resolvedHero) => <Hero entry={resolvedHero} />}
</RequestOptimizedEntry>
</RequestOptimizationRoot>
</Suspense>
</AppShell>
)
}
请求家庭创造了一个 private-request 移交、使用 preserve-server 默认水分化,
并让所有四个请求组件共享相同的请求初始化. 为SDK管理
条目中,它开始请求初始化和内容基线获取,然后解决
之后的选定变体。 它获得URL,路由密钥,初始页面有效载荷,
信头,以及来自已转发的请求上下文的 cookie 。 应用程序不需要自己的反应缓存,
请求 shell 、 重复等待 、 URL 解析 、 或 页面加载 .
选择谁拥有条目获取
两种获取工作流程都解决了请求选择的内容:
| 所有权 | 条目来源 | 使用时间 |
|---|---|---|
| 注册 | baselineEntry | 您的应用程序拥有内容客户端、 查询、 缓存或数据层 . |
| SDK 管理 | entryId 或者说 managedEntry | 服务器绑定配置 contentful: { client } 而SDK拥有基准读取. |
对于应用软件的取取,加载条目并直接通过:
const hero = await getHeroEntry({ locale: 'en-US', include: 10 })
return (
<RequestOptimizedEntry baselineEntry={hero}>
{(resolvedHero) => <Hero entry={resolvedHero} />}
</RequestOptimizedEntry>
)
只有SDK管理的取取程序在请求初始化和内容之间直接重叠 读取。 App自有的取回程序仍然使用同样的请求选择的解析程序 基线.
仍然需要代理或中间软件边界,因为它转发了已消毒的请求 URL.
保留任何 Suspense 或者说 connection() 您的 Next.js 渲染和缓存所需的边界
组件设置; 请求模式删除 SDK 请求管道, 而不是 Next.js 渲染要求 .
设定 request.hydration 在服务器绑定器上,只有当一个路由需要另一个固定的水合模式或
一个基于 requestUrl 财务报告和审定财务报表 routeKey设置 request.trustedRequestHandoff 改为
true 只有在请求处理器配置到服务器 SDK 并获得同意后才能转发
信任的页面和配置文件上下文 .
客户端组件
绑定 App 路由器客户端表面 "use client" 模块。 它没有私人要求的家庭或
手动服务器交接 API :
'use client'
import { bindNextjsAppRouterClientOptimization } from '@contentful/optimization-nextjs/app-router/client'
export const clientOptimization = bindNextjsAppRouterClientOptimization({
spaceId: 'space-id',
environment: 'master',
locale: 'en-US',
consent: {
clientDefaults: { consent: false, persistenceConsent: false },
},
})
服务器绑定器使用 contentful 在服务器功能路径中省略该客户端的序列
客户端道具。 保留任何只浏览器的Contentful获取明确应用的自控.
绑定的服务器 OptimizedEntry 完全接受一个来源:手动 baselineEntry,管理
entryId 可选 entryQuery,或一个 managedEntry 对象为 contentType, (中文(简体) ), slug选项
slugField选择 entryQuery。 。 。 . slugField 默认为 slug。成功的弹道检查
制作并跟踪取入的条目 sys.id无效的源组合
Bound Next.js OptimizedEntry requires exactly one source: baselineEntry, entryId, or managedEntry.
静态、公共和分析表面
使用顶级服务器成员, 不 optimization.request对于可缓存的静态路线,
应用型公共布局, 和只分析路线。 这些成员使用明确的投入,并且
未读 next/headers 或打电话 cookies()。 。 。 .
使用 createPublicPermutationHandoff() 由 App 路由器提供的 app 自主公共布局
缓存组件, Pages 路由器 ISR, CDN 路由, 或 Edge 运行时路由处理器 。 这个
应用程序提供选定的优化和公共布置维度。 提出请求
配置文件必须使用 private-request 缓存范围 .
const handoff = optimization.createPublicPermutationHandoff({
permutationKey: permutation.slug,
cacheVersion: permutation.cacheVersion,
locale: permutation.locale,
entryIds: permutation.entryIds,
selectedOptimizations: permutation.selectedOptimizations,
hydration: 'preserve-server',
initialPageEvent: 'emit',
})
使用顶级 OptimizationAnalyticsRoot 仅用于分析路径。 个人化内容
在服务器上,附加跟踪属性
@contentful/optimization-nextjs/tracking-attributes,然后通过 analytics-only 交给
树根.
手动请求
使用顶级 createRequestHandoff() 只有在高级管弦乐需要明确控制时
请求、页载荷或交接。 把交接权传给顶层根:
import { cookies, headers } from 'next/headers'
import { optimization } from '@/lib/optimization'
const { OptimizationRoot } = optimization
export default async function Page() {
const handoff = await optimization.createRequestHandoff({
cache: { scope: 'private-request' },
hydration: 'preserve-server',
pagePayload: { properties: { route: '/products' } },
request: {
cookies: await cookies(),
headers: new Headers(await headers()),
url: 'https://example.com/products',
},
})
return (
<OptimizationRoot
handoff={handoff}
prefetchManagedEntries={[
{ contentType: 'productPage', slug: 'featured', entryQuery: { locale: 'en-US' } },
]}
routeKey="/products"
buildPagePayload={() => ({ properties: { route: '/products' } })}
>
{/* route content */}
</OptimizationRoot>
)
}
prefetchManagedEntries 在服务器上获取描述符并将其基线合并到
handoff.entries; 弹出将规范描述符嵌入下面 managedEntry 并存储
已获取 sys.id 内 entryId服务器 OptimizedEntry 只获取此渲染, 所以使用 root
当匹配的浏览器管理源必须不另取水合物时,预留.
页面路由器设置
使用 /pages-router 用于客户端根在 _app.tsx 财务报告和审定财务报表 /pages-router/server 页:1
getServerSideProps。服务器帮助器是分开的,因为客户端绑定是一个 "use client"
输入.
import { bindNextjsPagesRouterOptimization } from '@contentful/optimization-nextjs/pages-router'
export const { OptimizationRoot, OptimizationAnalyticsRoot, OptimizedEntry } =
bindNextjsPagesRouterOptimization({
spaceId: 'space-id',
environment: 'master',
consent: {
clientDefaults: { consent: false, persistenceConsent: false },
},
})
import { OptimizationRoot } from '@/lib/optimization'
import type { AppProps } from 'next/app'
import { useRouter } from 'next/router'
export default function App({ Component, pageProps }: AppProps) {
const router = useRouter()
const routeKey = router.asPath || router.pathname
return (
<OptimizationRoot
buildPagePayload={() => ({ properties: { route: routeKey } })}
handoff={pageProps.contentfulOptimization?.handoff}
routeKey={routeKey}
>
<Component {...pageProps} />
</OptimizationRoot>
)
}
import { bindNextjsPagesRouterServerOptimization } from '@contentful/optimization-nextjs/pages-router/server'
import { contentfulClient } from './contentful'
const { createRequestHandoff } = bindNextjsPagesRouterServerOptimization({
spaceId: 'space-id',
contentful: { client: contentfulClient },
environment: 'master',
consent: {
server: { events: true, persistence: true },
},
})
export async function getServerSideProps(context) {
const handoff = await createRequestHandoff(context, {
cache: { scope: 'private-request' },
hydration: 'preserve-server',
pagePayload: { properties: { route: context.resolvedUrl } },
prefetchManagedEntries: [
{ contentType: 'productPage', slug: context.params.slug, entryQuery: { locale: 'en-US' } },
],
})
return { props: { contentfulOptimization: { handoff } } }
}
Pages 路由器服务器预选接受ID或内容类型/slug描述符并附加其基线
到浏览器交接。 绑定客户端 OptimizedEntry 财务报告和审定财务报表 /client useOptimizedEntry 接受
baselineEntry, (中文(简体) ), entryId 可选 entryQuery,或下面的内容类型/slug描述符
managedEntry相匹配的弹道源使用交接基线及其实际 sys.id。 。 。 .
首页决定前的工作
两个客户端都接受 beforeInitialPage 当浏览器身份或自定义操作时
必须在绑定内容根的初始页面决定前完成。 这个决定是根的
选择发送第一个浏览器页面事件或跳过它,因为一个应用的交接器已经拥有了
路径 :
'use client'
import { bindNextjsAppRouterClientOptimization } from '@contentful/optimization-nextjs/app-router/client'
export const clientOptimization = bindNextjsAppRouterClientOptimization({
spaceId: 'space-id',
environment: 'master',
beforeInitialPage: {
run: async ({ identify }) => {
await identify({ userId: visitor.id })
},
onError: reportBeforeInitialPageError,
},
})
export const { RequestOptimizationRoot: ClientRequestOptimizationRoot } = clientOptimization
export function OptimizationApp({ children, routeKey }) {
return (
<clientOptimization.OptimizationRoot
routeKey={routeKey}
buildPagePayload={() => ({ properties: { route: routeKey } })}
>
{children}
</clientOptimization.OptimizationRoot>
)
}
直接 App 客户端 OptimizationRoot 需要这些明确的路径输入。 对于 App 路由器
请求家族,在服务器绑定器中注入初始页面前的客户端请求根
相反:
import 'server-only'
import { bindNextjsAppRouterServerOptimization } from '@contentful/optimization-nextjs/app-router/server'
import { ClientRequestOptimizationRoot } from './optimization-client'
export const optimization = bindNextjsAppRouterServerOptimization(serverConfig, {
request: { OptimizationRoot: ClientRequestOptimizationRoot },
})
export const { OptimizationRoot: RequestOptimizationRoot } = optimization.request
RequestOptimizationRoot 属于 App 客户端在初始页面工作前的结果; 结果
没有这项工作,就保留了现有的成员.
注射时 RequestOptimizationRoot 来源 routeKey 财务报告和审定财务报表 buildPagePayload 从 App 路由器
状态并替换请求家族的默认根。 不带就挂
RequestNextAppAutoPageTracker; 被注入的根拥有直接的初始页面决定, 然后再使用
路由改变。 组件引用跨越服务器构成边界, 但调用
保留在其客户端模块中,不输入服务器配置或飞行数据.
App服务器请求家族可以接受其页面事件,并将所有权放入交接. 这个
浏览器请求 root 应用交接器; 在其自定义的活运行时间存在后, 它引用
beforeInitialPage,标记尝试
路由,然后为以后的路由更改发出消息.
Pages路由器客户端绑定器在其仅限客户端的模块中使用相同的选项:
import { bindNextjsPagesRouterOptimization } from '@contentful/optimization-nextjs/pages-router'
export const optimization = bindNextjsPagesRouterOptimization({
spaceId: 'space-id',
environment: 'master',
beforeInitialPage: {
run: ({ identify }) => identify({ userId: visitor.id }),
},
})
客户端绑定器抓取回调,并仅转发到绑定内容根. 回电
接收器安全 identify, (中文(简体) ), screen,以及 track 方法。 。 。 它没有转交给约束方
OptimizationProvider 或者说 OptimizationAnalyticsRoot,而注入提供者不接受.
对于 Pages 路由器请求,服务器助手可以接受该页面事件并记录其所有权于
交接通过页面道具。 浏览器根应用该交接器后, 它的活的拥有
运行时间存在, 它引用 beforeInitialPage,使一个直接页面尝试或同一程序交接
ưμ㼯a.
这个 NextjsClientOptimizationConfigWithoutBeforeInitialPage 财务报告和审定财务报表
NextjsClientOptimizationConfigWithBeforeInitialPage 分支来源于
NextjsBoundRootConfig,选定分支则确定绑定根的页面道具。 无
beforeInitialPage中,包括
initialPagePayload与 beforeInitialPage,绑定根需要 routeKey 懒惰的
buildPagePayload 和拒绝 initialPagePayload拓宽时键入的变量
NextjsClientOptimizationConfig 使用此更严格的初始页前根合同,直到
配置在绑定前会缩小 .
调用返回的工作完成或监视器过期后, 根会读取最新的路径
以及一个直接页面尝试的有效载荷构建器。 成功应用的同路交接方式
直接决定a skip否则,它试图 emit。尝试到达终端后
结果,现有的页面发送器将生成一个未排放的初始 skip 标记尝试路线,
然后使用其常态 emit 用于后期路由更改的路径。 首页前的根是唯一的
页面所有者在其子树。 直接 App 根,注入 App 请求根,因此Pages 根
不挂载单独的 NextAppAutoPageTracker, (中文(简体) ), RequestNextAppAutoPageTracker,或
NextPagesAutoPageTracker 在这条路上.
何时 maxWaitMs 被省略,默认为3,000毫秒。 它接受积极的有限价值. 0, (中文(简体) ),
负值, NaN, (中文(简体) ), Infinity,以及 -Infinity 同步掷出
TypeError('beforeInitialPage.maxWaitMs must be a positive finite number.') 在供应商之前,
回调、 页面或 onError 运行.
序为最上相. 归还属于 最初的工作。 火灾和遗忘的工作是后来的活动, 监督停止等待 不取消回调代码或飞行中请求。 虽然根仍然被挂起, 是一样的 sive owned runtime is current, callback 失败或监视器过期仍导致直接页面 尝试。 如果根卸载或运行时间被替换,则只替换未发送的本地页面和准备状态 继续被压制.
在直接页面尝试开始后, 路由更改既不取消, 也不启动 竞相尝试。 根会安顿下来,并标出捕捉到的路线,然后允许 页面排放。 仅在飞行中尝试时观察到的航道没有释放;航道变化 准备就绪后正常发射 现有录入期限可先输入回溯内容,而且 默认非活性行为在初始版工作过后保持倒计时冻结 成功 .
保留 beforeInitialPage 在只包含客户的模块中配置 。 App路由器服务器配置继承,以及
用于 Pages 路由器服务器绑定器的 beforeInitialPage?: never 边界。 两个服务器
绑定器拒绝包含此回调的导出客户端配置变量 。 应用请求根
注入会分别通过客户端组件引用;不会削弱该配置边界.
Pages 服务器绑定器既不运行回调,也不串接到传递中
页面道具。 在 App 路由器构成中,回调会保留在其客户端组件模块中,并且确实
不输入服务器组件, 请求配置、 飞行数据、 交接、 缓存状态、 ISR 或边缘
帮手.
边缘运行时间
使用 /edge 用于导出 Edge 运行时路由处理器 runtime = 'edge'。帮助者接受
网络标准 Request, (中文(简体) ), Headers,然后 cookie 抓图,不导入节点 SDK 或其他
仅节点APIs.
import { configureNextjsEdgeOptimization } from '@contentful/optimization-nextjs/edge'
const { createEdgeRequestHandoff } = configureNextjsEdgeOptimization({
spaceId: 'space-id',
environment: 'master',
consent: {
server: { events: true, persistence: true },
clientDefaults: { consent: false, persistenceConsent: false },
},
})
export const runtime = 'edge'
export async function GET(request: Request) {
const { handoff, persist } = await createEdgeRequestHandoff({
cache: { scope: 'private-request' },
hydration: 'preserve-server',
pagePayload: { properties: { route: new URL(request.url).pathname } },
request,
})
const response = new Response(renderHtml({ handoff }), {
headers: { 'content-type': 'text/html; charset=utf-8' },
})
persist(response)
return response
}
公共边际运行时间轮廓使用 createPublicPermutationHandoff() 从配置中 /edge
帮手 将它与 App 路由器缓存组件和页面路由器 ISR 分开; 路由名称或
帮助者名称本身并不能证明 Edge 运行时执行 .
服务器和跟踪助手
@contentful/optimization-nextjs/server 暴露出低级节点公用设施,例如
configureNextjsServerOptimization(), (中文(简体) ), createNextjsRequestHandoff(), (中文(简体) ), ServerOptimizedEntry,以及
getNextjsServerOptimizationData() 用于需要直接节点请求控制的应用程序.
模拟不同内容类型的基线和变体条目,见 条目优化和变量分辨率。 。 。 .
@contentful/optimization-nextjs/tracking-attributes 曝光情况 getServerTrackingAttributes()页:1
Next.js 环绕 React Web/Web 跟踪属性通过. 用它来
服务器/静态/上接的标记,仅由分析器浏览器根来观察.
请求处理器助手
@contentful/optimization-nextjs/request-handler 显示代理服务器和中间软件助手
请求文本转发.
import { createNextjsOptimizationContextHandler } from '@contentful/optimization-nextjs/request-handler'
export const proxy = createNextjsOptimizationContextHandler()
请求- 文本处理器总是转发已静态的请求上下文头 。 打电话没有
选项,它只转发请求上下文。 配置时 sdk 财务报告和审定财务报表 consent,它解决
同意, 一次执行服务器页面请求, 转发压缩 x-ctfl-opt-server-data 上下文为
encodeURIComponent(JSON.stringify({ consent, pageAccepted, profileId })),并坚持
ctfl-opt-aid 编辑 NextResponse 当坚忍被允许的时候。 设定
request.trustedRequestHandoff 改为 true 在 App 路由器服务器上绑定, 因此请求家族使用
已转发 profileId 无一秒 page() 调用和使用 pageAccepted 避免重复
第一页事件。 手动管弦,通过 trustedRequestHandoff: true 到顶层
createRequestHandoff() 换句话说 仅选择此配置的请求处理器覆盖的路径;
原始客户端提供 x-ctfl-opt-server-data 除非路由选择使用,否则会被忽略.
使用 createNextjsPublicPermutationCacheMiddleware() 从
@contentful/optimization-nextjs/cache-middleware 当代理代码需要公开排列时
缓存键重写 。 缓存中间软件可与已有的 NextResponse它保存着
非 SDK 响应和请求覆盖状态,同时去除 Stale SDK 拥有 x-ctfl-opt-* 请求
上下文在重写前.