找不到module:无法在 Next.js 应用程序中解析“fs”

IT技术 node.js reactjs next.js server-side-rendering fs
2021-04-16 14:08:43

无法确定我的 next.js 应用程序中发生了什么。因为fs是 nodejs 的默认文件系统module。它给出了找不到module的错误

在此处输入图片说明

在此处输入图片说明

6个回答

如果您使用fs,请确保它仅在getInitialPropsserverSideProps(任何东西都包括服务器端渲染)。

您可能还需要创建一个next.config.js包含以下内容文件来构建客户端包:

为了 webpack4

module.exports = {
  webpack: (config, { isServer }) => {
    // Fixes npm packages that depend on `fs` module
    if (!isServer) {
      config.node = {
        fs: 'empty'
      }
    }

    return config
  }
}

为了 webpack5

module.exports = {
  webpack5: true,
  webpack: (config) => {
    config.resolve.fallback = { fs: false };

    return config;
  },
};

注意:对于其他module,例如path,您可以添加多个参数,例如

{
  fs: false,
  path: false
}
好的,@AustinWitherow。让我检查并更新答案。谢谢指正。
2021-05-24 14:08:43
由于fs问了这个问题,@JusticeBringer。我可能无法添加代码,但让我将其添加为注释。
2021-06-07 14:08:43
黄金答案!只是我还必须path: falsefs: false.
2021-06-11 14:08:43
这很棒,但future: { webpack5: true }应该像webpack5: true. 谢谢!
2021-06-14 14:08:43

fspath或其他节点本机module只能在服务器端代码中使用,如“getServerSide”函数。如果您尝试在客户端中使用它,即使您只是使用 console.log 也会出错。该 console.log 也应该在服务器端函数中运行。

当您导入“fs”并在服务器端使用它时,next.js 足够聪明,可以看到您在服务器端使用它,因此它不会将该导入添加到客户端包中

我使用的软件包之一给了我这个错误,我用

module.exports = {
 
  webpack: (config, { isServer }) => {
    if (!isServer) {
      config.resolve.fallback.fs = false
    }

    return config
  },
  
}

但这在终端上发出警告:

"Critical dependency: require function is used in a way in which

 dependencies cannot be statically extracted"

然后我尝试在浏览器上加载节点module。我从 node_modules 复制了节点module的“min.js”并放置在“public/js/myPackage.js”中并用脚本加载它

export default function BaseLayout({children}) {
  return (
    <>
      <Script
        // this in public folder
        src="/js/myPackage.js"
        // this means this script will be loaded first
        strategy="beforeInteractive"
      />
    </>
  )
}

这个包被附加到window对象和 node_modules 源代码的 index.js 中:

if (typeof window !== "undefined") {
  window.TruffleContract = contract;
}

所以我可以访问这个脚本作为window.TruffleContract. 但这不是一种有效的方式。

可能是您尝试实现的module不应该在浏览器中运行。即它只是服务器端。

@asma 首先,StackOverflow 上没有像“经过验证的答案”这样的东西。其次,OP 接受了这个答案,而不是 ArjunKava 的答案,因为后者是在他们提出问题 6 个月后发布的,并且从那以后就不太在意接受更好的答案了。此外,这是一个完全有效的推理。如果在客户端代码中使用,仅服务器包会并且确实会导致此类问题。PS:在过时的答案更新后,此答案不再固定在顶部,因此它不应该成为问题,因为这是他们需要帮助 OP 的答案,因此是公认的答案
2021-05-22 14:08:43
@asma 它提供了问题的答案并被 OP 接受。它可能不会像 Yilmaz 的回答那样详细地解决解决方案,但在技术上它根本没有问题。“经过验证的答案”不是一回事,OP 接受对他们有用的答案。
2021-06-15 14:08:43
为什么这是一个经过验证的答案,而它甚至不是答案?
2021-06-20 14:08:43

我在 NextJS 应用程序中遇到此错误,因为我export

export function getStaticProps()
我有一个相关的错误,但我拼错了 getServerSideProps,所以我使用了 fs module客户端。一个容易犯的错误!
2021-06-03 14:08:43

最小的可重复示例

一个干净的最小示例将对 Webpack 初学者有益,因为基于使用情况的自动拆分是如此令人兴奋的魔法。

工作你好世界基线:

页面/index.js

// Client + server code.

export default function IndexPage(props) {
  return <div>{props.msg}</div>
}

// Server-only code.

export function getStaticProps() {
  return { props: { msg: 'hello world' } }
}

包.json

{
  "name": "test",
  "version": "1.0.0",
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "12.0.7",
    "react": "17.0.2",
    "react-dom": "17.0.2"
  }
}

运行:

npm install
npm run dev

现在让我们添加一个假人require('fs')来炸毁东西:

// Client + server code.

export default function IndexPage(props) {
  return <div>{props.msg}</div>
}

// Server-only code.

const fs = require('fs')

export function getStaticProps() {
  return { props: { msg: 'hello world' } }
}

失败:

Module not found: Can't resolve 'fs' 

这并不奇怪,因为 Next.js 无法知道那fs只是服务器,而且我们不希望它只是忽略随机要求错误,对吗?Next.js 只知道getStaticProps因为这是一个硬编码的 Next.js 函数名称。

好的,让我们通过使用fsinside通知 Next.js getStaticProps,以下再次起作用:

// Client + server code.

export default function IndexPage(props) {
  return <div>{props.msg}</div>
}

// Server-only code.

const fs = require('fs')

export function getStaticProps() {
  fs
  return { props: { msg: 'hello world' } }
}

头脑等于吹。所以我们明白,任何提到fs的主体内部getStaticProps,即使是像上面那样无用的,都会让 Next.js/Webpack 明白它将是仅限服务器的。

事情对getServerSideProps和 也一样getStaticPaths

高阶组件 (HOC) 必须在它们自己的文件中

现在,我们分解出的方式IndexPage,并getStaticProps在不同但类似的网页是用肝卵圆细胞,这是刚刚返回其他函数的函数。

HOC 通常会被放置在pages/多个位置之外,然后从多个位置需要,但是当您要将事情分解出来进行概括时,您可能会尝试将它们pages/暂时直接放在文件中,例如:

// Client + server code.

import Link from 'next/link'

export function makeIndexPage(isIndex) {
  return (props) => {
    return <>
      <Link href={isIndex ? '/index' : '/notindex'}>
        <a>{isIndex ? 'index' : 'notindex'}</a>
      </Link>
      <div>{props.fs}</div>
      <div>{props.isBlue}</div>
    </>
  }
}

export default makeIndexPage(true)

// Server-only code.

const fs = require('fs')

export function makeGetStaticProps(isBlue) {
  return () => {
    return { props: {
      fs: Object.keys(fs).join(' '),
      isBlue,
    } }
  }
}

export const getStaticProps = makeGetStaticProps(true)

但如果你这样做,你会难过地看到:

Module not found: Can't resolve 'fs' 

所以我们理解了另外一件事:fs用法必须直接在getStaticProps函数体内部,Webpack 无法在子函数中捕获它。

解决此问题的唯一方法是为仅后端内容创建一个单独的文件,如下所示:

页面/index.js

// Client + server code.

import { makeIndexPage } from "../front"

export default makeIndexPage(true)

// Server-only code.

import { makeGetStaticProps } from "../back"

export const getStaticProps = makeGetStaticProps(true)

页面/notindex.js

// Client + server code.

import { makeIndexPage } from "../front"

export default makeIndexPage(false)

// Server-only code.

import { makeGetStaticProps } from "../back"

export const getStaticProps = makeGetStaticProps(false)

前端.js

// Client + server code.

import Link from 'next/link'

export function makeIndexPage(isIndex) {
  return (props) => {
    console.error('page');
    return <>
      <Link href={isIndex ? '/notindex' : '/'}>
        <a>{isIndex ? 'notindex' : 'index'}</a>
      </Link>
      <div>{props.fs}</div>
      <div>{props.isBlue}</div>
    </>
  }
}

返回.js

// Server-only code.

const fs = require('fs')

export function makeGetStaticProps(isBlue) {
  return () => {
    return { props: {
      fs: Object.keys(fs).join(' '),
      isBlue,
    } }
  }
}

Webpack 必须看到该名称makeGetStaticProps被分配给getStaticProps,因此它决定整个 back文件是仅服务器的。

请注意,如果您尝试将back.js合并front.js到单个文件中,则它不起作用,可能是因为当您执行export default makeIndexPage(true)webpack时,它必然会尝试将整个front.js文件入前端,其中包括 fs,因此它失败了。

这导致库文件在以下之间自然拆分:

  • front.jsfront/*:前端+后端文件。这些对前端来说是安全的。后端可以做前端可以做的任何事情(我们正在做 SSR 对吗?)所以那些也可以从后端使用
  • back.jsback/*:仅后端文件。这些只能由后端使用,在前端导入它们会导致错误