使用 electron-builder 时 SpawnSync 不起作用

SpawnSync doesn't work when using electron-builder

我正在编写一个 react-electron 应用程序,我注意到当我使用 electron-builder 构建它时,二进制文件在调用“spawn”时卡住了。

使用“yarn start”可以毫无问题地执行应用程序。只有 electron-builder 才会卡住。

你能帮忙吗?

谢谢,

更新

作为程序的一部分包含的 C++ 二进制文件似乎无法在 electron 中执行。如果我给出二进制文件的硬编码完整路径,它就可以工作,但是如果我给出 __dirname 的路径,我会得到一个错误

const GetLocalPath = () => {
  const path = __dirname + "/../cpp_program/"

  return {
    helloWorld: path+ "helloWorld",
    helloWorldRepeat: path+ "helloWorldRepeat"
  }
}

export function helloWorld(){
  // let dir = "/Users/Rick/projects/lala/github/tutorial/electron-tutorial-app/cpp_program";
  let comm = GetLocalPath().helloWorld;

错误信息

internal/child_process.js:403 Uncaught (in promise) Error: spawn ENOTDIR
    at ChildProcess.spawn (internal/child_process.js:403)
    at Object.spawn (child_process.js:562)
    at helloWorldRepeat (/Users/ricky/proje…ar/build/Lib.js:113)
    at Object.<anonymous> (/Users/ricky/proje…sar/build/Lib.js:49)
    at Generator.next (<anonymous>)
    at /Users/ricky/proje…asar/build/Lib.js:9
    at new Promise (<anonymous>)
    at __awaiter (/Users/ricky/proje…asar/build/Lib.js:5)
    at Object.handleInitialize (/Users/ricky/proje…sar/build/Lib.js:35)
    at TestStateMachine.transition (/Users/ricky/proje…tStateMachine.js:56)

这很奇怪,因为它适用于“yarn start”,即“tsc && electron”

package.json如下图

  "scripts": {
    "start": "tsc && electron ."
  },
  "build": {
    "appId": "com.example.myapp",
    "productName": "MyApp",
    "files": [
      "build/**/*",
      "public/**/*",
      "src/images/**/*"
    ]
  }, 

更新版本 2

根据亚历山大的建议,我已经包括在内

"asar": false

里面package.json

当我执行它时,我得到一个不同的错误

Uncaught Error: spawn /Users/Rick/projects/lala/github/tutorial/electron-tutorial-app/dist/mac/MyApp.app/Contents/Resources/app/build/../cpp_program/helloWorldRepeat ENOENT
    at Process.ChildProcess._handle.onexit (internal/child_process.js:269)
    at onErrorNT (internal/child_process.js:465)
    at processTicksAndRejections (internal/process/task_queues.js:80)
errnoException  @   internal/errors.js:510
ChildProcess._handle.onexit @   internal/child_process.js:269
onErrorNT   @   internal/child_process.js:465
processTicksAndRejections   @   internal/process/task_queues.js:80

现在的错误是 /Users/Rick/projects/lala/github/tutorial/electron-tutorial-app/dist/mac/MyApp.app/Contents/Resources/app/build/../cpp_program/.

中没有“helloWorldRepeat”文件

二进制文件实际上位于

/Users/Rick/projects/lala/github/tutorial/electron-tutorial-app/build/../cpp_program/helloWorldRepeat

我是否必须手动创建此文件夹并粘贴二进制文件?

默认情况下,Electron Builder 会编译您的应用程序并将所有资源打包到一个大型存档文件中(将其视为 ZIP 文件),该文件可以很好地读取,因为 Electron 支持这种称为“ASAR”的格式。

当运行编译生成的程序时,将从存档中读取代码。这意味着 __dirname 将指向存档内的目录。但是,操作系统无法从存档中读取。由于您实际上并没有包含调用 child_process.spawn () 的代码片段,我只能推测为什么您会得到 ENOTDIR,这暗示给定路径不是目录,但它应该是一个目录,但是我假设这是因为您指向 ASAR 文件中的路径。

当依赖外部二进制文件时,最好将它们保存在 ASAR 存档之外并以编程方式找到它们的路径(这非常复杂)或阻止 Electron Builder 将您的应用程序编译成 ASAR 文件。但是,您还必须要求 Electron Builder 将可执行文件包含在您的应用程序的构建版本中。这可以通过修改 package.json:

来完成
{
    ...
    "build": {
        "appId": "com.example.myapp",
        "productName": "MyApp",
        "files": [
            "build/**/*",
            "public/**/*",
            "src/images/**/*"
        ],
        "extraResources": [
            "cpp_program/*"
        ]
        "asar": false
    },
}

(将 "cpp_program/*" 替换为与您所需目录匹配的任何路径模式,如果有子目录,甚至可以将 /* 替换为 /**/*。)

这样,目录 cpp_program 将在构建时被复制到您的应用程序的资源目录中。根据 Electron Builder's documentation,这条路径在 MacOS 上是 Contents/Resources/。因此,您将不得不修改您的路径(__dirname + "../" 将不起作用,因为它将指向 Contents/Resources/app,但 __dirname + "../../" 应该;如果不是,试验将导致正确的路径)*。每次您的 C++ 可执行文件更改时,请记住 运行 Electron Builder,因为 .app 文件夹中的文件未链接到构建应用程序之外的对应文件。


* 您可以通过检查 __dirname.includes (".app/")