next.js 只在服务器端导入一个库以在getInitialProps中使用

taor4pac  于 2023-08-04  发布在  其他
关注(0)|答案(2)|浏览(104)

我的设置

我在_app.js文件上使用getInitialProps在服务器端预加载数据:

import App from "next/app";

// The problematic import
import nodeFetchCache from "node-fetch-cache";

function MyApp({ Component, pageProps, customProps }) {
  return <Component customProps={customProps} {...pageProps} />;
}

MyApp.getInitialProps = async (appContext) => {
  const appProps = await App.getInitialProps(appContext);
  
  // When I remove the top import and use a classic "fetch" here, it works fine
  const res = await nodeFetchCache(
    `${process.env.NEXT_PUBLIC_API_URL}/api/node/last_items`
  );

  const items = await res.json();

  return {
    ...appProps,
    customProps: {
      footerArticles: items.data.articles,
      footerVideos: items.data.videos,
    },
  };
};

export default MyApp;

字符串

我的问题

此代码产生一个错误:
未处理的运行时错误TypeError:“原始”参数必须为Function类型
调用堆栈promisify node_modules/util/util.js(614:0)eval node_modules/@npmcli/move-file/index. js(25:0)对象../node_modules/@npmcli/move-file/index。js文件:/Users/dev/app/.next/static/chunks/pages/_app.js(716:1)对象。选择factory/_next/static/chunks/webpack.js(685:31)webpack_requirefile:/Users/dev/app/.next/static/chunks/webpack.js(37:33)fn/_next/static/chunks/webpack.js(354:21)eval node_modules/cache/lib/entry-index.js(16:17)Object../node_modules/cache/lib/entry-index.js文件:/Users/dev/app/.next/static/chunks/pages/_app.js(1598:1)对象。选择factory/_next/static/chunks/webpack.js(685:31)webpack_requirefile:/Users/dev/app/.next/static/chunks/webpack.js(37:33)fn/_next/static/chunks/webpack.js(354:21)eval node_modules/cache/ls.js(3:14)Object../node_modules/cache/ls.js文件:/Users/dev/app/.next/static/chunks/pages/_app.js(1686:1)对象。选择factory/_next/static/chunks/webpack.js(685:31)webpack_requirefile:/Users/dev/app/.next/static/chunks/webpack.js(37:33)fn/_next/static/chunks/webpack.js(354:21)eval node_modules/cache/index.js(3:11)Object../node_modules/cache/index.js文件:///Users/dev/app/.next/static/chunks/pages/_app.js(1543:1)对象。选择factory/_next/static/chunks/webpack.js(685:31)webpack_requirefile:/Users/dev/app/.next/static/chunks/webpack.js(37:33)fn/_next/static/chunks/webpack.js(354:21)eval webpack-internal:/./node_modules/node-fetch-cache/src/classes/caching/file_system_cache.js(5:65)Module../node_modules/node-fetch-cache/src/classes/caching/file_system_cache.js file:///Users/dev/app/.next/static/chunks/pages/_app.js(4513:1)模块。选择factory/_next/static/chunks/webpack.js(685:31)webpack_requirefile:/Users/dev/app/.next/static/chunks/webpack.js(37:33)fn/_next/static/chunks/webpack.js(354:21)eval webpack-internal:/./node_modules/node-fetch-cache/src/index.js(13:95)Module../node_modules/node-fetch-cache/src/index.js file:/Users/dev/app/.next/static/chunks/pages/_app.js(4557:1)模块。选择factory/_next/static/chunks/webpack.js(685:31)webpack_requirefile:///Users/dev/app/.next/static/chunks/webpack.js(37:33)fn/_next/static/chunks/webpack.js(354:21)eval webpack-internal:/./pages/_app.js(10:74)Module../pages/_app.js file:/Users/dev/app/.next/static/chunks/pages/_app.js(40:1)模块。选择factory/_next/static/chunks/webpack.js(685:31)webpack_requirefile:/Users/dev/app/.next/static/chunks/webpack.js(37:33)fn/_next/static/chunks/webpack.js(354:21)eval node_modules/next/dist/build/webpack/loaders/next-client-pages-loader. js?page =%2F_app&absolutePagePath = private-next-pages%2F_app!(5:15)eval node_modules/next/dist/client/route-loader.js(207:48)
从其他开发人员告诉我的情况来看,似乎Next试图在客户端导入服务器端代码。即使我删除了await nodeFetchCache(...)调用,我在顶部导入'node-fetch-cache'的唯一事实也会给我一个错误。

我的问题

我想达到的目标有可能实现吗?getInitialProps不是应该只在服务器端运行吗?难道代码/树抖动不应该消除客户端包中未使用的导入吗?
我有点迷路了。如有任何帮助,我们将不胜感激。

14ifxucb

14ifxucb1#

getInitialProps不是应该只在服务器端运行吗?
只有在某些情况下。
通常,getInitialProps同时在服务器(初始页面加载时)和客户端(客户端导航时)运行。此规则的例外是当您导航到的页面使用getServerSideProps时。
getInitialProps文档:
对于初始页面加载,getInitialProps将仅在服务器上运行。然后,当通过next/link组件或使用next/router导航到不同的路由时,getInitialProps将在客户端上运行。但是,如果在自定义_app.js中使用getInitialProps,并且导航到的页面实现了getServerSideProps,则getInitialProps将在服务器上运行。
因此,与getServerSideProps/getStaticProps不同,getInitialProps的代码不会通过Next.js从客户端包中获取automatically eliminated。这意味着webpack将在客户端包中包含您在getInitialProps中使用的任何库。理想情况下,您将希望用getInitialProps编写同构代码,即可以在客户机和服务器上运行的代码。
在你的例子中,node-fetch-cache是一个Node.js库,不能在浏览器中运行。从我所看到的可能的解决方案是:

1使用同构包

简单的解决方案是使用同构库来替换node-fetch-cache,如isomorphic-fetch。这将允许您在客户端和服务器上使用它,而不会带来额外的麻烦。

#2使用webpack的IgnorePlugin

如果你想在服务器上只在getInitialProps内部运行node-fetch-cache代码,你可以使用webpack的IgnorePlugin来忽略客户端的模块,防止任何潜在的错误。

// next.config.js
module.exports = {
    // Other configs you may have...
    webpack: function (config, { isServer, webpack }) {
        if (!isServer) {
            config.plugins.push(
                new webpack.IgnorePlugin({ resourceRegExp: /node-fetch-cache/ })
            );
        }
        return config;
    }
}

字符串

#3使用webpack的resolve.alias

与前面的解决方案类似,您可以使用set resolve.alias to false来告诉webpack在客户端忽略node-fetch-cache

// next.config.js
module.exports = {
    // Other configs you may have...
    webpack: function (config) {
        config.resolve.alias['node-fetch-cache'] = false;
        return config;
    }
}


请注意,对于解决方案**#2#3**,您需要重构当前代码以正确处理客户端场景,因为node-fetch-cache将无法在那里使用。

MyApp.getInitialProps = async (appContext) => {
    const appProps = await App.getInitialProps(appContext);
  
    if (appContext.ctx.req) { // Check if on the server-side
        // Dynamically import `node-fetch-cache` on the server-only  
        const { default: nodeFetchCache } = await import('node-fetch-cache');
        const res = await nodeFetchCache(`${process.env.NEXT_PUBLIC_API_URL}/api/node/last_items`);
        const items = await res.json();

        return {
            ...appProps,
            customProps: {
                footerArticles: items.data.articles,
                footerVideos: items.data.videos
            }
        };
    } else {
        // Handle client-side here
    }
};

a9wyjsp7

a9wyjsp72#

您可以将此参数添加到package.json

"browser": {
    "node-fetch-cache": false
  }

字符串
因此它将从客户端捆绑中排除它

相关问题