@decocms/nextjs

中文文档
8.18.0发布于 2026/11/11TypeScriptESM + CJS零依赖构建来源已验证近 30 天下载 1.3万

Deco CMS for any Next.js App Router app: 代理服务器和页面中的预览草稿,预览徽章, Studio Bridge, 有Deco () 和一个下一张/图像加载器

中文使用文档
文档目录9 节
  1. 草稿
  2. 访客、任务和客户
  3. 任务路线
  4. 草稿主机
  5. 版式
  6. 名称和工作室的起源
  7. 下一个。配置
  8. 请求参数
  9. 图像

@ decocms/ nextjs (英语)

Deco CMS 用于任何 下一个.js App路由器应用程序. 它不设定托管假设:没有构建CDN,ISR或平台行为. 这是一组小的帮助者 您的网站呼叫 从自己的代理,布局,页面和 next.config。 。 。 .

端点 : @decocms/blocks (同一个版本), next 16岁, react 19;可选 @opentelemetry/api (见 请求参数) (中文(简体) ).

导入它是为了什么
@decocms/nextjs/proxy请求的内容,一旦决定 proxy.ts数字 : decideDraft, (中文(简体) ), draftRequestHeaders, (中文(简体) ), rewriteToDraftRoute, (中文(简体) ), applyDraft, (中文(简体) ), isDraftRoutePath, (中文(简体) ), decideVisitor, (中文(简体) ), visitorRequestHeaders, (中文(简体) ), applyVisitor, (中文(简体) ), decideAssignments, (中文(简体) ), assignmentsRequestHeaders,或 draftProxy 用于没有自己代理的网站; assignmentsKey 用于一个站点的缓存密钥; rewriteToAssignmentsRoute, (中文(简体) ), isAssignmentsRoutePath, (中文(简体) ), assignmentsRoutePath 财务报告和审定财务报表 assignmentsSegment 给 Next 自己的缓存。 没有反应和块图.
@decocms/nextjs/server在 Server 组件中, 代理决定的内容 : bindDraft, (中文(简体) ), activeDraftPointer, (中文(简体) ), contentClient· ; assignedClient 用于任务路径上的一页.
@decocms/nextjsDraftPreviewIndicator (页面草稿上的"审查模式"徽章), StudioBridge (lets Studio的网站编辑器驱动页面)和 StudioPage (在屏幕上显示是哪一页),加上名字草稿和工作室的出处(下).
@decocms/nextjs/configwithDeco(nextConfig):草案头规则和工作室的dev起源. 常见JS,所以 next.config.js 能够 require() 这个.
@decocms/nextjs/instrumentationregister,则 instrumentation.ts 钩子记录 http.server.request.duration 从Next自己的请求跨度,和 serverRequestSpanProcessor() 用于拥有自己的OpenTeleometry SDK的站点.
@decocms/nextjs/image-loadercreateDecoImageLoader(imageUrl): 下一个/图像加载器超过一个 ImageUrl 从 @decocms/blocks/image。 。 。 .

createCMS 读取 NODE_ENV 决定 dev 模式,所以 next dev 永远不要将主机的发布替换为本地内容; 不需要通过 . createCMS({ dev }) 当一个网站需要时,它仍然可以覆盖.

草稿

// src/cms.config.ts: the options both CMS handles share (with `site`, hosted releases and
// the preview hosts Studio writes into them)
export const cmsConfig = { content, site: "my-store" };

// src/cms.ts and src/cms.proxy.ts
export const cms = createCMS({ blocks, ...cmsConfig });
export const proxyCms = createCMS({ blocks: {}, ...cmsConfig }); // no block map in the proxy

// src/proxy.ts
export async function proxy(request: NextRequest) {
  if (isDraftRoutePath(request.nextUrl.pathname)) return new NextResponse(null, { status: 404 });
  const draft = await decideDraft(proxyCms, request);
  const visitor = decideVisitor(request, draft);
  const assignments = await decideAssignments(proxyCms, draft, visitor);
  const headers = assignmentsRequestHeaders(
    visitorRequestHeaders(draftRequestHeaders(request, draft), visitor),
    assignments,
  );
  const response =
    rewriteToDraftRoute(request, draft, visitor, assignments) ??
    NextResponse.next({ request: { headers } });
  return applyVisitor(applyDraft(response, draft), visitor);
}

// src/app/%5Fdraft/[[...path]]/page.tsx: the dynamic draft route (a literal `_draft` folder never routes)
export const dynamic = "force-dynamic";
export default async function DraftPage({ params, searchParams }) {
  await bindDraft(cms, { searchParams: await searchParams });
  const client = contentClient(cms);
  // … resolve and render the page as on the published route …
  return <>{page}<DraftPreviewIndicator /></>;
}

已出版的页面保留缓存( ISR, 下面): 代理只向草稿路由发送预览请求( 任何) ?__draft=, (中文(简体) ), off 包含,或 cookie 草稿; 永远不指定任务路由),设置 cookie 草稿, 转发已接受的版本 x-deco-version (删除从外部发送的任何副本),并准确标明答复 Cache-Control: max-age=0, no-cache, must-revalidate, (中文(简体) ), Vary: Cookie 财务报告和审定财务报表 X-Robots-Tag: noindex, nofollow一份要求检查草稿,以核实最近一次发布(cms.checkRelease())并转发支票的id x-deco-release-check (删除外部发送的任何副本): 代理主机检查并阅读草稿, bindDraft'主机检查和页面' contentClient 全部等待这个检查, 因此一个预览请求会获取 latest.json 一次(在另一个过程中的一页,而不是代理进行自己的检查)。 它在转发之前会读到一个链接的草稿: 无法读取的草稿会让发行, 过期的饼干,并告诉上面的页 x-deco-draft-unavailable这样 DraftPreviewIndicator 显示平静的通知而不是错误页。 阅读内容的布局随其路线而去,所以被缓存的页面读取不请求: 在草稿路由下(app/%5Fdraft/layout.tsx它召唤 bindDraft(cms) 财务报告和审定财务报表 contentClient(cms),它读取转发头;在任务路线下(app/%5Fassignments/[assignments]/layout.tsx它读过 await assignedClient(cms, (await params).assignments)。 。 。 . bindDraft 读取 headers(),而一个读取请求头的缓存页面则在每一份请求上生成,因此从不在根版式或任务路线上调用它.

草稿链接可以携带已公布的发行承诺SHA来代替草稿(Studio's "Preview this version"),任何一种都可以携带一个预览时间(S__at测试和运动开启或关闭(__test, (中文(简体) ), __campaign页:1 cms.readVersion 读作客户端的 date, (中文(简体) ), experiments 财务报告和审定财务报表 campaigns. 全部通过同一主机检查,并在路由草稿上制作:现场的访客从不选择一个版本. 预览会以 0 的速度切换测试 .

访客、任务和客户

代理决定每个请求一次. decideVisitor(request, draft) 阅读访客 readVisitor 从 @decocms/blocks/experiments (单位:千美元) deco_segment 饼干或新访客; applyVisitor 它的饼干只是第一次访问 从来没有从预览. decideAssignments(proxyCms, draft, visitor) 然后决定每次测试和运动: cms.client({ visitor, version, date, experiments, campaigns }) 与访客和 Studio 链接的版本, 瞬间和切换测试和运动 experiments 财务报告和审定财务报表 campaigns 块. visitorRequestHeaders 财务报告和审定财务报表 assignmentsRequestHeaders 转发到 x-deco-visitor 财务报告和审定财务报表 x-deco-assignments (单位:千美元)draftRequestHeaders 总是从外部取出副本).

在页面上, bindDraft 绑定版本和代理转发的内容(在当前发布时,它绑定访问者和任务,只有在发布时保存一个) experiments 或者说 campaigns 块,且测试为0 %,无论信头上怎么说,均不进行) contentClient(cms) 正在建设 cms.client({ version, experiments, campaigns }) 从他们那里:页面不再决定什么。 页面信任这些标题:在代理后,他们持有它所决定的东西,以及一个没有它就能达到页面的要求(a) matcher 或一个没有代理的网站) 被读取相同的方式,随什么 x-deco-version 财务报告和审定财务报表 x-deco-assignments 它会随身而来 哪些路线通过代理, 和如何保护其他人, 是网站的呼声。 缓存页面不读取请求: CMS 的页面渲染到 任务路径,随着测试和运动 代理决定的道路.

绑定的缓存什么也没有。 在 Next 前面缓存页面的站点( CDN 键入请求头) 在请求的任务上按键, 绝不在访客上 : assignmentsKey(assignments) 从 @decocms/nextjs/proxy,与什么 decideAssignments 提供,是版本,测试和运动运行("" 当没有的时候。 每个测试的同一侧的访客共享一个条目,一次运动开始或结束都会改变关键. 让Next自己去缓存看看 任务路径。 。 。 .

任务路线

代理决定, 页面使这一点。 下一页按其路径缓存( ISR) , 因此代理将其决定放入路径: 它将每个 CMS 页面重写为 /_assignments/<assignments>/<path>,该页面则精确地进行分区名称的测试和活动。 然后,每条路径和一组任务都保留一个条目,并提供给每个访问者使用;页面没有读取请求,所以Next可以缓存. CMS的网页为ISR revalidate = 600 (10分钟):下一个服务一个被存储了10分钟的页面;之后的第一个请求仍然得到所存储的复制,而下一个则在之后的请求的背景中再次使页面恢复. 因此,一个公布的更改会在10分钟内显示在人们打开的一页上,一个没有人打开更长的一页再次显示它的旧副本. 这一拖延(例如晚间换起旗帜)被接受。 从不 force-static 在 Next.js 上: 永不过期的一页会保留它先完成的.

// src/proxy.ts
import { isAssignmentsRoutePath, isDraftRoutePath, rewriteToAssignmentsRoute /* … */ } from "@decocms/nextjs/proxy";

export async function proxy(request: NextRequest) {
  const { pathname } = request.nextUrl;
  if (isDraftRoutePath(pathname) || isAssignmentsRoutePath(pathname)) return new NextResponse(null, { status: 404 });
  const draft = await decideDraft(proxyCms, request, preview);
  const visitor = decideVisitor(request, draft);
  const assigned = isCmsPage(pathname) ? await rewriteToAssignmentsRoute(proxyCms, request, draft, visitor) : null;
  if (assigned) return applyVisitor(applyDraft(assigned, draft), visitor);
  const assignments = await decideAssignments(proxyCms, draft, visitor);
  const headers = assignmentsRequestHeaders(visitorRequestHeaders(draftRequestHeaders(request, draft), visitor), assignments);
  const response = rewriteToDraftRoute(request, draft, visitor, assignments) ?? NextResponse.next({ request: { headers } });
  return applyVisitor(applyDraft(response, draft), visitor);
}

// Next's own files never go through the proxy: rewritten, every script and style would be a 404.
export const config = { matcher: ["/((?!_next/|favicon.ico).*)"] };
// src/app/%5Fassignments/[assignments]/[[...path]]/page.tsx: every CMS page (a literal `_assignments` folder never routes)
import { assignedClient } from "@decocms/nextjs/server";

export const revalidate = 600; // 10 minutes; never force-static
export async function generateStaticParams() {
  return []; // no path at build time: each renders on its first request, then is cached
}
export default async function Page({ params }) {
  const { assignments, path } = await params;
  const client = await assignedClient(cms, assignments);
  if (!client) notFound();
  // … match the path and resolve the page through `client`, as on any page …
}
  • 部分内容: 保存的每个测试 experiments 阻止或关闭访客 和所有被拯救的运动 campaigns 块运行或现在不运行( n)readAssignments ),作为 assignmentsSegment 写道: - 没有,否则是base64url,每组任务1个拼写. 每一次测试的同一面访问者都会得到相同的路径;访问者的ID从来没有在其中,被重写的请求既没有带访问者,也没有带草稿头. 一场运动的开始或结束使每个访客都走上了新的道路.
  • 页面使路径名称数字 : await assignedClient(cms, segment) 正在建设 cms.client({ experiments, campaigns }) 每一个测试和运动都以片段的名称命名,没有访客,一个客户事先完全决定了,所以这个侧面的每个访客都做同一页. 该页面从不检查竞选日期或卷起测试本身. 现在的测试 以0% 保持关闭任何片段名称。 下一页在后面( 重新验证) 显示相同的测试和运动 .
  • 路由信任其代理撰写的路由: 代理回复直接点击 /_assignments/… 和404一样 /_draft/…,因此在代理机后面,只有它自己的重写才能到达路由. 以其他方式到达页面的请求( 代理) matcher 或一个没有代理的站点)使测试和运动其路径名称: assignedClient 只保留测试的0%, 测试或活动的内容没有, 返回 null (a 404) 对于一个段,代理从来不写。 哪些路线通过代理, 和如何保护其他人, 是网站的呼声。 离开而不是回答 404 个事项, 因为下一个缓存在路径下也有一个 404 个: 代理服务器看到新发布的内容仍然在生成之前所写的路径 .
  • URL 请求保持隐私: 当内容保存测试或运动时, 重写标记响应 Cache-Control: private, no-cache。下一个是每个路径和任务集保存一个缓存页面,但 /shoes 所以在前面的CDN 绝不能保留Next的ISR s-maxage 硂.
  • 缓存页面不读取请求数字 : headers(), (中文(简体) ), cookies() 或者说 searchParams 路线中的任意位置( 包括其布局, 因此没有) bindDraft (在那里)让Next在每次请求时,而不是缓存它,以及一个客户部分呼叫 useSearchParams() 使客户端达到最近的 <Suspense>。 。 。 . force-static 用于通过将页面空值交接来隐藏两者;随着ISR,页面会像任务一样从路径中取出它所需要的.
  • 这里永远不会重写草稿和预览: 起草的请求会转到动态草稿路由, 因此没有预览在 Next 的缓存中登陆 .
  • 路径:只有CMS的页面(isCmsPage 上面是网站自己的: 应用程序自己的路线,例如 /blog 这里,像以前一样渲染. draftProxy(proxyCms, { assignments: (request) => isCmsPage(request.nextUrl.pathname) }) 对于一个没有自己代理的网站来说也是如此.

examples/nextjs-binding-smoke 在寄存器中运行它:在测试的对面有两个访客获得不同的路径,两个在同一侧得到一个缓存条目(x-nextjs-cache: HIT),路线为600秒ISR并打出一个键 /_assignments/… 路径为 404 .

草稿主机

链接草案( A)?__draft=在 CMS 允许的主机上进行预览,其中 cms.readVersion 检查: 地址 Studio 写入当前发行的元数据 (previewHosts 内 latest.json,读取 createCMS是因为 site),加 (中文(简体) ) createCMS({ preview: { hosts } })。网站没有列出其他内容。 没有列表, 每个主机都会预览: 没有的网站 latest.json 尚未在CDN上发布,或者在 Studio 撰稿前发布 previewHosts (它下一次出版时会写列表),内容没有 site 除非 preview.hosts 列出主机( 如 ["localhost"]) (中文(简体) ). 若为 latest.json 无法读取( 网络错误, 5xx, 错误的文件) , 预览会保持关闭 preview.hosts,直到读取成功。 接待者是来访者要求访问者x-forwarded-host,则 host); 代理和 bindDraft 问同一个CMS。 在可能不预览的主机上,该页面会使发布; ?__draft=off 仍然结束任何预览 .

版式

import { StudioBridge } from "@decocms/nextjs";

<body>
  {children}
  <StudioBridge site="my-store" />
</body>

工作室的起源是包自有的,因此桥只取站名. v7's "." 默认情况下,编辑快捷键已启动(editShortcut={false} 关了它,和 nonce 是可选的。 桥只为v8:v7被设定的处理器(scrollToComponent, (中文(简体) ), editor::rerender)已消失,所以页面上没有任何脚本可以比较窗口和 top 或者说 parent,并重写 HTML 中“帧-bushing”代码的测试跑取器,其代理(Cypress's) modifyObstructiveCode)服务于字节的页面字节.

该桥还将 Studio 频道挂在每一页上,制作内容包括: 一个小的内线脚本(约0.7 kB gziped),工作室通过它将自己的编辑码(一保存后的部分线框,页面互换)加载到页面上. 这是工作室在页面中运行代码的唯一方式:桥面评价没有脚本工作室发送. 该页面信任一份确切的工作室起源列表: studioOrigins 当给与, 否则 DECO_STUDIO_ORIGIN 环境变量,逗号分隔(本地工作室,例如 http://localhost:3000)),其他工作室的出品和出品起源(出品人DEFAULT_STUDIO_ORIGINS) (中文(简体) ). 框架, 页面帖 { type: "deco:ready" } 每一个都作为目标来源(只有其中之一的家长收到),并且只有在工作室的回答时,才会导入一个模块, { type: "deco:load", url },来自其中之一,并在该消息的来由上命名一个URL;不是由任何其他来源设定,也不是由其他来源设定,它什么都不做。 有内容安全政策的网站通过 withStudioCsp(directives),将同一列表添加到 script-src (和a) frame-ancestors 与工作室, 当政策没有: headers: [{ source: "/:path*", headers: [{ key: "Content-Security-Policy", value: withStudioCsp("script-src 'self' 'unsafe-inline'; object-src 'none'").join("; ") }] }],或网站代理中相同. 内线剧本取自网站 nonce。信件和模块类型在 @decocms/blocks/protocol。 。 。 .

在不位于 Studio 帧的一页上,"""(或 Ctrl+Shift+E)打开了 Studio 编辑器的一页,而 Ctrl 或 Cmd+" 在一个新的分页上打开; Studio 请一个没有签名的访客先签名. 要打开正确的一页,每个CMS页面告诉桥其路径模板:根布局会停留在通航之间,因此该页面使标记在它所解决的部分旁边:

import { StudioPage } from "@decocms/nextjs";

const match = matchRoute(pathname, { routes: pages });
// …
return <>{sections}<StudioPage pathTemplate={match.entry.path} /></>;

它使一个 <meta> 反应位置在 <head>,所以页面本身的标记不变. 没有它,工作室从URL中选择页面.

名称和工作室的起源

对于一个在自己的代码中需要它们的网站(一条设置自己标题的路线,即它自己写的CSP), @decocms/nextjs 导出代理、页面和 withDeco 使用: DRAFT_PARAM (单位:千美元)__draft, (中文(简体) ), DRAFT_COOKIE (单位:千美元)__deco_draft, (中文(简体) ), VERSION_HEADER (单位:千美元)x-deco-version, (中文(简体) ), VISITOR_HEADER (单位:千美元)x-deco-visitor, (中文(简体) ), ASSIGNMENTS_HEADER (单位:千美元)x-deco-assignments, (中文(简体) ), draftResponseHeaders(version), (中文(简体) ), STUDIO_ORIGINS, (中文(简体) ), STUDIO_FRAME_ANCESTORS, (中文(简体) ), isStudioOrigin(origin), (中文(简体) ), DEFAULT_STUDIO_ORIGINS, (中文(简体) ), studioOrigins(option?) 财务报告和审定财务报表 withStudioCsp(directives, options?)。它们具有与 @decocms/tanstack's;每个装订都保存自己的副本,从不进口对方.

下一个。配置

const { withDeco } = require("@decocms/nextjs/config");
module.exports = withDeco({ images: { loader: "custom", loaderFile: "./src/image-loader.ts" } });

withDeco 将 v7 的两条草案头规则放在您自己的前面( a) ?__draft= 查询,或 cookie 草稿: max-age=0, no-cache, must-revalidate, (中文(简体) ), Vary: Cookie, noindex)并添加 Studio的出处到 allowedDevOrigins。每个都可以关闭: withDeco(config, { draftHeaders: false, studioOrigins: false })下一组 Cache-Control 财务报告和审定财务报表 Vary 本身在动态页面上,所以仅 X-Robots-Tag 一定能从这些规则中到达 applyDraft 将所有三个放在它的反应上.

请求参数

// src/instrumentation.ts (or instrumentation.ts at the root, next to app/)
export { register } from "@decocms/nextjs/instrumentation";

下一步,j 已经衡量它所服务的每一项请求:每个请求一个根本跨度(BaseServer.handleRequest),以状态,方法和路由模板结束. register 给 下一个是追踪器提供商,其唯一工作就是这个范围:当它结束时,请求会转到CMS的遥测仪上作为 http.server.request.duration (通过) recordServerRequest 从 @decocms/blocks/metrics) (秒,与上游客户相同的桶" http.client.request.duration在其它东西旁边 createCMS 发送。 没有间距被导出到任何地方, 下一个间距要求的每一个间距都是共享的非记录间距 。 没有遥测目的地( 无) token 没有 endpoint无所记录.

标签数值
http.route下一个路由模板 : /[[...path]], (中文(简体) ), /blog, (中文(简体) ), /_draft/[[...path]]。一个RSC请求在其页面路径下计数. unmatched 当下一个名称无时( 边缘路由) next start(中文(简体) )
http.request.methodGET, (中文(简体) ), POST,...; 任何其他为 _OTHER
status_class2xx . 5xx; 发出的请求是 5xx
cacheDRAFT 草稿(代理人转交) x-deco-version,或请求被重写到 /_draft),否则 BYPASS:下一个决定自己的缓存(x-nextjs-cache在答复中,跨度从未看到
  • @opentelemetry/api 是可选的对等点 : register 使用相同的副本 Next does (您安装时的, 否则 Next 的已编译) , 如果两者都未加载, 则什么都不做 .
  • 您自己的 OpenTelection 设置 (单位:千美元)@vercel/otel, (中文(简体) ), NodeSDK:只有一个跟踪提供者可以注册,所以 register 别管你的了 记下如何结合他们 在您的处理器中添加 : registerOTel({ serviceName, spanProcessors: ["auto", serverRequestSpanProcessor()] })。 。 。 .
  • 代理服务器: 在 next start 接下来通过自己请求的跨度运行代理;该跨度不计算,代理手接的请求就是. 代理自制的响应( 重定向, 404 为直接 /_draft (按下)从不到达一页,也不计算.
  • 边缘运行时间数字 : register 什么都没有做。 下 next start 边缘路由仍由服务它的Node.js服务器测量(unmatched,没有模板);在一个独自运行 Edge 函数的宿主上,没有什么可以衡量它们.

图像

// src/image-loader.ts
import { vtexCatalogWebp, vtexFileManager } from "@decocms/apps-vtex/image"; // your platform's helpers, if any
import { createImageUrl, decoCdn } from "@decocms/blocks/image";
import { createDecoImageLoader, nextImageOptimizer } from "@decocms/nextjs/image-loader";

const imageUrl = createImageUrl({
  providers: [
    vtexCatalogWebp(),
    vtexFileManager({ via: "query" }),
    decoCdn({ quality: "high", fit: "contain", layout: "quality-last" }),
  ],
});
export default createDecoImageLoader(imageUrl, { fallback: nextImageOptimizer });

装货员不知道商业平台:站点列出其平台的帮手(@decocms/apps-vtex/image, (中文(简体) ), @decocms/apps-shopify/image)在Deco CDN之前,第一个取出源的提供者会制作它的URL. 任何其他来源到 fallback (单位:千美元)nextImageOptimizer 使用 Next 的自定义 /_next/image),或者回来时没有改变. 有了上面的提供者, 下一个 storefront 的当前加载器 URL 就会为字节出字节(tests/nextjs-image-loader.golden.test.ts 除了内容中已经修改的Deco CDN URL:现在正在修改其内容 src 而不是成为 src=image。 。 。 .

examples/nextjs-binding-smoke 在寄存器中,是一个完整的应用程序, 及其 bun run smoke 检查整个流量 next start。 。 。 .

版本与发布记录

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

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

其他发布通道:latest-7 → 7.85.2。

关于 @decocms/nextjs 的常见问题

@decocms/nextjs 是什么?

Deco CMS for any Next.js App Router app: 代理服务器和页面中的预览草稿,预览徽章, Studio Bridge, 有Deco () 和一个下一张/图像加载器

如何安装 @decocms/nextjs?

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

@decocms/nextjs 支持 TypeScript 吗?

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

@decocms/nextjs 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@decocms/nextjs 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@decocms/nextjs 可以商用吗?

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

@decocms/nextjs 的下载量有多少?

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

@decocms/nextjs 还在维护吗?

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