The final step: How to package a Node.JS application as an exe
Published: 2021-01-04 16:48:29

“To a man with a hammer, everything looks like a nail.” — Twain/Maslow/Kaplan/Baruch/Buddha/Unknown.

We all have our go-to tools; that language, framework, and/or IDE that we swear we can do anything with. Personally, I enjoy pushing the limits of whatever tool or programming language I use at the time. Currently, JavaScript is my hammer, and I hit everything with it. 

I was recently asked to build a "simple app" that did some administrative tasks. As with most things lately, I decided to use JavaScript to build it and only found out at the end of my development that I was expected to deliver this app as a .exe file to run on windows. Now that I had written all the wonderful Node.JS code, I had to answer the question: how do we package our application share it as an executable. 

There are numerous online resources aimed at teaching you how to build a Node.JS application. This is great since node, especially when reinforced with the myriad of open-source packages you can add with npm and yarn, is a great way of building applications of varying sizes and complexities. 

JavaScript is most commonly used for web development. Since sharing our creation on the web is such a common part of the web development ecosystem, we have a lot of hosting services that package and run our Node.JS code, leaving us only with the responsibility of giving them our code.

What happens when we need to build a simple application that runs on a custom server somewhere? Most developers that use languages like Java and the c-family languages will simply go for building an executable programme from their code so that the application is self-contained and they don't need to share their actual code. JavaScript developers, how do we go about doing this; how do we build an executable from our Node.JS code without containerization?

## PKG

The first option is to use [pkg](https://www.npmjs.com/package/pkg). It is a command-line interface that enables the developer to create executables from Node.JS projects; allowing you to run the app even on environments that do not have Node.JS installed on them. Use cases include being able to share your app without sharing your source code thereby equipping you to create cross-platform commercial and demo copies of your application without needing to re-code the entire application or install dependencies on the machine that runs the application.  

## Getting started
To install pkg
`npm install -g pkg 
`
To check if the pkg is correctly installed, you can run the following command: `pkg`.

Most people have the entry point of their Node.JS application as an index.js file. If you build a package with no configuration, it will name your executable index.exe which is not a very meaningful name. I would, therefore, advise that you give this file a more meaningful name, like 'lucky-example-node-executable.js' but since I'm lazy to retype this name in the rest of the article, I'll call my example file 'lene.js'. With lene.js as the entry point to my Node app, I can package my app by running the following command:
`pkg lene.js
`
Running the above command will generate three programmes; namely an executable for Windows, macOS, and Linux as shown in the image below:
![pkg output](https://dev-to-uploads.s3.amazonaws.com/i/qe8zx6u9gi2tjsr0q5ux.png)
As shown in the above image, the command generates files that are aptly-named in accordance with the target platform of each programme.

Suppose you only need to run your programme on one platform, say a windows server. Then packaging your app for all three targets would not necessarily make sense or be a good thing to do. In this instance, you can specify your target platform using the following command:
`pkg -t <targets> <programme-entry>.js`
where `<programme-entry>.js` is the file name of the entry point into your Node project. In our example here, the file name is `lene.js.`

`<targets>` is a comma-separated list of target platforms that follow a specific 3-part format. Each part specifies different platform attributes that help tell pkg how exactly to package our app. These attributes are `nodeRange-platform-architecture`. The first specifies the version of Node to be used by your application and specified as `node${n}` or `node latest` to use the latest available LTS version of Node. The second is the platform, specified as one of the following supported strings: 
- freebsd, 
- linux, 
- alpine, 
- macos, 
- win.

and the last part is the target architecture namely x64, x86, armv6 or armv7.

So `pkg -t node12-linux,node10-win-x86 lene.js` will fetch the necessary dependencies required to package the application and use node version 12 to build a Linux executable and then Node version 10 to build a Windows x86 executable. 

This is a quick start guide to using pkg. This was the most beginner-friendly solution I could find. For a simple application, you need almost no further configuration. The only extra work you might need is if you import dependencies based on variables. In this scenario, you would have to specify the files - scripts and assets - manually in pkg property of your package.json file in order for them to get packaged with your application code. 

Pkg is only one of a number of ways to do this. I also found [Nexe](https://github.com/nexe/nexe) which is also a command-line utility that compiles your Node.js application into a single executable file.

Let me know what you think of pkg and if you'd like to make a comparison of pkg and nexe. Do you have any other similar tools that I can look at? Please let me know in the comments section. 

I hope you found this article useful.