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

时间:2018-09-01 06:47:35

标签: 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',
  },
}

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

这会在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

我在做什么错了?

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

1 个答案:

答案 0 :(得分:0)

tl;博士

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

说明

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

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

如果我们检查整个 fsevents-handler.js 模块在主 index.js 文件中的使用方式,我们可以看到它们 check if they can use this module 通过 FsEventsHandler.canUse()save it to opts.useFsEvents、然后每次他们想使用该模块they check that option

canUse 函数是 implemented this way

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

因此,如果我们有一个模块返回虚假信息,那么通过 fsevents 变量将禁用整个模块(在 Linux 上应该是默认设置)。

解决方案

在我创建了下面章节中描述的(现在是替代的)解决方案之后,vinceau 想出了一个更简单的解决方案:您可以告诉 Webpack 基于正则表达式槽 {{3} 忽略 require }}。这样您就不必模拟模块,因此库中的 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 中,这可以通过 IgnorePlugin 完成。我们还添加了一个条件,因此我们不会在 fsevents 可用的 OSX 上执行此操作:

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

module.exports = {
  resolve: {
    alias: {
      ...optionalAliases,
    },
  },
};