Next.js App Router中如何在指定文章页面的<head>中仅加载一次Google Reader Revenue Manager脚本?
Next.js App Router中如何在指定文章页面的中仅加载一次Google Reader Revenue Manager脚本?
我完全懂你遇到的糟心事——要精准把Google的脚本塞到Next.js App Router文章页面的<head>里,还得保证只在这些页面加载、只加载一次,之前的办法要么位置不对要么踩了重复加载的坑。其实App Router本身就有更干净的解决思路,根本不用搞Root Layout的条件判断或者依赖请求头的hack。
最优解法:给文章页面用专属嵌套Layout
App Router的核心优势之一就是路由段可以有自己独立的Layout,咱们完全可以给/news/[slug]这个路由单独做一个Layout组件,把Google脚本直接写在这个Layout的<head>里。这样只有访问文章页面时,这些脚本才会被渲染到全局<head>中,而且只会加载一次,完美契合你的需求。
具体代码实现:
在/app/news/[slug]/目录下新建layout.tsx文件,内容如下:
// /app/news/[slug]/layout.tsx import type { ReactNode } from 'react'; export default function NewsArticleLayout({ children }: { children: ReactNode }) { return ( <> {/* 这个<head>会和根Layout的<head>自动合并,最终渲染在HTML的根<head>里 */} <head> {/* 加载Google基础脚本 */} <script async src="https://news.google.com/swg/js/v1/swg-basic.js"></script> {/* 初始化脚本,用dangerouslySetInnerHTML处理内联代码 */} <script async dangerouslySetInnerHTML={{ __html: ` // 初始化SWG全局对象 window.swg = window.swg || function() { (swg.q = swg.q || []).push(arguments); }; // 替换成你的实际Google配置 swg('init', { publisherId: '你的发布者ID', articleId: '${(children as any).props.articleId}' // 可从页面props/路由参数获取真实文章ID }); swg('fetchBasicContent'); ` }} /> </head> {/* 包裹文章页面的内容 */} {children} </> ); }
为什么这个方案靠谱?
- 路由专属:只有访问
/news/[slug]下的页面时,这个Layout才会生效,脚本完全不会影响首页或其他路由。 - 位置精准:脚本直接写在Layout的
<head>里,最终会被Next.js合并到HTML的根<head>中,完全符合Google要求的“原始HTML的中”。 - 无重复加载:每个文章页面只会触发一次这个Layout的渲染,脚本只会请求一次,彻底解决你之前看到的两次加载问题。
聊聊你之前方案的问题所在
- 用
next/script的坑:虽然beforeInteractive策略理论上会把脚本放到<head>,但在App Router的Page组件中使用时,尤其是如果你的Page是客户端组件,Next.js可能因为渲染优先级问题,最终把脚本插到了<body>里,确实满足不了Google的要求。 - Root Layout条件判断的问题:你依赖
x-pathname请求头判断路径,但这个头需要配合Middleware设置,而且Server Component中的headers()在客户端导航时不会实时更新,再加上Next.js的布局缓存机制,很容易出现脚本重复加载或者路径判断错误的情况,这就是你看到两次请求的核心原因。
内容来源于stack exchange
相关产品推荐
相关产品推荐

