Next.js 没有在应该将页面构建为 SSG 时

Next.js is not building page as SSG when it should

我想了解为什么 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
            }
        }
    }
};

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

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

应该是

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

Next.js 中的 404.tsx 或 404.js 页面是独一无二的,因为它不依赖于服务器并且始终是静态的——仅依赖于静态 html (无 json)在构建时——即使在文件中使用 GetStaticProps

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

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

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

例如,我的 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 (.js, .json, .html) 所有三种文件类型都存在。如果您在自定义 _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`.