Iba*_*ikh 3 fs node.js reactjs server-side-rendering next.js
无法确定我的 next.js 应用程序中发生了什么。因为fs是 nodejs 的默认文件系统模块。它给出了找不到模块的错误。
dia*_*zlp 53
我花了几个小时在这上面,解决方案也在 Stackoverflow 上,但在不同的问题上 - > /sf/answers/4723505741/
特此,我请求 MOD 许可转发此问题,因为这个问题是第一个出现在 Google 上的问题,并且可能越来越多的人会偶然发现与我相同的问题,所以我会尽力为他们省去一些麻烦
Soo,你需要将其添加到你的next.config.js
module.exports = {
// Can be safely removed in newer versions of Next.js
future: {
// by default, if you customize webpack config, they switch back to version 4.
// Looks like backward compatibility approach.
webpack5: true,
},
webpack(config) {
config.resolve.fallback = {
// if you miss it, all the other options in fallback, specified
// by next.js will be dropped.
...config.resolve.fallback,
fs: false, // the solution
};
return config;
},
};
Run Code Online (Sandbox Code Playgroud)
它对我来说就像一种魅力。
编辑:对于较新版本的 Next.JS,该选项future.webpack5已替换为webpack5,默认为true。由于我们在此解决方案中使用 Webpack 5,因此可以安全地删除此选项。
https://nextjs.org/docs/messages/future-webpack5-moved-to-webpack5#possible-ways-to-fix-it
Cir*_*四事件 42
最小可重复示例
一个干净的最小示例将对 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' } }
}
Run Code Online (Sandbox Code Playgroud)
包.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"
}
}
Run Code Online (Sandbox Code Playgroud)
运行:
npm install
npm run dev
Run Code Online (Sandbox Code Playgroud)
现在让我们添加一个虚拟对象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' } }
}
Run Code Online (Sandbox Code Playgroud)
失败并显示:
Module not found: Can't resolve 'fs'
Run Code Online (Sandbox Code Playgroud)
这并不奇怪,因为 Next.js 无法知道那fs只是服务器,而且我们也不希望它只是忽略随机的 require 错误,对吧?Next.js 只知道 forgetStaticProps因为这是硬编码的 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' } }
}
Run Code Online (Sandbox Code Playgroud)
心智等于崩溃。因此我们知道,任何对fs主体内部的提及getStaticProps,即使是像上面这样无用的内容,也会让 Next.js/Webpack 明白它将仅是服务器的。
getServerSideProps对于和 ,事情是一样的getStaticPaths。
高阶组件 (HOC) 必须位于自己的文件中
IndexPage现在,我们在不同但相似的页面中进行分解的方法getStaticProps是使用 HOC,它们只是返回其他函数的函数。
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)
Run Code Online (Sandbox Code Playgroud)
但如果你这样做,你会悲伤地看到:
Module not found: Can't resolve 'fs'
Run Code Online (Sandbox Code Playgroud)
所以我们明白了另一件事: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)
Run Code Online (Sandbox Code Playgroud)
页面/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)
Run Code Online (Sandbox Code Playgroud)
前端.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>
</>
}
}
Run Code Online (Sandbox Code Playgroud)
返回.js
// Server-only code.
const fs = require('fs')
export function makeGetStaticProps(isBlue) {
return () => {
return { props: {
fs: Object.keys(fs).join(' '),
isBlue,
} }
}
}
Run Code Online (Sandbox Code Playgroud)
Webpack 必须看到该名称makeGetStaticProps被分配给getStaticProps,因此它决定整个 back文件仅供服务器使用。
back.js请注意,如果您尝试将和合并front.js到单个文件中,它不起作用,可能是因为当您执行export default makeIndexPage(true)webpack 时,必须尝试将整个front.js文件拉入前端,其中包括 fs,因此它会失败。
这导致库文件在以下之间自然地(基本上几乎是强制性的)分割:
front.js和front/*:前端+后端文件。这些对于前端来说是安全的。后端可以做前端可以做的任何事情(我们正在做 SSR,对吧?),所以这些也可以从后端使用。
也许这就是许多官方示例中传统“组件”文件夹背后的想法。但这是一个坏名字,因为该文件夹不仅应该包含组件,还应该包含将从前端使用的任何库非组件帮助器/常量。
back.js和back/*(或者 ) 之外的任何内容front/*:仅后端文件。这些只能由后端使用,在前端导入它们会导致错误
Zac*_*zer 19
虽然此错误比您遇到的大多数错误需要更多的推理,但它发生的原因很简单。
与许多框架不同,Next.js 允许您将仅服务器(不能在浏览器中工作的 Node.js API)代码导入到页面文件中。当 Next.js 构建您的项目时,它会通过检查以下任一内置方法(代码分割)中存在哪些代码,从客户端包中删除仅服务器代码:
getServerSidePropsgetStaticPropsgetStaticPaths旁注:有一个演示应用程序可以直观地展示其工作原理。
当您尝试在这些方法之外使用仅服务器代码时,Module not found: can't resolve 'xyz'就会发生此错误。
要重现此错误,让我们从一个简单的 Next.js 页面文件开始。
工作文件
/** THIS FILE WORKS FINE! */
import type { GetServerSideProps } from "next";
import fs from "fs"; // our server-only import
type Props = {
doesFileExist: boolean;
};
export const getServerSideProps: GetServerSideProps = async () => {
const fileExists = fs.existsSync("/some-file");
return {
props: {
doesFileExist: fileExists,
},
};
};
const ExamplePage = ({ doesFileExist }: Props) => {
return <div>File exists?: {doesFileExist ? "Yes" : "No"}</div>;
};
export default ExamplePage;
Run Code Online (Sandbox Code Playgroud)
现在,让我们通过将fs.existsSync方法移到. 区别很微妙,但下面的代码会抛出我们可怕的错误。getServerSidePropsModule not found
错误文件
import type { GetServerSideProps } from "next";
import fs from "fs";
type Props = {
doesFileExist: boolean;
};
/** ERROR!! - Module not found: can't resolve 'fs' */
const fileExists = fs.existsSync("/some-file");
export const getServerSideProps: GetServerSideProps = async () => {
return {
props: {
doesFileExist: fileExists,
},
};
};
const ExamplePage = ({ doesFileExist }: Props) => {
return <div>File exists?: {doesFileExist ? "Yes" : "No"}</div>;
};
export default ExamplePage;
Run Code Online (Sandbox Code Playgroud)
当您使用包含多种类型代码(客户端+服务器端)的模块时,最常见(且令人困惑)会发生此错误。
假设我有以下模块file-utils.ts:
import fs from 'fs'
// This code only works server-side
export function getFileExistence(filepath: string) {
return fs.existsSync(filepath)
}
// This code works fine on both the server AND the client
export function formatResult(fileExistsResult: boolean) {
return fileExistsResult ? 'Yes, file exists' : 'No, file does not exist'
}
Run Code Online (Sandbox Code Playgroud)
在本模块中,我们有一种仅服务器方法和一种“共享”方法,理论上应该在客户端工作(但正如我们将看到的,理论并不完美)。
现在,让我们尝试将其合并到我们的 Next.js 页面文件中。
/** ERROR!! */
import type { GetServerSideProps } from "next";
import { getFileExistence, formatResult } from './file-utils.ts'
type Props = {
doesFileExist: boolean;
};
export const getServerSideProps: GetServerSideProps = async () => {
return {
props: {
doesFileExist: getFileExistence('/some-file')
},
};
};
const ExamplePage = ({ doesFileExist }: Props) => {
// ERROR!!!
return <div>File exists?: {formatResult(doesFileExist)}</div>;
};
export default ExamplePage;
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我们在这里收到错误,因为当我们尝试使用formatResult客户端时,我们的模块仍然必须导入服务器端代码。
为了解决这个问题,我们需要将模块分为两类:
// file-utils.ts
import fs from 'fs'
// This code (and entire file) only works server-side
export function getFileExistence(filepath: string) {
return fs.existsSync(filepath)
}
Run Code Online (Sandbox Code Playgroud)
// file-format-utils.ts
// This code works fine on both the server AND the client
export function formatResult(fileExistsResult: boolean) {
return fileExistsResult ? 'Yes, file exists' : 'No, file does not exist'
}
Run Code Online (Sandbox Code Playgroud)
现在,我们可以创建一个工作页面文件:
/** WORKING! */
import type { GetServerSideProps } from "next";
import { getFileExistence } from './file-utils.ts' // server only
import { formatResult } from './file-format-utils.ts' // shared
type Props = {
doesFileExist: boolean;
};
export const getServerSideProps: GetServerSideProps = async () => {
return {
props: {
doesFileExist: getFileExistence('/some-file')
},
};
};
const ExamplePage = ({ doesFileExist }: Props) => {
return <div>File exists?: {formatResult(doesFileExist)}</div>;
};
export default ExamplePage;
Run Code Online (Sandbox Code Playgroud)
有两种方法可以解决这个问题:
解决此错误的最佳方法是确保您了解发生这种情况的原因(如上所述),并确保您仅在getStaticPaths、getStaticProps、 或getServerSideProps以及 NOWHERE else中使用服务器端代码。
请记住,如果导入包含服务器端和客户端代码的模块,则无法使用该模块客户端的任何导入(请重新访问上面的示例#2)。
正如其他人所建议的,您可以更改next.config.js为在构建时忽略某些模块。这意味着当 Next.js 尝试在仅服务器代码和共享代码之间拆分页面文件时,它不会尝试填充无法构建客户端的 Node.js API。
在这种情况下,您只需要:
/** THIS FILE WORKS FINE! */
import type { GetServerSideProps } from "next";
import fs from "fs"; // our server-only import
type Props = {
doesFileExist: boolean;
};
export const getServerSideProps: GetServerSideProps = async () => {
const fileExists = fs.existsSync("/some-file");
return {
props: {
doesFileExist: fileExists,
},
};
};
const ExamplePage = ({ doesFileExist }: Props) => {
return <div>File exists?: {doesFileExist ? "Yes" : "No"}</div>;
};
export default ExamplePage;
Run Code Online (Sandbox Code Playgroud)
如 Webpack 文档的resolve.fallback部分所示,此配置选项的主要原因是因为从 Webpack 开始v5.x,核心 Node.js 模块默认情况下不再是多填充的。因此,此选项的主要目的是为您提供一种方法来定义要使用的 polyfill 。
当您false作为选项传递时,这意味着“不包含填充”。
虽然这种方法有效,但它可能很脆弱,并且需要持续维护才能包含您引入到项目中的任何新模块。除非您要转换现有项目/支持遗留代码,否则最好选择上面的选项#1,因为它根据 Next.js 实际如何拆分代码来促进更好的模块组织。
Yil*_*maz 15
fs或path其他节点本机模块只能在服务器端代码内使用,例如“getServerSide”函数。如果您尝试在客户端中使用它,即使您只是使用 console.log 也会出现错误。console.log 也应该在服务器端函数内运行。
当您导入“fs”并在服务器端使用它时,next.js 足够聪明,可以看到您在服务器端使用它,因此它不会将导入添加到客户端捆绑包中
我使用的一个软件包给了我这个错误,我修复了这个问题
module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.fallback.fs = false
}
return config
},
}
Run Code Online (Sandbox Code Playgroud)
但这在终端上发出警告:
"Critical dependency: require function is used in a way in which
dependencies cannot be statically extracted"
Run Code Online (Sandbox Code Playgroud)
然后我尝试在浏览器上加载节点模块。我从node_modules复制了节点模块的“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"
/>
</>
)
}
Run Code Online (Sandbox Code Playgroud)
该包附加到window对象和node_modules源代码的index.js中:
if (typeof window !== "undefined") {
window.TruffleContract = contract;
}
Run Code Online (Sandbox Code Playgroud)
所以我可以以window.TruffleContract. 但这不是一个有效的方法。
如果您使用fs,请确保它仅在getInitialProps或内serverSideProps。(任何包括服务器端渲染)。
您可能还需要创建一个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
}
}
Run Code Online (Sandbox Code Playgroud)
为了 webpack5
module.exports = {
webpack5: true,
webpack: (config) => {
config.resolve.fallback = { fs: false };
return config;
},
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8928 次 |
| 最近记录: |