I'm trying to create an Electron app, but many node-libs causes the Module not found
error, even for the electron-main
target.
webpack.config.js
const path = require('path')
module.exports = {
mode: 'development',
target: `electron-main`,
entry: {main: `./src/main.js`},
resolve: {
extensions: ['.js'],
modules: ['node_modules', path.join(__dirname, 'src')],
},
output: {
path: path.resolve(__dirname, `dist`),
filename: '[name].bundle.js',
},
}
src/main.js
const watcher = require('chokidar').watch('./dist')
watcher.on('change', function() {
console.log('change', arguments)
})
package.json
{
"name": "test",
"version": "1.0.0",
"author": "I",
"private": true,
"main": "dist/main.bundle.js",
"scripts": {
"build": "webpack"
},
"devDependencies": {
"@types/chokidar": "^1.7.5",
"chokidar": "^2.0.4",
"electron": "^2.0.8",
"webpack": "^4.17.1",
"webpack-cli": "^3.1.0"
}
}
This produces the error during build
:
WARNING in ./node_modules/chokidar/lib/fsevents-handler.js
Module not found: Error: Can't resolve 'fsevents' in '.\node_modules\chokidar\lib'
@ ./node_modules/chokidar/lib/fsevents-handler.js
@ ./node_modules/chokidar/index.js
@ ./src/main.js
What am I doing wrong?
PS: Adding node: { fsevents: 'empty' }
doesn't help.
Tell Webpack to ignore that require
via IgnorePlugin
:
const { IgnorePlugin } = require('webpack');
const optionalPlugins = [];
if (process.platform !== "darwin") { // don't ignore on OSX
optionalPlugins.push(new IgnorePlugin({ resourceRegExp: /^fsevents$/ }));
}
module.exports = {
// other webpack config options here...
plugins: [
...optionalPlugins,
],
};
The issue comes from this line in lib/fsevents-handler.js
:
try {
fsevents = require('fsevents'); // this module doesn't exists on Linux
} catch (error) {
if (process.env.CHOKIDAR_PRINT_FSEVENTS_REQUIRE_ERROR) console.error(error);
}
My guess is that since it is a require
, Webpack tries to resolve it, even tho on Linux it doesn't exists. That's why it is in a try...catch
block, because it will fail when running on Linux and they handle it that way. Sadly Webpack (occasionally?) has problems with this.
If we check how this whole fsevents-handler.js
module is used in the main index.js
file, we can see that they check if they can use this module via FsEventsHandler.canUse()
, save it to opts.useFsEvents
, then every time they want to use that module they check that option.
The canUse
function is implemented this way:
const canUse = () => fsevents && FSEventsWatchers.size < 128;
So if we had a module that returned something falsy, then through the fsevents
variable the whole thing would be disabled (as it should be by default on Linux).
After I created the (now alternative) solution described in the chapter below, vinceau came up with a simpler solution: you can tell Webpack to ignore require
s based on a regex trough IgnorePlugin
. This way you don't have to mock the module so the require
in the lib will work (fail) as the authors originally expected it. So just add the plugin:
module.exports = {
plugins: [
new IgnorePlugin({ resourceRegExp: /^fsevents$/ }),
],
};
This will ignore the require
on every OS, but that shouldn't happen under OSX so it is better to check the platform and only add it optionally:
const optionalPlugins = [];
if (process.platform !== "darwin") { // don't ignore on OSX
optionalPlugins.push(new IgnorePlugin({ resourceRegExp: /^fsevents$/ }));
}
module.exports = {
plugins: [ ...optionalPlugins ],
};
We can create a mock module that will return a falsy default (also add some comments to explain the situation):
// mock module to prevent Webpack from throwing an error when
// it tries to resolve the `fsevents` module under Linux that
// doesn't have this module.
// see: https://stackoverflow.com/a/67829712
module.exports = undefined
Lets save this to the project root named fsevent.js
(you can call/place it however you like), then configure Webpack, so when it tries to resolve fsevents
it will return this mock module. In Webpack 5 this can be done trough resolve aliases. We also add a condition so we don't do this on OSX where fsevents
is available:
const optionalAliases = {};
if (process.platform !== "darwin") {
optionalAliases['fsevents$'] = path.resolve(__dirname, `fsevents.js`);
}
module.exports = {
resolve: {
alias: {
...optionalAliases,
},
},
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With