@decocms/compat-v7

中文文档
8.18.0发布于 2026/11/11TypeScriptES Module零依赖构建来源已验证近 30 天下载 2963

v7 纯助推器( 类型, 设备检测, 内线脚本, clx, 匹配器, 分区加载器跑取器, apps- commerce's 类型和帮助器) 在 @ decocms/ blocks 8 上, V7 输出而无 v7 运行时间; v7 设备上下文和粘着 A/ B cookie 用于 @ decocms/ tast

中文使用文档
文档目录10 节
  1. 类型
  2. 设备检测
  3. 内置脚本
  4. 链接
  5. 匹配者
  6. 区装填器
  7. 商业类型和帮助者
  8. TanStack 开始( @decocms/tanstack (中文(简体) )
  9. A/B与遗产来源分离
  10. 下册.js @decocms/nextjs (中文(简体) )

@ decocms/compat-v7 (英语)

v7 的纯帮助站点移出 @decocms/blocks 7点到8点 每个都给出了v7的输出,字节表示字节,所以一个迁移的站点从这里导入,而不是保存自己的副本. 测试将每个帮助者标注在v7自己的代码上(最新7.x).

这不是一个v7运行时间。 没有 ctx,没有引用,没有请求范围,也没有缓存的加载器:v8没有它们,这个包没有带回它们. 它没有读取环境变量.

端点 : @decocms/blocks (同一个版本). 框架子路径还使用网站绑定: /tanstack 带 @decocms/tanstack 联合国 @tanstack/react-start 财务报告和审定财务报表 react, (中文(简体) ), /nextjs 带 @decocms/nextjs 联合国 next 财务报告和审定财务报表 react) (中文(简体) ). 这些是可选的同伴;一个网站只安装自己的.

类型

import type { ImageWidget, RichText, SectionProps } from "@decocms/compat-v7/types";

export interface Props {
  image: ImageWidget;
  body: RichText;
}

export const loader = async (props: Props, req: Request) => ({ ...props, url: req.url });

export default function Banner(props: SectionProps<typeof loader>) {
  // ...
}
  • SectionProps<typeof loader> 是装载器的返回值,等待。 v7 还被打开a Promise;对于同步加载器,v7给出了加载器自己的类型,在这里给出了值.
  • Resolved<T>, (中文(简体) ), LoadingFallbackProps 财务报告和审定财务报表 Flag 这是v7的.
  • 部件的别名( N)ImageWidget, (中文(简体) ), VideoWidget, (中文(简体) ), HTMLWidget, (中文(简体) ), RichText, (中文(简体) ), TextArea, (中文(简体) ), Color, (中文(简体) ), TextWidget, (中文(简体) ), ButtonWidget, (中文(简体) ), Secret)为弦. deco schema 读取它们的名字,所以一个字段会像在v7上所做的那样获得网站编辑器的部件. Secret 是 v7 的被遮盖的文本框 : 一个在内容中保存的平面字符串, 所以将真实的证书保存在您的部署平台的秘密中, 由网站的代码读取并作为参数通过 . @decocms/compat-v7/types/widgets 只有一个别名.

7号 AppContext 财务报告和审定财务报表 FnContext 不在这里,他们描述 ctx 参数,v8不会通过.

设备检测

import { detectDevice, isMobileUA } from "@decocms/compat-v7/device";

const device = detectDevice(request.headers.get("user-agent") ?? ""); // "mobile" | "tablet" | "desktop"

这些是v7的用户代理模式,在v7的顺序(tablet first)中检查. isMobileUA 电话和平板电脑都是真的.

内置脚本

import { inlineScript, useScript } from "@decocms/compat-v7/script";

<script {...inlineScript(`document.body.dataset.ready = "true"`)} />
<script dangerouslySetInnerHTML={{ __html: useScript(onLoad, "banner-1") }} />

useScript, (中文(简体) ), useScriptAsDataURI 财务报告和审定财务报表 inlineScript 给 v7 输出。 v7 在开发中警告 fn.toString(),因为服务器和客户端构建可以以不同的方式序列化一个函数并打破水分. 警告不见了,因为它读到 NODE_ENV,但建议仍然有效: inlineScript 带一弦.

链接

import { clx } from "@decocms/compat-v7/clx";

clx("btn", isActive && "btn-active", undefined); // "btn btn-active"

它会降低发作值,加入其余部分,并像 v7 那样崩溃白空间运行. 像v7,它不会修剪.

匹配者

import { type DeviceProps, device, type RandomProps, random } from "@decocms/compat-v7/matchers";

export const blocks = {
  "website/matchers/device.ts": (props: DeviceProps) => device(props, matcherContext()),
  "website/matchers/random.ts": (props: RandomProps) => random(props, matcherContext()),
};

device, (中文(简体) ), cookie, (中文(简体) ), host, (中文(简体) ), pathname, (中文(简体) ), queryString, (中文(简体) ), location, (中文(简体) ), multi 财务报告和审定财务报表 random 给v7的结果。 v8 块函数只获得其输入, 因此每个匹配者将请求作为其第二个参数: a Request,或 { request, url, flags }时 url 当请求是客户端导航服务器功能调用时, 是页面的 URL,以及 flags 对 A/B 决定,每个请求一个阵列. matcherContext() 然而,该站点符合所要满足的要求;框架的子路径提供了这种要求. always, (中文(简体) ), never 财务报告和审定财务报表 date 是v8内置,所以他们不在这里;v8's date 命名已保存块的运动 campaigns,并移动每个 v7 日期窗口.

  • random 是 v7 的粘度随机( 上 7. x) : deco_segment cookie),当流量变化时再次被绘制出. 饼干是按键测试的 组名, 已保存的匹配者块名一个v8区块不知道自己的名字 所以这个区块把它带进 cohort; 随机规则内置使用 website/matchers/random.ts和v7一样 改变流量份额时保持组别:重新命名让每个访客都参加新的测试. v7 – v8 迁移不注册: 它报告每个随机匹配者, 将移动到保存的块中 experiments (类型) split-traffic)在同名下,所以访客保留他们的团体,装订者拥有 deco_segment。不要运行两者在一个网站: 饼干的两位作者 撤销彼此的决定.
  • 页面解决后, segmentSetCookie(request, flags) 给 Set-Cookie 发送,或 null 当访客的饼干 已经说了同样的话. decideRandom 返回一个决定与饼干。 不要缓存一个回应 设置给其他访客.
  • multi 获得规则的结果:v8先解决. 内在 random v7在每一个请求中都重新画出来.
  • environment 抛出:它读取没有 v8 软件包的流程环境。 登记自己的配对者的名字.
  • location 读取 cf-* 头,然后工人 request.cf,然后是 __cf_geo_* 饼干,像v7一样.

区装填器

import { compose, runSectionLoaders, withDevice, withSearchParam } from "@decocms/compat-v7/sections";

const loaders = {
  "site/sections/Product/ProductShelf.tsx": withDevice(),
  "site/sections/Header/Header.tsx": compose(withDevice(), withSearchParam()),
  "site/sections/Category/Banner.tsx": async (props, req) => ({ ...props, url: req.url }),
};

// After the page's sections resolved, once per page, globals included:
const { sections, degraded } = await runSectionLoaders(page.sections, { loaders, request, url: pageUrl });

runSectionLoaders 运行 v7's (props, req) 区域加载器 :

  • 每个区段运行它的装载器,然后道具中的区段运行,无论它们在哪里(最晚为7.x). 其v7基线为7.77.12或更早通过的地点 nested: "direct":这些释放只运行直接以道具或列表道具保存的部分.
  • 一个装填器得到道具 __pageUrl 财务报告和审定财务报表 __pagePath 添加(在道具中已经获得数值)和 a GET 请求页 : url 当请求是客户端导航的服务器功能呼叫时, 否则 request.url,用请求的页眉.
  • 投出道具的加载器是保存的道具. 该节列于 degraded 除非是在 nonCritical (v7级) registerNonCriticalSections; 将 v7 的布局区段也放在那里, 因为 v7 从未标记它们退化). v7 已发送 X-Deco-Degraded 当列表不是空的,所以页面没有被边缘标记.
  • runSectionLoader 某一节(推迟部分)也是如此.

v7 的缓存( layout 区段, 可缓存区段) 及其注册不在此: 加载器是一个参数 。 v7的第三个论点, ctx不见了 一个读取它的加载器扔出一个错误,说出该使用什么来取而代之,而其部分保留了被保存的道具.

withDevice, (中文(简体) ), withMobile, (中文(简体) ), withSearchParam, (中文(简体) ), compose 财务报告和审定财务报表 withSectionLoader 是v7的混音器,有v7的输出. withSectionLoader 保留 v7 的捕获量:一个会扔回道具的区段模块装载器,而区段没有退化.

v8节为 { component, props }. v7 的解析器将嵌入部分写成 { Component, props };这里的嵌入区段形状与页面区段相同,并保留它拥有的任何其他密钥.

商业类型和帮助者

import type { Product } from "@decocms/compat-v7/commerce/types";
import { formatPrice } from "@decocms/compat-v7/commerce/sdk/formatPrice";
import { useOffer } from "@decocms/compat-v7/commerce/sdk/useOffer";
import { relative } from "@decocms/compat-v7/commerce/sdk/url";
import { mapProductToAnalyticsItem } from "@decocms/compat-v7/commerce/utils/productToAnalyticsItem";

7号 @decocms/apps-commerce下页 /commerce 使用自己的子路径布局: 替换 @decocms/apps-commerce/ 与 @decocms/compat-v7/commerce/ 在导入中,没有其他变化.

  • /commerce/types (和 /commerce: schema.org 商业类型(Product, (中文(简体) ), Offer, (中文(简体) ), AggregateOffer, (中文(简体) ), BreadcrumbList, (中文(简体) ), ProductListingPage,分析事件,... ),与车型的再出口. /commerce/types/cart 单凭手推车类型和区段预设.
  • /commerce/sdk/*数字 : formatPrice编号 :formatPriceRange, (中文(简体) ), relative, (中文(简体) ), useOffer编号 :bestInstallment, (中文(简体) ), useVariantPossibilities和分析绘图器analytics) (中文(简体) ).
  • /commerce/utils/*数字 : canonicalFromBreadcrumblist, (中文(简体) ), DEFAULT_IMAGE, (中文(简体) ), parseRange编号 :formatRange, (中文(简体) ), mapProductToAnalyticsItem,以及 getStateFromZip (默认导出 stateByZip) (中文(简体) ).

每个文件都是v7's,格式化一旁,测试运行v7's文件旁边. 无使用反应( N)useOffer 财务报告和审定财务报表 useVariantPossibilities 是普通函数,尽管名称不同)。 v7 的应用程序运行时间( e)app-types, (中文(简体) ), manifest-utils, (中文(简体) ), registry, (中文(简体) ), resolve) 这里没有: v8 配置有参数的客户端.

TanStack 开始(@decocms/tanstack(中文(简体) )

// the block map
import { random, type RandomProps } from "@decocms/compat-v7/matchers";
import { matcherContext } from "@decocms/compat-v7/tanstack/server";

"website/matchers/random.ts": (props: RandomProps) => random(props, matcherContext()),

// the page's server function (it gets the page's href)
const page = await openPage(data.href);  // resolves the page, so the matchers run
commitSegmentCookie();                   // deco_segment, as v7's page route set it
return { ...page, device: requestDevice() };

// the page component
import { DeviceProvider } from "@decocms/compat-v7/tanstack";
<DeviceProvider value={page.device}>{sections}</DeviceProvider>

// src/worker-entry.ts: the segment of the site's own page cache
const segment = (request: Request) => ({ device: …, ...cohortSegment(request) });
  • matcherContext(pageUrl?) 给每个匹配者所服务的请求( TanStack Start ) getRequest(),页面的 URL 和一个 flags 每个请求的阵列。 在客户端导航上,请求是服务器功能呼叫,因此通过该页面的URL,因为v7匹配正在导航的页面;没有它,该呼叫会丢出.
  • commitSegmentCookie() 套装 deco_segment 将客人们的饼干合并: deco_segment=<value>; Max-Age=31536000; Path=/; SameSite=Lax,v7的字节. 当饼干已经说一样的话时,就没什么了. 在页面解析后在服务器函数中调用它 。 一个网站的页面缓存从不存储设置它的响应,因为v7的工人没有: 保留 deco_segment 从饼干中取出它的缓存条和商店(工人进入处方) @decocms/tanstackREADME 存储的响应中,没有设置 cookie 以外的响应 SAFE_COOKIES) (中文(简体) ).
  • cohortSegment(request) 是 v7 边缘缓存的 A/B 拆分({ abf: <token> } 在一个考验中, {} 因此,每个组保留自己的缓存页面,其他人共享一个.
  • requestDevice() 为 v7's detectDevice 关于请求的用户代理:默认情况下工人-输入食谱的缓存密钥用途。 与页面一起返回,所以浏览器的水合值是相同的. useDevice() 读取提供者;没有读取浏览器的用户代理("desktop" 和v7一样.

A/B与遗产来源分离

7号 withABTesting (由 KV 驱动在 TanStack 站点与其取代站点之间的分割) 是 abTestingRoutes,为 createDecoWorker是因为 routes数字 :

// src/worker-entry.ts
import { abTestingRoutes } from "@decocms/compat-v7/tanstack/worker";

const abTesting = abTestingRoutes({
  worker: () => worker,
  kvBinding: "SITES_KV",
  shouldBypassAB: (_request, url) => isCommercePath(url.pathname),
});

const worker = createDecoWorker({
  // …
  routes: async (request, env, ctx) => (await abTesting(request, env, ctx)) ?? siteRoutes(request),
});
export default worker;
  • 相同的 KV 条目( E){ workerName, fallbackOrigin, abTest: { ratio } } 在请求的主机名下,同一桶(?_deco_bucket= 覆盖,然后是 _deco_bucket=<bucket>:<ratio %> 在目前比例下设定了饼干,然后是客户IP的散列,同样的饼干和 x-deco-bucket 头,断路器, shouldBypassAB, (中文(简体) ), preHandler 和倒置代理(主机名在 Set-Cookie, (中文(简体) ), Location 和2xx文本机构,流出)。 测试运行 v7 的文件旁边.
  • v7包了整个工人。 操作器运行在工人运行的地方 routes:在CMS重定向后, /deco/_liveness 和缓存清洗。 对于"工人"的桶 它叫工人回来(worker)),因此页面得到桶饼干,一个工人出错会回落到遗留来源,如v7中;内调会跳过处理器并去站点的其他路线和边缘缓存,这已经让 _deco_bucket 通过缓存页面.
  • 留下的遗迹的回音 就像工人一样 routes 回应 : CDN-Cache-Control: no-store 当它没有设置, 工地的安全头 当它没有设置 preload 提示( 它们为新站点命名 ; v7 发送了 无) 。 "工人"桶的一页载着他们一次,从制造它的内部呼叫.

下册.js@decocms/nextjs(中文(简体) )

// proxy.ts: forward the visitor's URL (with the draft headers, if any)
import { pageUrlRequestHeaders } from "@decocms/compat-v7/nextjs/proxy";
const headers = pageUrlRequestHeaders(request, draftRequestHeaders(request, decision));
return applyDraft(NextResponse.next({ request: { headers } }), decision);

// the block map
import { matcherContext } from "@decocms/compat-v7/nextjs/server";
"website/matchers/random.ts": async (props: RandomProps) => random(props, await matcherContext()),

// the page (a server component)
import { SegmentCookie } from "@decocms/compat-v7/nextjs/server";
const sections = await resolvePage(...);  // the matchers run here
return <>{sections}<SegmentCookie nonce={nonce} /></>;

// app/layout.tsx
import { DeviceProvider } from "@decocms/compat-v7/nextjs";
<DeviceProvider value={await requestDevice()}>{children}</DeviceProvider>
  • 一个服务器组件看到请求的页眉,但不看到其URL,代理机可能会重写一个页面所绘制的路径. 代理转发访问者要求的 URL x-deco-page-url (取出任何外部副本),以及 matcherContext() 匹配; 通过 URL 到 matcherContext(url) 而不是当页面知道它.
  • 这些决定是按React的要求作出的 cache。 。 。 .
  • 服务器组件不能设置饼干,代理在页面决定前运行. 这么说吧 SegmentCookie 制作一行脚本,设置同样的 cookie v7 的 TanStack 路由发送(deco_segment=<value>; Max-Age=31536000; Path=/; SameSite=Lax)),或者当访客的饼干已经说了同样的话就什么都没有了. 在客户端导航 React 使页面本身不运行脚本之后,它不会生成脚本,所以一个效果就设置了相同的饼干. 内容解决后再渲染. 阅读请求的一页是动态的,所以Next永远不要在访客之间分享;让一个CDN在前面也不要缓存. v7's Next.js 捆绑从未写过这个饼干: 在那里,随机再次从每个请求中抽取.

设备上下文是两个框架相同的模块: DeviceContext。 。 。 .

包根导出类型,设备,脚本和 Clx 帮助. 选手,选手, /commerce/* 而框架的子路径 只在自己的子路径.

版本与发布记录

@decocms/compat-v7 共发布 21 个版本,首次发布于 2026/10/15;过去 12 个月发布了 21 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
8.18.0latest2026/11/11今天
8.17.02026/11/111 天前
8.16.12026/11/111 天前
8.16.02026/11/111 天前
8.15.02026/11/101 天前
8.14.02026/11/101 天前

关于 @decocms/compat-v7 的常见问题

@decocms/compat-v7 是什么?

v7 纯助推器( 类型, 设备检测, 内线脚本, clx, 匹配器, 分区加载器跑取器, apps- commerce's 类型和帮助器) 在 @ decocms/ blocks 8 上, V7 输出而无 v7 运行时间; v7 设备上下文和粘着 A/ B cookie 用于 @ decocms/ tast

如何安装 @decocms/compat-v7?

在项目目录运行 npm install @decocms/compat-v7,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@decocms/blocks(^8.4.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@decocms/compat-v7 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@decocms/compat-v7 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@decocms/compat-v7 可以商用吗?

@decocms/compat-v7 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@decocms/compat-v7 的下载量有多少?

根据 npm 官方下载统计,@decocms/compat-v7 在 2026/10/12 – 2026/11/10 这 30 天内被下载 2,963 次,日均约 99 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@decocms/compat-v7 还在维护吗?

最新版本 8.18.0 发布于 2026/11/11(今天);至今共发布 21 个版本,其中过去 12 个月发布了 21 个;首次发布于 2026/10/15。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。