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

J. *_*now 5 webpack electron

我正在尝试创建一个 Electron 应用程序,但是许多节点库导致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',
  },
}
Run Code Online (Sandbox Code Playgroud)

源代码/main.js

const watcher = require('chokidar').watch('./dist')

watcher.on('change', function() {
  console.log('change', arguments)
})
Run Code Online (Sandbox Code Playgroud)

包.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"
  }
}
Run Code Online (Sandbox Code Playgroud)

这会在以下期间产生错误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
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

PS:添加node: { fsevents: 'empty' }没有帮助。

tot*_*dli 3

太长了;博士

require通过以下方式告诉 Webpack 忽略它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,
  ],
};
Run Code Online (Sandbox Code Playgroud)

解释

问题来自以下行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);
}
Run Code Online (Sandbox Code Playgroud)

我的猜测是,由于它是一个require,Webpack 会尝试解决它,即使在 Linux 上它不存在。这就是为什么它在一个try...catch块中,因为它在 Linux 上运行时会失败,而他们就是这样处理的。遗憾的是 Webpack(偶尔?)在这方面存在问题。

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

canUse功能是这样实现的

const canUse = () => fsevents && FSEventsWatchers.size < 128;
Run Code Online (Sandbox Code Playgroud)

因此,如果我们有一个返回错误值的模块,那么通过该fsevents变量,整个事情将被禁用(Linux 上默认情况下应该如此)。

解决方案

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

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

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

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

module.exports = {
  plugins: [ ...optionalPlugins ],
};
Run Code Online (Sandbox Code Playgroud)

替代解决方案

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

// 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
Run Code Online (Sandbox Code Playgroud)

让我们将其保存到名为的项目根目录中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,
    },
  },
};
Run Code Online (Sandbox Code Playgroud)