【问题标题】:Next.js is not building page as SSG when it shouldNext.js 不应该将页面构建为 SSG
【发布时间】:2021-07-22 16:26:39
【问题描述】:

我试图理解为什么 Next.js 将我的一些页面构建为 SSG,而其中一些页面构建为静态,而它们都使用 getStaticProps。

让我们以我的 404 页面为例,该页面使用 getStaticProps 通过 graphql 从 prismic 中获取数据。它被呈现为静态网站,而我认为它应该呈现为 SSG(因为它使用 getStaticProps)。

我在我的 500 页中做同样的事情,但使用不同的 graphql 查询,并且它被呈现(在我看来是正确的)为 SSG。

这是为什么呢?

404 页面:

const NotFound = ({ data: { page } }) => {
    return (
        <div className={'not-found'}>
            <p className={'not-found__description'}>{RichText.asText(page.description)}</p>
        </div>
    );
};

export const getStaticProps = async (context) => {
    const currentLanguage = getCurrentLocale(context);

    const response = await apolloClient.query({
        query: gql`
            query {
            }
        `
    };

    return {
        props: {
            data: {
                page: response
            }
        }
    }
});

export default NotFound;

500 页:

const InternalServerError = ({ data: { page } }) => {
    return (
        <div className={'internal-server-error'}>
             <p className={'internal-server-error__description'}>{RichText.asText(page.description)}</p>
        </div>
    );
};

export const getStaticProps = async (context) => {
    const currentLanguage = getCurrentLocale(context);
    
    const response = await apolloClient.query({
        query: gql`
            query {
            }
        `
    });
    
    return {
        props: {
            data: {
                page: response
            }
        }
    }
};

【问题讨论】:

    标签: javascript build next.js prismic.io


    【解决方案1】:

    Next.js 中的 404.tsx 或 404.js 页面的独特之处在于它不依赖服务器并且始终是静态的——仅在构建时依赖静态 html(无 json) em> -- 即使在文件中使用GetStaticProps

    404 页面只是一个包罗万象的funnel 路由,用户在导航到您的站点不存在的路径作为基本 URL 时会被重定向到该路由。因此,它在初始构建时不依赖服务器。这是不存在的路径的后备,仅此而已。另一方面,500 页面处理应用程序中的内部错误,因此它确实依赖.html.json 文件类型来查明错误的性质。

    有趣的是,如果您在本地检查.next 目录的内容,您会注意到所有使用GetStaticProps 的页面都静态生成了.json.html 文件。使用GetStaticPropsrevalidate 的页面返回=== Incremental Static RegenerationISRISRSSGSSR 的理想混合体,具有后台功能扫描生产中的传入更改/更新(您指定的数字是可能的更新之间的时间量,以秒为单位)。因此,带有GetStaticProps + ISR 的页面会在.next 目录中生成三种文件类型——.html.json.js。也就是说,使用GetServerSidePropsGetInitialProps 的页面只有.js 文件在.next 目录中生成。最后,纯Static的页面,不使用上述方法,只生成.html文件。

    404 页面及其静态特性背后的想法是通过加快自定义oops! that path doesn't exist 页面的呈现(或更准确地说是预呈现)来增强用户体验,以便用户可以尽快返回到实际应用程序。

    例如,我的404.tsx 页面中有以下内容,但它仍然呈现为静态html在构建时

    import { Container } from '@/components/UI';
    import { initializeApollo, addApolloState } from '@/lib/apollo';
    import { NotFound } from '@/components/NotFound';
    import { AppLayout } from '@/components/Layout';
    import {
        GetStaticPropsContext,
        GetStaticPropsResult,
        InferGetStaticPropsType
    } from 'next';
    import {
        NotFoundQuery,
        NotFoundDocument,
        NotFoundQueryVariables,
        DynamicNavQuery,
        DynamicNavDocument,
        DynamicNavQueryVariables,
        WordpressMenuNodeIdTypeEnum,
        WordpressMediaItemSizeEnum,
        WordpressPageIdType
    } from '@/graphql/generated/graphql';
    
    export function SOS({
        notFound,
        Header,
        Footer
    }: InferGetStaticPropsType<typeof getStaticProps>) {
        return (
            <>
                <AppLayout title={'✂ 404 ✂'} Header={Header} Footer={Footer}>
                    <Container clean className='fit'>
                        <NotFound notFound={notFound} />
                    </Container>
                </AppLayout>
            </>
        );
    }
    
    export async function getStaticProps(
        ctx: GetStaticPropsContext
    ): Promise<
        GetStaticPropsResult<{
            notFound: NotFoundQuery['NotFound'];
            Header: DynamicNavQuery['Header'];
            Footer: DynamicNavQuery['Footer'];
        }>
    > {
        const params = ctx.params!;
        console.log(params ?? '');
        const apolloClient = initializeApollo();
        await apolloClient.query<
            DynamicNavQuery,
            DynamicNavQueryVariables
        >({
            query: DynamicNavDocument,
            variables: {
                idHead: 'Header',
                idTypeHead: WordpressMenuNodeIdTypeEnum.NAME,
                idTypeFoot: WordpressMenuNodeIdTypeEnum.NAME,
                idFoot: 'Footer'
            }
        });
    
        await apolloClient.query<NotFoundQuery, NotFoundQueryVariables>(
            {
                query: NotFoundDocument,
                variables: {
                    id: '/404-not-found/' as '/404/',
                    idType: WordpressPageIdType.URI,
                    size: WordpressMediaItemSizeEnum.LARGE
                }
            }
        );
        return addApolloState(apolloClient, {
            props: {},
            revalidate: 60
        });
    }
    export default SOS;
    

    有趣的是,因为我在我的404.tsx 页面中使用GetStaticPropsrevalidate 来表示ISR,所以.next 目录的内容反映了这一点,因为404 的所有三种文件类型都存在(@ 987654362@)。如果您在自定义_app.tsx_app.js 文件中使用getInitialProps,则整个应用程序将禁用自动静态优化(静态页面的预呈现)。如果您好奇,请尝试一下,它应该会导致 404 页面在您的构建日志中旁边有一个 lambda。但是,由于您已经拥有 GetStaticProps,它应该使用 GetInitialProps 覆盖由您的根 app 页面引起的应用程序范围的静态去优化

    例如,在创建自定义 404.tsx 页面之前,我在 _app.tsx 中使用了 GetInitialProps。我决定拉出构建日志并拍摄随附的屏幕截图。

    Warning: You have opted-out of Automatic Static Optimization due to `getInitialProps` in `pages/_app`. This does not opt-out pages with `getStaticProps`.
    

    【讨论】:

    • 好的,但是 Next.js 文档说“这个文件是在构建时静态生成的。如果您需要在构建时获取数据,您可以在此页面中使用 getStaticProps。 (404 和 500 页)。两个页面不应该以完全相同的方式构建吗?
    • 我同意它们应该是,而且我认为它们确实是,如果您检查 .next 目录的内容,您会发现您拥有所有三种文件类型(js、json、html ) 在 404 页面中使用 GetStaticProps + ISR 时。也就是说,也许构建日志反映了以下内容:“404 页面可能会被非常频繁地访问。服务器为每次访问呈现错误页面会增加 Next.js 服务器的负载。这可能会导致成本增加和体验变慢。 "默认情况下它是静态的(仅限 html)——添加 GetStaticProps 会覆盖它。只是符号保持不变。
    • 我只花了大约 10 分钟筛选他们的声明文件,以确定如何在后台处理 404 与 500,但无济于事。将在 nextjs repo 上询问有关此问题的问题,您提出了一个很好的观点。我能在 === _error.d.ts 上找到所有信息,但没有明确提及 404 或 500 错误页面。
    • 我认为你是对的。 Next.js 似乎有问题
    【解决方案2】:

    404 页面是否缺少代码中的括号?

    const response = await apolloClient.query({
        query: gql`
            query {
            }
        `
    };
    

    应该是

    const response = await apolloClient.query({
        query: gql`
            query {
            }
        `
    });
    

    【讨论】:

    • 不,对不起。我错过了那个。
    猜你喜欢
    • 2021-07-05
    • 2022-07-23
    • 2022-06-28
    • 2021-08-23
    • 2021-06-26
    • 1970-01-01
    • 1970-01-01
    • 2020-10-29
    • 2020-11-15
    相关资源
    最近更新 更多