gpt4 book ai didi

javascript - Facebook 调试器不拾取 Next.js 的 next-seo 元标记

转载 作者:行者123 更新时间:2023-12-04 16:31:50 25 4
gpt4 key购买 nike

感觉这个问题已经被问了一百遍了。所以,这可能是一个很难的问题。我将为我的案例提供更多细节。也许会有所帮助。
我正在使用 Next.js ^10.0.9 和 next-seo ^4.22.0。我可以在 devtools 中看到元标记,但 FB 和 Twitter 以及许多其他元标记验证器无法获取它们。
从这里和其他地方的其他几个问题来看,似乎有一些共识,只要它不在源中,即,如果我们“检查源”并且看不到它,那么爬虫就无法使用它。据我了解,这是因为这些机器人不运行呈现元标记所需的 JavaScript。
资源
此页面源应包含用于描述、标题、图像和其他一些内容的 opengraph 元标记,但它不包含:

<!DOCTYPE html>
<html lang="en">
<head>
<style data-next-hide-fouc="true">
body{display:none}
</style>
<noscript data-next-hide-fouc="true">
<style>
body{display:block}
</style>
</noscript>

<meta charSet="utf-8"/>
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width"/>
<meta name="next-head-count" content="2"/>

<noscript data-n-css=""></noscript>

<link rel="preload" href="/_next/static/chunks/main.js?ts=1616232654196" as="script"/>
<link rel="preload" href="/_next/static/chunks/webpack.js?ts=1616232654196" as="script"/>
<link rel="preload" href="/_next/static/chunks/pages/_app.js?ts=1616232654196" as="script"/>
<link rel="preload" href="/_next/static/chunks/pages/index.js?ts=1616232654196" as="script"/>

<noscript id="__next_css__DO_NOT_USE__"></noscript>

<style id="jss-server-side">html {
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
*, *::before, *::after {
box-sizing: inherit;
}
strong, b {
font-weight: 700;
}
body {
color: rgba(0, 0, 0, 0.87);
margin: 0;
font-size: 0.875rem;
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
font-weight: 400;
line-height: 1.43;
letter-spacing: 0.01071em;
background-color: #c3d0f5;
}
@media print {
body {
background-color: #fff;
}
}
body::backdrop {
background-color: #c3d0f5;
}</style>

</head>

<body>
<div id="__next">
<div class="Loading__Center-sc-9gpo7v-0 dctQei">
<div style="width:100%;height:100%;overflow:hidden;margin:0 auto;outline:none" title="" role="button" aria-label="animation" tabindex="0">
</div>
<h2>This is you. This is how you wait.</h2>
</div>
</div>

<script src="/_next/static/chunks/react-refresh.js?ts=1616232654196"></script>

<script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"development","runtimeConfig":{"APP_NAME":"example","APP_DESCRIPTION":"Discover examples of examples of examples.","APP_URL":"https://example.com","nextExport":true,"autoExport":true,"isFallback":false}</script>

<script nomodule="" src="/_next/static/chunks/polyfills.js?ts=1616232654196"></script>
<script src="/_next/static/chunks/main.js?ts=1616232654196"></script>
<script src="/_next/static/chunks/webpack.js?ts=1616232654196"></script>
<script src="/_next/static/chunks/pages/_app.js?ts=1616232654196"></script>
<script src="/_next/static/chunks/pages/index.js?ts=1616232654196"></script>
<script src="/_next/static/development/_buildManifest.js?ts=1616232654196"></script>
<script src="/_next/static/development/_ssgManifest.js?ts=1616232654196"></script>
</body>
</html>
构建时生成的页面?
Next.js 没有渲染它们让我感到困惑。根据 docs :

By default, Next.js pre-renders every page. This means that Next.jsgenerates HTML for each page in advance, instead of having it all doneby client-side JavaScript. Pre-rendering can result in betterperformance and SEO.


除非我看错了,这意味着只要我使用默认设置,页面将通过 SSR 或静态生成呈现。正确的?
此外,上述来源提到 "nextExport":true,"autoExport":true ,我认为这表明该页面应该在构建时创建。
我的代码可能经历了一些更改,但我很确定它们没有偏离 SSR 或静态生成。
代码的高级 View
在某些时候,我添加了 _document.tsx 和 _app.tsx。
我对 _document.tsx 的改动不大。经过一些实验,我认为拥有 Head 是至关重要的。来自 next/document这里:
import Document, { Head, Html, Main, NextScript } from "next/document";

import React from "react";
import { ServerStyleSheets } from "@material-ui/core/styles";
import theme from "../styles/theme";

export default class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}

MyDocument.getInitialProps = async (ctx) => {
const sheets = new ServerStyleSheets();
const originalRenderPage = ctx.renderPage;

ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) => sheets.collect(<App {...props} />),
});

const initialProps = await Document.getInitialProps(ctx);

return {
...initialProps,
styles: [
...React.Children.toArray(initialProps.styles),
sheets.getStyleElement(),
],
};
};
_app.tsx 有更多变化,但我认为不会影响元标记。如果我手动在 Head 中手动放置元标记在这里,它们会出现在源代码中。适用于默认值,但我希望能够以编程方式为每个页面执行此操作。
import { useEffect, useState } from "react";

import { AppProps } from "next/app";
import CssBaseline from "@material-ui/core/CssBaseline";
import Layout from "../components/Layout";
import { ThemeProvider } from "@material-ui/core/styles";
import { User } from "../context/user";
import theme from "../styles/theme";

export default function App({ Component, pageProps }: AppProps) {
const [user, setUser] = useState({
auth: null,
loading: true,
});

useEffect(() => {
const getUser = async () => {
const res = await fetch("/api/auth/me");
const auth = res.ok ? await res.json() : null;
setUser({ auth, loading: false });
};
getUser();

const jssStyles = document.querySelector("#jss-server-side");
if (jssStyles) {
jssStyles &&
jssStyles.parentElement &&
jssStyles.parentElement.removeChild(jssStyles);
}
}, []);

return (
<>
<User.Provider value={{ user, setUser }}>
<ThemeProvider theme={theme}>
<CssBaseline />
<Layout>
<Component {...pageProps} />
</Layout>
</ThemeProvider>
</User.Provider>
</>
);
}
我创建了一个 Head使用 next-seo 的组件。它做了很多工作。也许只是注意它直接返回 NextSeo ,而不将其放入 React 片段或其他组件中:
import { NextPage } from "next";
import { NextSeo } from "next-seo";
import React from "react";
import getConfig from "next/config";
const { publicRuntimeConfig } = getConfig();
interface Props {
page?: string;
description?: string;
image?: {
url: string;
alt: string;
};
}

const appDescription = publicRuntimeConfig.APP_DESCRIPTION;
const appName = publicRuntimeConfig.APP_NAME;
const appUrl = publicRuntimeConfig.APP_URL;
const twitter = publicRuntimeConfig.TWITTER;

const PageHead: NextPage<Props> = ({ page, description, image }: Props) => {
const pageTitle = page ? `${page} | ${appName}` : appName;
const pageDescription = description ?? appDescription;

let pageUrl;
let isItemPage;

if (typeof window !== "undefined") {
pageUrl = window.location.href ?? appUrl;
isItemPage = window.location.pathname.includes("item");
}

const disallowRobot = isItemPage ? true : false;

const pageImage = image ?? {
url: `${appUrl}/logo.png`,
width: 400,
height: 400,
alt: `${appName} logo`,
};

return (
<NextSeo
title={pageTitle}
description={pageDescription}
canonical={pageUrl}
openGraph={{
url: pageUrl,
title: pageTitle,
description: pageDescription,
images: [pageImage],
site_name: appName,
}}
twitter={{
handle: twitter,
site: twitter,
cardType: "summary_large_image",
}}
noindex={disallowRobot}
nofollow={disallowRobot}
/>
);
};

export default PageHead;

以下是它在组件/页面中的使用方式。此页面包含来自第三方 API 的动态内容,并且 URL 取决于该内容。我不确定,但我认为这个页面是通过静态生成创建的:
import Head from "../../components/Head";

interface Props {
item: ContentProps;
}

const MostLikedThings: NextPage<Props> = ({ item }: Props) => {
...

return (
<>
<Head
page={item.title}
description={item.synopsis}
image={...}
/>
<MainWrapper>
...
</MainWrapper>
</>
);
};

export default MostLikedThings;

export async function getStaticPaths() {
return {
paths: [],
fallback: true,
};
}

export async function getStaticProps({ params }: { params: { id: string } }) {
const item = await (
await fetch(`/api/content`)
).json();
return {
props: { item },
revalidate: 86400,
};
}

不需要外部内容的更简单的页面如下面的代码所示。我相信它也是用静态生成制作的,因为(据我所知)我没有使用过 getServerSideProps用它:
import Head from "../components/Head";
import Main from "../apps/main/index";
import { NextPage } from "next";

const Home: NextPage = () => {

return (
<>
<Head page="Home" />
<Main />
</>
);
};

export default Home;

我相信这两个页面都是通过静态生成生成的,对吧?在这种情况下,它们都是在构建时生成的。这意味着元标记应该在源代码中。那么,他们为什么不呢?
做了几次尝试
我已经尝试了很多东西,包括:
  • 使用 getServerSideProps试图以某种方式更明确地确保页面是在服务器端生成的
  • 删除 Head来自 _app.tsx 和 _document.tsx
  • 仅使用 html 标签 head在页面中手动设置元标记
  • 使用 next/head而不是直接在页面中手动设置元标签的next-seo:
  • <Head>
    ...
    <meta name="twitter:card" content="summary_large_image" />
    <meta name="twitter:site" content={twitter} />
    <meta name="twitter:creator" content={twitter} />
    ...
    </Head>
    他们都没有工作。
    最后要注意的是,我阅读了 here那:

    title, meta or any other elements (e.g. script) need to be containedas direct children of the Head element, or wrapped into maximum onelevel of <React.Fragment> or arrays—otherwise the tags won't becorrectly picked up on client-side navigations.


    我想我已经确定了这一点。
    我读过的许多问题中的几个:
  • Meta Tags does not appear in View Source Code - Facebook Crawler issue - SEO
  • Next JS - Meta Tags Missing in Source Code
  • META tags in Next.js React App are not readable by BrowseSEO
  • Page Content is not showing in source code

  • 我错过了什么吗?
    谢谢。

    最佳答案

    在无数次基于其他人未回答的问题进行实验后,我发现我有两个问题。
    首先要注意的一点:主页面肯定是在构建时创建的(静态生成)。在我的问题中,我不确定。现在我确定了。
    关于问题。
    载入画面问题
    在数据加载之前有一个加载屏幕是一种常见的模式。如果我们有一个加载屏幕,那就是在构建时创建的。
    我的组件嵌套如下:

        <Layout> // loading screen here
    <Navbar />
    <Main>{children!}</Main> // NextSeo here
    </Layout>
    加载屏幕位于 <Layout />但我的 <NextSeo />实现在 <Main /> .这是我在布局中的加载代码:
      if (user && user.loading)
    return (
    <Loading />
    );
    因此,即使页面在运行时被浏览器正确渲染,Next.js 在构建时也只构建了 Loading 组件。可能是因为它是它收到的第一件事。这就是各种元标记验证器所抓取的内容。
    不幸的是,当我写我的问题时,我并不知道这一点,所以可能没有人能够弄清楚这一点,因为我不知道所有组件和实现是如何嵌套的。我的错。
    就我而言,我有点不赞成用户加载东西,并且能够用 this solution 替换它:
      const router = useRouter();

    const [pageLoading, setPageLoading] = useState<boolean>(false);

    useEffect(() => {
    const handleStart = () => {
    setPageLoading(true);
    };
    const handleComplete = () => {
    setPageLoading(false);
    };

    router.events.on("routeChangeStart", handleStart);
    router.events.on("routeChangeComplete", handleComplete);
    router.events.on("routeChangeError", handleComplete);
    }, [router]);
    如果我确实需要再次拥有用户数据,我可能不得不使用 getServerSideProps除了 useRouter .我还不知道。这只是说您的用例可能需要与我的不同的东西。
    getServerSideProps 还是 getStaticProps?
    我的第二个问题是对 getStaticPath 的误用/误解。和 getStaticProps .根据 docs :

    getStaticPaths (Static Generation): Specify dynamic routes topre-render pages based on data.


    我的用例涉及从第三方 API 获取动态 id,然后使用它来构建 URL 并为其获取内容。所以我用 getStaticPath 和 getStaticProps 一起做。这些在构建时创建页面。因此,页面从未收到元标记所需的数据。
    因为文档明确说明了在这两种方法中使用动态路径,但在 getServerSideProps 方面没有那么明确,我的印象是不应该使用 getServerSideProps 来完成。
    事实证明,我错了。我们可以将 getServerSideProps 与动态路径一起使用。所以代替这个:
    export async function getStaticPaths() {
    return {
    paths: [],
    fallback: true,
    };
    }

    export async function getStaticProps({ params }: { params: { id: string } }) {
    let item = await (
    await fetch(
    `/api/content/?id=${params.id}`
    )
    ).json();

    return {
    props: { item },
    revalidate: 86400,
    };
    }
    我现在这样做:
    export async function getServerSideProps({
    params,
    }: {
    params: { id: string };
    }) {
    let item = await (
    await fetch(
    `/api/content/?id=${params.id}`
    )
    ).json();

    return {
    props: { item },
    };
    }
    因为 getServerSideProps 会根据请求生成页面,所以它每次都重新提供元标记。

    关于javascript - Facebook 调试器不拾取 Next.js 的 next-seo 元标记,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66717038/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com