电子+Webpack = 找不到模块:错误:无法解析 chokidar/etc 中的 fsevents/fs/etc



我正在尝试创建一个Electron应用程序,但是许多node-libs会导致Module not found错误,即使对于electron-main目标也是如此。

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/主.js

const watcher = require('chokidar').watch('./dist')
watcher.on('change', function() {
console.log('change', arguments)
})

包.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"
}
}

这会在build期间产生错误:

WARNING in ./node_modules/chokidar/lib/fsevents-handler.js
Module not found: Error: Can't resolve 'fsevents' in '.node_moduleschokidarlib'
@ ./node_modules/chokidar/lib/fsevents-handler.js
@ ./node_modules/chokidar/index.js
@ ./src/main.js

我做错了什么?

PS:添加node: { fsevents: 'empty' }无济于事。

tl;博士

告诉 Webpack 通过IgnorePlugin忽略该require

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,
],
};

解释

问题来自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);
}

我的猜测是,由于它是一个require,Webpack 试图解决它,即使在 Linux 上它不存在。这就是为什么它在try...catch块中的原因,因为它在 Linux 上运行时会失败,并且他们以这种方式处理它。可悲的是Webpack(偶尔?(对此有问题。

如果我们检查整个fsevents-handler.js模块在主index.js文件中的使用方式,我们可以看到他们检查他们是否可以通过使用此模块FsEventsHandler.canUse(),将其保存到opts.useFsEvents,然后每次他们想使用该模块时,他们都会选中该选项。

canUse函数是这样实现的:

const canUse = () => fsevents && FSEventsWatchers.size < 128;

因此,如果我们有一个返回虚假内容的模块,那么通过fsevents变量,整个事情将被禁用(因为在 Linux 上默认情况下应该是这样(。

溶液

在我创建了下面章节中描述的(现在是替代的(解决方案之后,vinceau 提出了一个更简单的解决方案:您可以告诉 Webpack 忽略require基于正则表达式槽IgnorePlugin。这样你就不必模拟模块,因此库中的require将按照作者最初的预期工作(失败(。所以只需添加插件:

module.exports = {
plugins: [
new IgnorePlugin({ resourceRegExp: /^fsevents$/ }),
],
};

这将忽略每个操作系统上的require,但这不应该在 OSX 下发生,因此最好检查平台并仅选择性地添加它:

const optionalPlugins = [];
if (process.platform !== "darwin") { // don't ignore on OSX
optionalPlugins.push(new IgnorePlugin({ resourceRegExp: /^fsevents$/ }));
}
module.exports = {
plugins: [ ...optionalPlugins ],
};

替代解决方案

我们可以创建一个模拟模块,它将返回一个虚假的默认值(也添加一些注释来解释这种情况(:

// 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

让我们将其保存到名为fsevent.js的项目根目录(您可以随意调用/放置它(,然后配置 Webpack,因此当它尝试解析fsevents时,它将返回此模拟模块。在 Webpack 5 中,这可以通过解析别名来完成。我们还添加了一个条件,因此我们不会在fsevents可用的 OSX 上执行此操作:

const optionalAliases = {};
if (process.platform !== "darwin") {
optionalAliases['fsevents$'] = path.resolve(__dirname, `fsevents.js`);
}
module.exports = {
resolve: {
alias: {
...optionalAliases,
},
},
};

相关内容

最新更新