I have a macOS electron app that is based on this electron-forge Webpack + Typescript boilerplate, integrated with React, as documented here.
I'm able to spawn a binary node module in dev mode (yarn start) but not able to in production mode (yarn package).
A binary node module that is being spawned but not imported is not being packed by webpack.
In my code, I use the NodeJS spawn module to run a child process in the background. This child process is an installed dependency node module (btw it's @loadmill/agent npm package, but the problem could be applied to any package that is being called by a binary file, instead of a js file).
spawn('loadmill-agent', ['start', '-t', token])
But I don't explicitly import this package into the code. (i.e there is no
import '@loadmill/agent' line anywhere in the code)
It works well in development mode. When I run yarn start, the child process is spawned and I can communicate with it and all is well under the sun.
However, when I package the app and run the same line of code, I get an error.
Uncaught Exception:
Error: spawn loadmill-agent ENOENT
at Process.ChildProcess._handle.onexit (node:internal/child_process:282:19)
at onErrorNT (node:internal/child_process:477:16)
at processTicksAndRejections (node:internal/process/task_queues:83:21)
I searched a bit and found that I can debug spawned process errors in NodeJS like so:
spawn('loadmill-agent', ['start', '-t', token], {
env: { NODE_DEBUG: 'child_process', },
}
);
Now instead of the error popup dialog, I get the actual error output:
/bin/sh: loadmill-agent: command not found
Which means the command is either not installed, or not on the PATH, or not executable without a shell.
Furthermore, the @loadmill/agent node module was not even packed by webpack as a dependency. I know this because I don't see it in the dependencies of the packaged electron app contents/resources.
loadmill-agent node module is not being packed by webpack.spawned process outputs
/bin/sh: loadmill-agent: command not found@loadmill/agent.@loadmill/agent with-the-right-path-to-binary-file.
This issue can probably be resolved by configuring the PATH env var or by using the fix-path npm package.You can force the inclusion of files in the packaged app using the electron-forge/electron-packager option packagerConfig.extraResource.
There are alternatives to using extraResource if you want to get fancier, like manually scripting the copy of the files using one of Forge's hooks. Regardless of what method you use, you may need to include some logic in your app for where to find the binary depending on whether in development mode or packaged mode (e.g. using app.isPackaged and process.resourcesPath).
As to the larger question of why the binary is not being included in your app package, it must be a configuration error. Are you using .asar in your app package? Are you sure the loadmill-agent module is installed as a regular (non-dev) local dependency to your app? Meaning it's listed in your package.json under dependencies and located inside node_modules?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With