I'm using node.js and webpack to create a bundle. From what I've read, node.js should contain fs module for managing files. However when I call require("fs") I get an Cannot find module "fs" error. What should I do?
11 Answers
I came across this problem myself when bundling with webpack and found the answer on this thread.
The way to solve it for me was to use the following config:
module.exports = {
entry: "./app",
output: {
path: __dirname,
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.js$/,
exclude: 'node_modules',
loader: 'babel',
query: {presets: ['es2015']},
}
]
},
target: 'node'
};
By setting target to node webpack will make the necessary changes to bundle your node application
Edit: This answer targeted webpack 1.x which has now been superseded.
3 Comments
target: 'node' line is still important and what makes this work on webpack v4target: 'node' works, moreover, with webpack v5.88.2 the loaders strucutre has changed refer: webpack.js.org/concepts/loaders.If you are running your webpack bundle in nodejs environment then target: 'node' is required in webpack.config.js file otherwise webpack takes default value as web for target check here.
You can resolve the issue in two ways
Add below configuration to your webpack.config.js
node: {
fs: "empty"
}
OR
Add below configuration to your package.json
"browser": {
"fs": false
}
Edit:
promising fix is
"browser": {
"fs": false
}
4 Comments
Add below configuration to your webpack.config.js
resolve: {
fallback: {
fs: false
}
}
2 Comments
I had the same issue when bundling a NWjs application using webworkers (which in turn had node enabled).
The solution I found was to include each native module I used in externals with the prefix commonjs to the name of the module. For example:
...
target: "webworker", // or 'node' or 'node-webkit'
externals:{
fs: "commonjs fs",
path: "commonjs path"
}
...
I've done the same for targets "webworker" and "node-webkit" in different projects to solve the same issue.
Comments
I needed to build a class that would use fetch if executed in a browser, or fs if executed in node. For other reasons, it was impractical to produce separate bundles, so I produced a single browser-targeted bundle.
The solution I used was to use eval('require("fs")') if the script was running in node.
const fs = eval('require("fs")')
Browser-safe (fs is null in the browser):
const fs = typeof window === 'object'
? null
: eval('require("fs")')
Comments
After trying everything I found on the internet (target, externals, node configs), the only solution that actually worked for me was replacing:
const filesystem = require("fs")
or
import fs from "fs"
by the special webpack version
const fs = __non_webpack_require__("fs")
This generates a require function that is not parsed by webpack.
1 Comment
__non_webpack_require__ is..In addition to the answer of PDG
I'm used to this short copy/paste candy.
Using path and fs :
var nodeModules = {};
fs.readdirSync(path.resolve(__dirname, 'node_modules'))
.filter(x => ['.bin'].indexOf(x) === -1)
.forEach(mod => { nodeModules[mod] = `commonjs ${mod}`; });
// Before your webpack configuration
module.exports = {
...
}
Then inside your configuration file, include the nodeModules variable in the externals
...
externals: nodeModules,
...
Comments
It would be more elegant to use pre-defined solution as:
Adding target: 'node' to webpack config file.
More info on: official documentation
Comments
To be clear, I am not a pro node.js developer, just an unfortunate guy who is on frontend try to use somebody else's code.
you may have wondered why error occurs, obviously, node.js provides more than frontend, many opensource thereby integrite modules such as fs, path, for building backend approaches.
So how the heck can I ignore, you know the backend part of implementation, in order to get this work?
Option 1
nullify backend modules
add to webpack.config.js
resolve: {
fallback: {
fs: false,
path: false,
},
},
also add corresponding to package.json, otherwise you are likely to get a Filed 'browser' doesn't contain a valid alias configuration
"browser": {
"fs": false,
"path": false,
},
this will do if the dependency does not rely on the backend module, that means, not doing stuff like writing local file during runtime, and not accessing the prototype from any declared in that module.
Option 2
browserify polyfill
polyfill are basically a piece of code that fill the functionality gap, browserify provides object that stimulate that dependency's interface, with that help, in minified code, for example, if fs.readFile is called, it won't throw a undefined error, but the function would return null and continue to run.
resolve: {
fallback: {
fs: require.resolve("browserify-fs"),,
path: require.resolve("path-browserify"),,
},
},
you may notice the prefix browserify- and surfix -browserify are different, it's not a typo, depending on the module you actually need to search for a valid name on npm. here are some common names you can dirrectly use:
- browserify-fs
- browserify-zlib
- browserify-shim
- path-browserify
- stream-browserify
- crypto-browserify
here's a quick note, after plugin multiple polyfill, the production mode build may compile a file with enomous file size. you may wanna directly use development mode, though it writes tons of file.
Comments
I had a similar issue while using webpack to bundle a typescript project for a Cloud Run Function in GCP. The problem with the fs module breaking the build is common. I tried all the suggested solutions, but none worked for me.
If you're still having this problem, try this:
In your webpack.config file, add this line:
externals: [nodeExternals()]
This will exclude external node modules packages from the final bundled file.
When deploying, only upload your build file (e.g., index.js) along with the package.json. But before uploading, delete all the scripts in the package.json file.
i.e. the package.json should look something like this:-
{
"name": "abc",
"version": "1.0.0",
"description": "abc",
"main": "index.js", //this is important make sure this filename is the your bindles file name
"scripts": { delete everything inside here }, // add this in case some other failure - "clean": "npm clean cache"
"dependencies": {...}
"devDependencies": {...}
}
By default, GCP Cloud Run installs everything from the package.json file. If there are scripts, it will run them too, which can cause issues. That’s why you should remove them before uploading.
Hope this helps!