Shipping executables with your Electron app
My app, HTTPSLocalhost (The fastest, most secure way to handle local SSL), needed a local proxy server that listens to port 443 and redirects the traffic to a pre-configured port.
I wrote this server using Node’s http package and configured it to run using the command line. It was as simple as firing a shell and running the following command:
$ node proxyServer.js `/path/to/ssl/certs` `[{proxy: 'config1'}, {proxy: 'config2'}]`
On my local setup, I just had to exec the command and it worked. But this was an Electron app and shipping this as it is meant three things:
- The source of proxyServer would be visible to everyone using the app
- I was assuming that my script was capable of running on all versions of Node (which is very bold)
- I had to bundle
node_modules
folder with the app (which would drastically increase the build size)
So I started looking for other ways to go around this issue.
Converting Node apps to standalone executables with Pkg
For people who are not familiar with the JS ecosystem, Zeit is the company behind Next.js and Now.sh.
Pkg by Zeit is a tool that bundles a Node app into a cross-platform executable that can run without a Node installation. Mind-blown!
And packaging your app was as simple as:
$ pkg path/to/index.js
When I first saw this, I was a little skeptic. I have seen tools like these before and almost none of them work as advertised.
Pkg, however, exceeded my expectations. Not only it worked, but it was also able to produce a bundle of the proxyServer.js that worked without a Node installation and was only 49mb in size (including dependencies).
This is a serious contender for deploying Node web apps. Will surely consider this the next time I have a need to do so. It’s like jar
for Node.
Packaging the executable with electron-builder
After having built the executable and putting it insider build/executables
directory, I had to update my package.json to include this in the electron package output. This required me to add an extraResources
key to the build
configuration:
"build": {
...
"extraResources": [
"build/**/*"
]
}
The above copies everything inside build
to AppPath/Contents/Resources/build
. The path to Resources folder is available as process.resourcesPath
variable for MacOS builds. This might vary on other OSes.
I packaged my proxyServer, added yarn scripts to automate the task and hoped everything would work in the first go. Guess what, it didn’t.
Handling native addons (.node files)
My setup worked fine in dev mode but threw an error when built. The error basically meant that the system was looking for a .node
file and wasn’t able to find it.
After 3 months of research and giving up on the problem many times, I found this issue on Github: https://github.com/zeit/pkg/issues/343
And then I realized that the project Readme had this issue highlighted already. The solution was simple. Just put the .node file along with the executable and it would work.
# Excerpt from zeit/pkg Readme
Native addons (.node files) use is supported, but packaging .node files inside the executable is not resolved yet. You have to deploy native addons used by your project to the same directory as the executable.
After fixing this issue, the packaged app worked just fine. You can try it for yourself.
Hi, if you liked this article and want to stay updated, follow me on: Medium, Github or Twitter
You might also like:
- How to embed a database in your electron app
- A gluten free Electron React setup [ft. live reload]
- Introducing Eiphop — An electron IPC wrapper
- Fractal — A react app structure for infinite scale