Electron crashes when requiring sqlite3 native module in forked process

感情迁移 提交于 2021-02-10 03:58:39

问题


I'm trying to use sqlite3 module in a child process with electron, but I get error of undefined symbol. Also, the error happens only when I run the program from electron's node.js, but when I run the program from usual node.js everything works fine. I think the problem may be related to 'nativeness' of sqlite3 module, and I tried electron-rebuild, npm --build-from-source, they didn't help.

main.js:

const { fork } = require('child_process');
fork('fork');

fork.js:

const sqlite3 = require('sqlite3');

package.json:

{
  "name": "bugreproduce_sqlite",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "sqlite3": "^4.0.2"
  },
  "devDependencies": {
    "electron": "^3.0.5"
  }
}

output:

> ./node_modules/electron/dist/electron .
/home/myuser/Programming/javascript/bugreproduce_sqlite/node_modules/electron/dist/electron: symbol lookup error: /home/myuser/Programming/javascript/bugreproduce_sqlite/node_modules/sqlite3/lib/binding/node-v64-linux-x64/node_sqlite3.node: undefined symbol: _ZN2v816FunctionTemplate3NewEPNS_7IsolateEPFvRKNS_20FunctionCallbackInfoINS_5ValueEEEENS_5LocalIS4_EENSA_INS_9SignatureEEEiNS_19ConstructorBehaviorENS_14SideEffectTypeE

回答1:


I found the root problem. Here is the relevant issue and pull request 1, pull request 2 on GitHub.

My steps to temporarily fixing the problem were:

  • Clone node-pre-gyp git repository
  • checkout to the version sqlite3 wants(0.10.3 at the moment)
  • Apply patch from the second pull request
  • Install this patched node-pre-gyp via npm install ../path/to/patched/node-pre-gyp from the main project folder
  • npm i --build-from-source sqlite3(not sure this command is needed) and ./node_modules/.bin/electron-rebuild from the main project folder (I installed electron-rebuild)
  • call fork with electron version set, like this:

    fork('fork', [], { env: { ELECTRON_VERSION: "3.0.5" }});

This is a hack, but it seems to work. Hope the problem will be fixed in upstream.

edited: fixed pull request link (I used the second pull request, not the first)




回答2:


I fixed the same problem by:

  1. Updating Electron to v6 Beta. Version 6 has the needed feature of adding process.versions.electron to get the Electron version in forked processes.
  2. Using electron-builder's "install-app-deps" command as a postinstall script. That means putting "postinstall": "electron-builder install-app-deps" in my npm scripts in package.json.

As to why the issue happens:

  • node-sqlite3's main module uses node-pre-gyp to figure out which compiled sqlite binary to require
  • node-pre-gyp tries to detect the process runtime to return the path to the correct binary for the process/platform.
  • node-pre-gyp's detection function (get_process_runtime in versioning.js) looks at process.versions.electron to see if the process is an Electron process. Otherwise it assumes a Node process.
  • Since process.versions.electron was not implemented in my version of Electron (v5) for forked processes, node-pre-gyp assumed a Node process and returned a path to node-v70-win32-x64 which didn't exist because the node version I use to npm install node-sqlite3 is different from the node version that the forked process reports to node-pre-gyp. I did have node-v67-win32-x64 in my node_modules/sqlite3/lib/binding directory.
  • Thus, although electron-builder correctly created electron-v5.0-win32-x64 in node_modules/sqlite3/lib/binding, node-pre-gyp returned node-v70-win32-x64 to node-sqlite3 and of course the module couldn't be found. The final piece was therefore to update to Electron v6 which reports the Electron version to forked processes, allowing node-pre-gyp to detect an electron process and return the correct path to the binary that electron-builder created, in this case node_modules/sqlite3/lib/binding/electron-v6.0-win32-x64.



回答3:


Just my two cents since these issues can be very time consuming: I am also forking a process which depends on sqlite3 from an electron app.

The way I have it set up and working is as follows (Electron v8.0.1):

There are two project folders, "parent" and "child". Parent is the electron project with main and renderer code.

In the parent:

  1. Include as a devDependency: electron-builder
  2. Add as a postinstall script electron-builder install-app-deps
  3. If this is immediately after adding electron-builder, run postinstall manually. In the future it's run automatically after npm i

This should take care rebuilding sqlite3 against electron.

Now to get the child process to use that lib.

  1. The child process development depends on sqlite too, so just install that locally
  2. I bundle all my js files using webpack
  3. To have webpack working for the backend, I add
externals: {
    sqlite3: 'commonjs sqlite3'
  },

(In this way webpack doesn't attempt to bundle in sqlite3, which doesn't work with native modules.

Back in the parent:

I. Say the output bundle is called "child.js", copy it to the parent folder, and add it to the files attribute in the "electron-builder.json" file, e.g. files: ["!*.log", "!doc", ..., "child.js"]. Like this the child is added into the asar archive at the app's root. Don't use electron-builder's extraFiles/extraResources and try to fork the child like that, your child won't find sqlite3.

II. In the app's "main.ts" file, launch the child as

fork(path.resolve(app.getAppPath(), 'child.js')

This should do it, hope it's helpful to anybody.



来源:https://stackoverflow.com/questions/52897950/electron-crashes-when-requiring-sqlite3-native-module-in-forked-process

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!