How to bundle a third party binary with Electron? - node.js

I am still new to the electron ecosystem and desktop development in general but what I wish to do is to interface with a third party, open source application that comes bundled in with my software. First, I am unsure on what the package options to distribute should be. Is it customary to have two downloads, one for users that already have the third party binary installed, and another one that includes it? Also how do I go about actually packaging, and installing the binary? Should this be an option on my package.json? What kind of script should I execute? Are there any npm modules to facilitate this?
edit - is it possible to invoke npm from my main.js even though a user has not previously installed node? I know node is bundled with the electron package but is npm too?
-The binary in this case is PostgreSQL

There are a couple of options coming to my mind.
Bundle a 3rd party installer w/ your app. This is what I did recently. On the first run I check if the service that I need is installed / running and if not I call the 3rd party installer / start it. When the installer quits I simply app.relaunch() and start consumig it. Of course you'll need installers for each platform you plan to support. And you'll have to figure out ways to check if the software is installed (properly) for each platform.
Bundle binaries w/ you app. Of course you can bundle pretty much anything w/ your electron app. Again, you'll need binaries for each platform you plan to support. And of course they shouldn't be linked to anything that the default user doesn't have on his machine like SDKs and additional headers ...
Less comfy but you can alway add some start-up message or before-download massage telling the user that he needs software xy in order to run your application.
Derivate of 1/2: Download required stuff on demand. For your example this would mean checking the user's OS and arch and then just download the required installers or binaries if available. You could also build the stuff on the user's machine although this probably being the worst/biggest/most complex solution.
Then there's things like https://www.npmjs.com/package/pg - you should always check npm if someone already built what you need ;)
I'd recommend using the great electron-builder which makes bundling stuff w/ your app a piece of cake.
Feel free to comment if you need more intel.

Related

How can I restore node modules for multiple platforms?

My Node application needs to be deployed on Windows and Linux. The main deployment package is built on a Linux CI server.
When this package is deployed to Windows, it crashes immediately due to missing native bindings, such as those for sqlite. Only the bindings for the build platform (Linux) are restored.
With a deadline approaching, we just set up a Windows build configuration which outputs a Windows specific package that contains the appropriate bindings, and we choose the appropriate artifact to bundle in the installer.
This works but feels fragile, as we would need to keep the Node versions in sync between the two otherwise unrelated environments. I would like to be able to do this with a single build configuration.
I couldn't find any guidance on how this is done. I'm imagining a command-line option like --platform=windows to npm ci, or a modification to package.json but I couldn't find any information about this. Presumably this is a reasonably rare requirement, and perhaps there is no tooling around this, which would be a shame.
Another requirement is that the application must be installed without an internet connection. We cannot run npm ci or npm install when we install it as some of our clients do not permit their servers to access the public internet.
Based on your requirements it sounds like building a package on each required platform would be the safest bet, with the least number moving parts to go wrong.
As the comments have suggested most projects rely on an npm install on the required platform so you are stepping into not that common territory.
This works but feels fragile, as we would need to keep the Node versions in sync between the two otherwise unrelated environments. I would like to be able to do this with a single build configuration.
Node uses NODE_MODULE_VERSION (displayed on the releases page) to track ABI compatibility for native modules. This only changes with a new major Node release number.
The CI builds would need to create app packages for each major version of Node you run on each platform. Keeping the Node.js major versions in sync for the application a good thing in any case. Running Node N and N-1 builds until that can be achieved is good cover and probably the best option with the air gap requirements.
NPM Cache
If the air gapped clients are largely on common networks, an NPM cache/proxy (nexus/verdaccio) may be of use. The NPM cache will need a process to snapshot the repo after a production npm install on all required platforms, to be pushed out to your endpoints. Unfortunately binary modules are often distributed out of band from NPM so won't be stored in regular NPM caches. Each client instance will need a complete build environment to build any native modules from source which can sometime present it's own difficulties on Windows platforms.
Alternatives
Node.js is not a great platform for distributing packaged applications to many diverse clients, especially if you need to distribute Node itself. Any language with an external VM requirement presents difficulties. Nodes package management choices and reliance on native modules exacerbate this.
I've given up in the past and converted clients (albeit thin) to Go, as it lends itself to cross platform distribution a lot better by removing the external runtime requirement and having less variables.

Packaging Software Ideas

We have a migration tool to migrate the customers data between different applications. I am looking for ideas to make it very easy for the customer to use this tool. Right now they invoke shell scripts with some options and get the data dump, but I want to make this even more easier for the end customer. Tool is written in nodejs
pkg could be what you're looking for.
From the package description:
This command line interface enables you to package your Node.js
project into an executable that can be run even on devices without
Node.js installed.
Use Cases
Make a commercial version of your application without
sources
Make a demo/evaluation/trial version of your app without
sources
Instantly make executables for other platforms
(cross-compilation) Make some kind of self-extracting archive or
installer No need to install Node.js and npm to run the packaged
application No need to download hundreds of files via npm install to
deploy your application. Deploy it as a single file Put your assets
inside the executable to make it even more portable Test your app
against new Node.js version without installing it

NodeJS app for end-user distribution

I'm looking for the proper way to distribute/deploy a node.js app that would run as a small webserver on the user's machine.
Is there a stub method or install script or a "install wizard" that would download all node_modules dependencies, download the latest nodejs binary, set up the environment, etc... or I have to distribute it bulk with everything packed? Is there any guide for that purpose?
Edited :
You could install node and npm, download your dependencies by running npm install in the command line (first declare them within your package.json) only then users can run your script. This is how you do development in Node.js, or deploy to a development server. See using npm. You could automate that with a shell script if that is what you are after.
However, when distributing programs to end-users that might not be the best approach. Linux users are used to a package (.deb for instance) and Windows users are used to an .exe or a setup wizard.
That is why I recommended the tools below. I also assumed you were targeting Windows as this is less of a problem is unix-like environments.
If you want a single file (.exe), pkg and nexe are made for that purpose. These Node.js tools are used by the developer to compile JavaScript code into a single executable binary that is convenient for end-users and Windows deployment. The resulting .exe file is very light and does not require node to be installed on the end-user’s computers.
Electron along with electron-packager can produce setup wizards, but it installs a lot of files even for the smallest program. Your program will include all of node and webkit, that is why it produces heavy installs.
NSIS can also create a setup wizard, it is simple and does common stuff well (copying files, running shell scripts).
Original answer:
Short answer is: not really.
You have to keep in mind that Javascript is and has always been interpreted, so until recently never compiled to binary as you might do with other languages. Some exploration has been going on, but essentially you won’t get a "good practice" answer.
The long answer is, maybe, for some limited use cases:
There is the fresh new pkg that does exactly this, and it looks promising.
There has been nexe for a while, it works great for some use cases (maybe yours). Native/compiled modules are still an issue however.
Electron might work for a full blown app with a significant user interface, but it is not light or compact.
You could always use browserify to concatenate and uglify all your code with the modules you use and then make an installer with something like NSIS to setup node and your script. Native modules would still be a problem however.

Electron as a PPA

I've been doing some research: You can't build PPA's from a Node.js application.
Apparently, this is not a rule, since there are a few projects that have successfully achieve this. WebUDP8 is an example; they build the PPA's for Atom IDE (using Electron) & Popcorn Time (using Node-Webkit)
I did what any human being would do: bother these guys, since there's no documentation (or at least, none that I found).
Their answer:
Launchpad PPAs don't support nodejs yet because they don't allow
fetching external resources. So the Popcorn TIme PPA used to be a
simple installer that automatically downloaded Popcorn Time from its
servers. But, as far as I'm aware of, I'm not using external
resources. It's not like I am downloading dependences from the
package.json. They are all --saved in the folder to build.
How can I make a PPA of my Electron App?
Does the Software Center work with PPA's as well, or only .deb's?

Provide Node.JS webapp "key in hand"

I am building a simple Node.JS application for a client. The webapp should be easy to deploy on each server instance (which are RedHat EL 6.3), "key in hand".
What is the best way to package a Node.JS app? Basically, I need an "installer" or "package" to:
Install Node.JS
Install the dependencies (npm install)
Populate the application files (CSS, JS, HTML, etc.)
You should deliver a self-contained package. Please check out the great site The Twelve-Factor App, specifically the build, release, run section. There is a lot of hard-won wisdom from experienced operations engineers embodied in that site.
In your app's repo, write a script (shell, node, whatever) that can generate a distributable archive
RPM or tar archive are the 2 most sensible choices for you. tar is more portable and simpler. RPM would integrate nicely with an RPM-based distribution. I would recommend starting with tar if you have not done a lot of software packaging/management work. RPM is significantly more complex than tar.
The tar archive should embed the node.js files within it. This will make your app easy to install and avoid sharing a system-wide node install thus creating artificial coupling. If you go the RPM route, you can specify node as a dependency in your RPM spec file (but you probably shouldn't - see below).
The archive should embed all of the npm dependencies as well. Don't run npm install at package install time. Consider using the npm shrinkwrap tool to manage your dependencies during development, but at deployment time they should be pre-bundled and ready to run.
Specifically, these are bad ideas you should avoid:
Do not download anything from the Internet during installation. This is brittle, slow, and potentially can throw you bad surprises including security problems
Do not build artifacts at install time that can be built at build time. So ship pre-build CSS files, requirejs optimized files, pre-compiled binaries, etc.
As to whether your application RPM should list node.js as a dependency or embed node into the RPM, here are some points to consider.
Embed node.js into your RPM
Single .rpm file to distribute
Allows your application to tightly control the node version it uses. (see below)
Higher reliability. The fact is your app is probably coupled fairly tightly to at least the minor version of node.js you develop on (0.8.x for example) or even a patch release (>= 0.8.12 < 0.9 for example). It's best to allow node.js to decouple your app from the OS, but don't be fooled into thinking your app will work reliably on a different version of node.js without testing & adjustment. Most commonly these days there's just 1 app running on the OS, and the notion of sharing node between apps incorrectly values conservation of disk space over proper decoupling and operational independence of applications.
It's unclear whether there are any official/reliable pre-built RPMs out there in yumland that will "just work".
Specify node.js as a dependency of your PRM
Follows the general philosophy of OS package management (avoid duplication, conserve disk space, etc)
RPM provides capabilities beyond TAR around inventory management, uninstallation, upgrade, etc. Since you are asking this question, you are probably not ready to address these properly yet, so you might want to start with tar and once you have a solid understanding of that, consider RPM upgrade scripts, etc.
The "single file to distribute" nice point can quickly become untenable once your app starts using a database or 3, supporting daemons for email, log aggregators, etc.

Resources