I'm using the popular find-up npm package, which has locate-path as a dependency. locate-path
requires fs
within it's code.
When I attempt to run my app I get the following error message:
[ error ] ./node_modules/locate-path/index.js
Module not found: Can't resolve 'fs' in 'C:\...\node_modules\locate-path'
Could not find files for /index in .next/build-manifest.json
Promise { <pending> }
ModuleNotFoundError: Module not found: Error: Can't resolve 'fs' in 'C:\...\node_modules\locate-path'
at factory.create (C:\...\node_modules\webpack\lib\Compilation.js:823:10)
at factory (C:\...\node_modules\webpack\lib\NormalModuleFactory.js:397:22)
at resolver (C:\...\node_modules\webpack\lib\NormalModuleFactory.js:130:21)
at asyncLib.parallel (C:\...\node_modules\webpack\lib\NormalModuleFactory.js:224:22)
at C:\...\node_modules\neo-async\async.js:2830:7
at C:\...\node_modules\neo-async\async.js:6877:13
at normalResolver.resolve (C:\...\node_modules\webpack\lib\NormalModuleFactory.js:214:25)
at doResolve (C:\...\node_modules\enhanced-resolve\lib\Resolver.js:184:12)
at hook.callAsync (C:\...\node_modules\enhanced-resolve\lib\Resolver.js:238:5)
at _fn0 (eval at create (C:\...\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:15:1)
at resolver.doResolve (C:\...\node_modules\enhanced-resolve\lib\UnsafeCachePlugin.js:37:5)
at hook.callAsync (C:\...\node_modules\enhanced-resolve\lib\Resolver.js:238:5)
at _fn0 (eval at create (C:\...\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:15:1)
at hook.callAsync (C:\...\node_modules\enhanced-resolve\lib\Resolver.js:238:5)
at _fn0 (eval at create (C:\...\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:27:1)
at resolver.doResolve (C:\...\node_modules\enhanced-resolve\lib\DescriptionFilePlugin.js:42:38)
I created an issue in the locate-path repo and they have confirmed the issue is not with them, but likely with webpack. I don't use webpack in my app so the issue must be arising from Next.js's use of webpack.
Clone https://github.com/TidyIQ/nextjs-issue and run npm run dev
.
No issue
You can safely use fs
within getStaticProps
or getServerSideProps
, no extra configuration required. Be sure you're referencing the variable in your data lifecycle so it's correctly tree shaken away.
You can use this tool to learn visually how it works!
If you're still building on a legacy Next.js version with getInitialProps
, read below ๐
The provided code is not valid -- this file would never be available on the client side during rendering:
Remember, you can only do FS-related operations while _on the server_. This means you cannot use fs
while rendering.
If you use fs
, be sure it's only within getInitialProps
.
You may also need to create a next.config.js
file with the following content to get the client bundle to build:
module.exports = {
webpack: (config, { isServer }) => {
// Fixes npm packages that depend on `fs` module
if (!isServer) {
config.node = {
fs: 'empty'
}
}
return config
}
}
I have the same problem on my local, practically vanilla install, however in the examples from nextjs this doesn not seem to be a problem
https://github.com/zeit/next.js/tree/5787cbd9de33ea9add7cadeb04689b0d4b02976d/examples/blog-starter
what makes it work there without modifying the config file?
Only use fs
in getStaticProps / getServerSideProps as those are eliminated from the browser bundle.
I found out what the problem was. If I import a function that uses fs
, but do not run/use the function inside getStaticProps, it will end up being included in the browser bundle. Once the function gets referenced inside getStaticProps it will stop appearing in the browser bundle.
I guess there is some hidden logic that removes imports used in getStaticProps but unused in main export. I spent a few hours debugging until I could reproduce, maybe worth having a sidenote somewhere in the docs :)
Isn't the hidden logic just webpack's tree shaking? Makes sense when you think of it, Next doesn't import getStaticProps
in the browser bundle, so it removes the imported function used in it.
If you don't reference it anywhere, I guess webpack considers you imported it for side effects, so it still includes it in every bundle.
Isn't the hidden logic just webpack's tree shaking? Makes sense when you think of it, Next doesn't import
getStaticProps
in the browser bundle, so it removes the imported function used in it.If you don't reference it anywhere, I guess webpack considers you imported it for side effects, so it still includes it in every bundle.
No, webpack tree shaking is not sophisticated enough to shake these exports in that way. Tree shaking getStaticProps / getServerSideProps / getStaticPaths is handled by this custom Babel plugin we created: https://github.com/vercel/next.js/blob/canary/packages/next/build/babel/plugins/next-ssg-transform.ts
Oh thanks for the pointer, looks like I overestimated webpack :)
Any reason this would be happening from _within_ getServerSideProps
?
Hi all. Like @aloukissas I have the same issue when using dotenv
within my index.js
getStaticProps()
. It gets solved when adding the next.config.js
file as shown in @Timer initial comment.
Any clues why is this happening? I'm unsing Next.js
v.9.4.0
Thanks!
I had this error while using fast-glob
.
I used this great tool to understand the code that gets bundled in the client-side.
Turned out, I was importing a variable from a file that uses fast-glob
which internally uses fs
but I wasn't using the variable anywhere inside getStaticProps
so the files imports fast-glob
weren't getting eliminated.
An example:
import glob from 'fast-glob'
import path from 'path'
export const BLOG_PATH = path.join(process.cwd(), 'posts')
export const blogFilePaths = glob.sync(`${BLOG_PATH}/blog/**/*.mdx`)
import { BLOG_PATH, blogFilePaths } from './mdxUtils'
export const getStaticProps = () => {
const posts = blogFilePaths.map((filePath) => {
...
}
return { props: { posts } }
}
As you can see I am not using BLOG_PATH
anywhere in index.js
but still importing it. I am only using blogFilePaths
so it gave me this error.
For more context โ https://github.com/vercel/next.js/discussions/17138
Thanks @deadcoder0904 this is my code:
import Layout from '../components/template'
import Main from '../components/main'
import Menu from '../components/menu'
import 'dotenv/config'
export async function getStaticProps () {
const avatarLocation = process.env.AVATAR_URL
const avatarTitle = process.env.AVATAR_TITLE
return {
props: {
avatarLocation,
avatarTitle
}
}
}
export default function RenderMainPage ({ avatarLocation, avatarTitle }) {
return (
<Layout
avatarURL={avatarLocation}
topLeft={<Menu />}
middle={<Main avatarURL={avatarLocation} avatarTitle={avatarTitle} />}
/>
)
}
The tool you mention shows import 'dotenv/config'
is included in the client code, and probably that is making the error appear. The thing is that I need it to read from the env variables.
Probably there's another better way to do it, I'm still learning Next.js :)
@ig-perez As of Next v9.4, they have a built-in way to load environment variables โ https://nextjs.org/docs/basic-features/environment-variables
I suggest you read the docs to find the solution :)
That is awesome, I missed that part in the docs, thanks! I'll update my code ๐๐ฝ
Most helpful comment
Update for modern Next.js (9.4+)
You can safely use
fs
withingetStaticProps
orgetServerSideProps
, no extra configuration required. Be sure you're referencing the variable in your data lifecycle so it's correctly tree shaken away.You can use this tool to learn visually how it works!
If you're still building on a legacy Next.js version with
getInitialProps
, read below ๐The provided code is not valid -- this file would never be available on the client side during rendering:
https://github.com/TidyIQ/nextjs-issue/blob/aef67b12d91d299d0978550005a40cbb34f74b71/pages/index.js#L5
Remember, you can only do FS-related operations while _on the server_. This means you cannot use
fs
while rendering.If you use
fs
, be sure it's only withingetInitialProps
.You may also need to create a
next.config.js
file with the following content to get the client bundle to build: