簡體   English   中英

如何在 Next.js 中最好地導入“僅限服務器”代碼?

[英]How to best import "server-only" code in Next.js?

在我的索引頁面的getServerSideProps function 中,我想使用從另一個本地文件導入的 function foo ,該文件依賴於某個節點庫。 所述庫不能在瀏覽器中運行,因為它依賴於“僅服務器”模塊,例如fsrequest

我一直在使用以下模式,但想對其進行優化。 foo定義為 mutable 以使其位於 scope 中很笨拙,似乎可以避免。

let foo;
if (typeof window === "undefined") {
  foo =  require("../clients/foo");
}

export default function Index({data}) {
  ...
}

export async function getServerSideProps() {
  return {
    props: {data: await foo()},
  }
}

這里的最佳做法是什么? 是否有可能利用 ES6 的動態導入 function? getServerSideProps中動態導入怎么樣?

我正在使用 Next.js 版本9.3.6

謝謝。

更新:

似乎 Next.js 自己的動態導入解決方案就是這個問題的答案。 我仍在測試它,並會在完成后相應地更新這篇文章。 文檔對我來說似乎很困惑,因為他們提到禁用 SSR 的導入,但反之則不然。

https://nextjs.org/docs/advanced-features/dynamic-import

當使用getServerSideProps / getStaticProps Next.js 將自動從客戶端包中刪除所有僅服務器代碼。 在瀏覽器上運行服務器代碼沒有風險。

您可以使用Next.js 代碼消除工具來驗證客戶端捆綁的內容。 您會注意到getServerSideProps / getStaticProps和它使用的導入一樣被刪除。

getServerSideProps / getStaticProps之外,我發現了 2 個非常相似的解決方案。

依賴死代碼消除

next.config.js

config.plugins.push(
    new webpack.DefinePlugin({
      'process.env.RUNTIME_ENV': JSON.stringify(isServer ? 'server' : 'browser'),
    }),
  );
export const addBreadcrumb = (...params: AddBreadcrumbParams) => {
  if (process.env.RUNTIME_ENV === 'server') {
    return import('./sentryServer').then(({ addBreadcrumb }) => addBreadcrumb(...params));
  }
  return SentryBrowser.addBreadcrumb(...params);
};

請注意,出於我不理解的某些原因,如果您使用async await或者如果您使用變量來存儲process.env.RUNTIME_ENV === 'server'的結果,則死代碼消除效果不佳。 我在 nextjs github 中創建了一個討論

告訴 webpack 忽略它

next.config.js

if (!isServer) {
    config.plugins.push(
      new webpack.IgnorePlugin({
        resourceRegExp: /sentryServer$/,
      }),
    );
  }

在這種情況下,您需要確保永遠不會在客戶端中導入此文件,否則在運行時會出錯。

您可以在getServerSidePropsgetInitialProps中導入第三方庫或服務器端文件,因為這些函數在服務器上運行。

就我而言,我使用的是僅在服務器上運行的 winston 記錄器,因此僅在這樣的服務器上導入配置文件

export async function getServerSideProps (){
   const logger = await import('../logger');
   logger.info(`Info Log ->> ${JSON.stringify(err)}`);  
}

您還可以像這樣導入具有默認導出的庫/文件

export async function getServerSideProps(context) {
  const moment = (await import('moment')).default(); //default method is to access default export
  return {
    date: moment.format('dddd D MMMM YYYY'),
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM