欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

next.js?getServerSideProps源碼解析

 更新時(shí)間:2022年10月11日 08:42:17   作者:嘿嘿Z  
這篇文章主要為大家介紹了next.js?getServerSideProps源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

SSR 處理

老規(guī)矩,昨天寫了關(guān)于 getServerSideProps 的內(nèi)容,今天趁熱寫一下 getServerSideProps 相應(yīng)的源碼,看看 next.js getServerSideProps 是怎么實(shí)現(xiàn)的,還有什么從文檔無法知曉的細(xì)節(jié)。

我們先從 SSR 時(shí)相關(guān)的 getServerSideProps 處理看起,源碼排查步驟上一步已經(jīng)有所介紹,本篇不再多說,在 SSR 時(shí),next.js 會(huì)調(diào)用 doRender 來進(jìn)行渲染,其中會(huì)再次調(diào)用 renderHTML,進(jìn)過各種判斷和調(diào)用最終會(huì)進(jìn)入 packages/next/server/render.tsx 中的 renderToHTML 進(jìn)行處理。

// const SERVER_PROPS_ID = "__N_SSP";
if (getServerSideProps) {
    props[SERVER_PROPS_ID] = true;
}

next.js 會(huì)先將 props 中的 SERVER_PROPS_ID 設(shè)置為 true,用做標(biāo)識(shí)。

try {
    data = await getServerSideProps({
        req: req as IncomingMessage & {
            cookies: NextApiRequestCookies;
        },
        res: resOrProxy,
        query,
        resolvedUrl: renderOpts.resolvedUrl as string,
        ...(pageIsDynamic ? { params: params as ParsedUrlQuery } : undefined),
        ...(previewData !== false ? { preview: true, previewData: previewData } : undefined),
        locales: renderOpts.locales,
        locale: renderOpts.locale,
        defaultLocale: renderOpts.defaultLocale
    });
    canAccessRes = false;
} catch (serverSidePropsError: any) {
    if (isError(serverSidePropsError) && serverSidePropsError.code === 'ENOENT') {
        delete serverSidePropsError.code;
    }
    throw serverSidePropsError;
}
if (data == null) {
    throw new Error(GSSP_NO_RETURNED_VALUE);
}
if ((data as any).props instanceof Promise) {
    deferredContent = true;
}
const invalidKeys = Object.keys(data).filter(key => key !== 'props' && key !== 'redirect' && key !== 'notFound');
if (invalidKeys.length) {
    throw new Error(invalidKeysMsg('getServerSideProps', invalidKeys));
}

注意這里的 getServerSideProps 是從外層傳進(jìn)來了,因?yàn)樯婕暗拇a較多,就不貼了,主要是通過 packages/next/server/load-components 中的 loadComponents,將路由文件中的 getServerSideProps 通過從 require 后的頁面中取出。不過挺好奇他在 node 端是怎么 require 頁面代碼而不報(bào)錯(cuò)的,畢竟頁面代碼中很可能會(huì)存在依賴瀏覽器環(huán)境的代碼,估計(jì)是做了一些類似于 runtime shim 之類的操作?此處先挖個(gè)坑,以后有空研究下。突然想起頁面都是 SSR 了,初始化代碼肯定都做過處理了 ??。

上面的代碼可以看出 SSR 的時(shí)候是直接調(diào)用 getServerSideProps 傳入 context 內(nèi)容,context 的內(nèi)容也一目了然。然后 next.js 會(huì)校驗(yàn)返回值是否為空,或者是否包含非法參數(shù)等。

然后回去檢查 notFoundredirect 參數(shù),進(jìn)行特殊處理。

if ('notFound' in data && data.notFound) {
    if (pathname === '/404') {
        throw new Error(`The /404 page can not return notFound in "getStaticProps", please remove it to continue!`);
    }
    (renderOpts as any).isNotFound = true;
    return null;
}
if ('redirect' in data && typeof data.redirect === 'object') {
    checkRedirectValues(data.redirect as Redirect, req, 'getServerSideProps');
    (data as any).props = {
        __N_REDIRECT: data.redirect.destination,
        __N_REDIRECT_STATUS: getRedirectStatus(data.redirect)
    };
    if (typeof data.redirect.basePath !== 'undefined') {
        (data as any).props.__N_REDIRECT_BASE_PATH = data.redirect.basePath;
    }
    (renderOpts as any).isRedirect = true;
}

此外從上面這段代碼還發(fā)現(xiàn)一個(gè)有意思的就是 props 是可以為 Promise 的:

if ((data as any).props instanceof Promise) {
    deferredContent = true;
}

返回 Promise 時(shí),next.js 會(huì)在異常處理完畢后獲取值:

if (deferredContent) {
    (data as any).props = await(data as any).props;
}

最后 next.js 會(huì)將獲取到的 props 值放入到頂層的 props 中:

props.pageProps = Object.assign({}, props.pageProps, (data as any).props);
(renderOpts as any).pageData = props;

SSR 時(shí),我們?cè)陧撁嬷锌吹降挠糜?hydrate__NEXT_DATA__ 中的 props 就是這個(gè) props,可以再看一眼其中的數(shù)據(jù):

<script id="__NEXT_DATA__" type="application/json">
    {
        "props": {
            "pageProps": {
                "feature": {
                    "name": "xxxx",
                    "desc": "xxxx",
                    "tags": ["xxx"],
                    "id": "account-manage"
                }
            },
            "__N_SSP": true
        },
        "page": "/feature/[fid]",
        "query": { "fid": "account-manage" },
        "buildId": "development",
        "isFallback": false,
        "gssp": true,
        "scriptLoader": []
    }
</script>

可以看到 pageProps__N_SSP 都是上面放進(jìn)去的。

動(dòng)態(tài)加載處理

看完了 SSR 場景下,next.js 如何處理 getServerSideProps,我們?cè)倏聪马撁鏋閯?dòng)態(tài)加載時(shí)的處理。

通過跳轉(zhuǎn)時(shí)發(fā)起請(qǐng)求的調(diào)用棧,我們很輕松就能找到在頁面為動(dòng)態(tài)加載時(shí),next.js 將會(huì)通過 packages/next/shared/lib/router.ts 中的 getRouteInfo 來獲取要跳轉(zhuǎn)的頁面信息,然后會(huì)通過 routeInfo__N_SSP 判定是否要去獲取數(shù)據(jù):

const shouldFetchData = routeInfo.__N_SSG || routeInfo.__N_SSP;
if (shouldFetchData) {
    const { json, cacheKey: _cacheKey } = data?.json
        ? data
        : await fetchNextData({
              dataHref: this.pageLoader.getDataHref({
                  href: formatWithValidation({ pathname, query }),
                  asPath: resolvedAs,
                  locale
              }),
              isServerRender: this.isSsr,
              parseJSON: true,
              inflightCache: this.sdc,
              persistCache: !isPreview,
              isPrefetch: false,
              unstable_skipClientCache
          });
    return {
        cacheKey: _cacheKey,
        props: json || {}
    };
}

然后通過 fetchNextData 來獲取數(shù)據(jù),而我們上文提到的 _next/data/development/{url}.json?{query} 這段 URL 就是由 formatWithValidation 構(gòu)建生成的。

而請(qǐng)求發(fā)送后服務(wù)端的處理就七繞八繞邏輯太深了,這里不一一列舉代碼,簡單說下:next.js 會(huì)通過 /_next/data/ 匹配請(qǐng)求判斷是否是數(shù)據(jù)請(qǐng)求,如果是數(shù)據(jù)請(qǐng)求將會(huì)一樣執(zhí)行 SSR代碼,然后可以理解為走的就是上面 SSR 初始化時(shí)的那套邏輯,只是最后會(huì)按照數(shù)據(jù)請(qǐng)求標(biāo)識(shí),將 props 抽離出來,放到響應(yīng)中中返回。

總結(jié)

getServerSideProps 相關(guān)的源碼還是有點(diǎn)繞的,其中應(yīng)該還少了一些其它場景的相關(guān)代碼,不過只看主場景應(yīng)該就是這些了。

以上就是next.js getServerSideProps源碼解析的詳細(xì)內(nèi)容,更多關(guān)于next.js getServerSideProps的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論