PhantomJS from Node on Windows

2019-07-19 10:42发布

问题:

I have written a Electron application using Node, Electron Boilerplate, and phantom. It works perfectly fine for me on my linux machine, I copied the source over to Windows 10, and ran with npm start, and all goes smoothly.

However, when I try to build the application with the boilerplate module using npm run release, things go a little less smoothly. I can install and open the application just fine, but when I click the button that activates the phantom module, the windows goes all white and nothing happens. I was able to logs some errors with the dev tools.

First, I have:

C:\...\dist\win-unpacked\resources\app.asar\node_modules\phantom\lib\phantom.js:361
Uncaught (in promise) Error: Error reading from stdin: Error: write EPIPE(…)

I did some research into similar issues, namely here, and it seems to me the issue is starting the child process, PhantomJS, with the npm module phantom. Originally, I was using a WPF application I wrote in C# to start the process, and that worked just fine. This leads me to believe that the phantom module is the culprit.

So I tried swapping out the npm phantom module for horseman, but got similar results:

Unhandled rejection HeadlessError: Phantom immediately exited with: 4294967295
    at ChildProcess.immediateExit (C:\...\dist\win-unpacked\resources\app.asar\node_modules\node-horseman\node_modules\node-phantom-simple\node-phantom-simple.js:153:23)
    at ChildProcess.g (events.js:286:16)
    at emitTwo (events.js:106:13)
    at ChildProcess.emit (events.js:191:7)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:204:12)

回答1:

Here is a shot in the dark. I am not positive this will solve your issue but here it goes:

GYP and miss-matched binaries

Phantom and many other node modules use binaries built for the specific OS that it will be running on. Sometimes in your npm log files you will see references to node-gyp. Node-gyp simply helps to build native add-on's in node modules. When the binaries are built they are usually built against, among others, three main parameters, the operating system, cpu architecture and version of node that is doing the installation.

I think you need to rebuild phantomjs to the version of node Electron is using. Most of the time the node version you have installed on your machine and the node version running in Electron are not the same. Electron does its best to keep up, but there is always a little lag because of the amount of work and testing required to keep up-to-date.

When you install phantom by running npm install phantom it will assume it needs to install or build the binaries for the node version your machine is using. Then when your Electron app tries to run phantom it tries to call the binary of the Electron's node version. When it isn't there the child process immediately exits with an error.

How to fix

Luckily, there are other people out there that have figured out how to fix this issue and have created a great tool to help generate the correct binaries.

Enter electron-rebuild:

https://github.com/electron/electron-rebuild

Electron-rebuild can be run in the command line, and it will rebuild all of your native modules to the version of Electron your project is using.

To install:

npm install electron-prebuilt

To use (in Windows):

.\node_modules\.bin\electron-rebuild.cmd

This should be enough to put the correct binaries in the right place.

Other thoughts

Sometimes you can use a package that uses a dependency called node-pre-gyp. E.g. sqlite3. There is a known issue I ended up running into when trying to rebuild my packages for Electron. Basically, in order to avoid this issue (if you run into it) just append --pre-gyp-fix to the above command.

Tangent for those who run into the pre-gyp-fix issue

One more thing on the pre-gyp-fix: If one or more of your dependencies depends on one of the modules that need the pre-gyp-fix then they will be looking for the binary in the wrong place even if they are running in Electron. All of the pre-gyp binaries are stored in a folder similar to this:

.\node_modules\sqlite3\lib\binding

In my current project I have three folders here, one for Electron-v1.4, and two for node-v46 and node-v50. (hack alert) In order to have sqlite3 work with my other dependencies I copy the binary found in the Electron-v1.4 folder and put it in both node-v* folders. That way when running in Electron, all dependencies are running the correct binaries even though they are looking for them in the wrong place. (end hack alert)

Conclusion

There is no way I can be sure this has anything to do with the issue you are seeing. But it is worth a shot to see if it fixes your problem. If not then at least I hope I can help someone else experiencing the same issues I ran into.