JavaScript Executables

Corey Butler
The Startup
Published in
6 min readDec 6, 2020

--

Love it or hate it, JavaScript has become a prominent language beyond the browser. Node.js popularized the use of JavaScript development on the backend. The global JS community took it significantly further, leveraging Node and npm as a form of DevOps and code distribution. The next major wave, in my humble opinion, is greater emphasis on the use of JavaScript to produce executables.

What is a JS Executable?

A JavaScript executable is just a program written in JavaScript, then compiled to a runnable file. In other words, a .exe or .bin file (or no extension on macOS).

It has been possible to create executables for Node.js applications using community projects like node-windows/mac/linux, pkg, or nexe for a while, so the concept isn’t entirely new. These are all efforts maintained by the community (userland). While these types of efforts haven’t gone unrecognized, it’s always been more of an “add-on” experience.

Compiling With Deno 1.6.0

Deno 1.6.0 is/was scheduled for release on December 8th, 2020. It is notable for the inclusion of deno compile, a highly requested new feature for generating executables from your source code. While this is just the first release of several strategies, it marks an important milestone for the project. Deno is the first JavaScript runtime to support the creation of user-defined executables. This greatly reduces the amount of effort and third party tooling required to create executables.

The Impact of Executables

Currently, running JavaScript outside of a browser requires Node.js or Deno to be installed/available on the server/computer where the scripts will run. Executables are self-contained, so nothing needs to be installed beforehand.

This has particularly important ramifications for the creation of developer tooling and commercial software. Being able to ship a single executable can be a much simpler process than requiring users to have software pre-installed.

Consider the use case for Docker and containers. Containerization is a solid approach to development, but it still requires a runtime like Docker, podman, etc. That is a manageable hurdle for IT departments installing software on their servers, but it’s far more challenging for developers who ship software to individuals working on a workstation. It’s difficult to ship that great new FinTech app to your users if they also need Node or Docker installed to use it.

Fenix Web Server

Developing Applications as Executables

Some developers use tools like Electron for building applications with JavaScript. I’ve always liked Electron (built Fenix Web Server on it), but it isn’t a fit for every type of application. For example, many applications run as background services and do not need a dedicated UI. For these types of applications, Electron’s inclusion of a UI rendering system adds significant size to the application without adding additional value.

For applications like these, an executable is a slimmer and more manageable way to deliver software.

NVM for Windows

Developing CLI Applications

CLI (Command Line Interpreter) applications are a natural fit for the executable format. These types of applications are one of the purest forms of function, meaning they do something very specific.

With Deno 1.6.0, developers can create their own tooling without worrying much about runtime dependencies. Remember, executables are self-contained, so it does not matter if the runtime changes. For example, updating to a new version of Node.js (or downgrading) will not change the executable. End users do not need to do anything special to install prerequisites. They just download and run the application.

Challenges

The ability to generate an executable from JavaScript helps the language work in even more scenarios than it has before. After all, executables are a fundamental concept, one of the oldest in computing. Just because JavaScript can now be easily used as a source of “programs-without-runtimes” doesn’t alleviate the natural challenges which impact all executables.

  1. First, users do not always update their executables as frequently as developers would like. There are ways to administer automatic updates, but it is the responsibility of developers to create such a mechanism.
  2. Generating an executable is not a substitute for security. Do not make the mistake of thinking code which is compiled is impervious to malicious use.
  3. Installers can be hard to create. In a world where npm install has felt normal, developers will need a different way to distribute executables. Tools like homebrew and choco help, but distribution of commercial applications still have the same installation challenges.
  4. Runtimes like Node.js and Deno bridge many cross-platform gaps, but not all of them. Generating an executable does not alleviate these problems.

Summary

The announcement of deno compile is a big step forward for the use of executables. There will undoubtedly be some challenges for early adopters, but there will also be many benefits.

Update (Feb 20, 2023)

Node.js 19.7.0 ships this week with single executable application support (SEA). Node developers will now be able to produce binary applications from their scripts/projects.

Personal Use Cases

Articles like these can come across vague, advocating some so-called new way of doing things without much real life experience to support it. For a change of pace, I’d like to share some of what I’m working on and why I’m excited to work with the new deno compile feature.

As a quick caveat, CLI’s and executables definitely aren’t a new concept. They’re one of the oldest forms of computing. What’s new is the tooling used to create them. Most of my work with JS executables is a result of “back to basics” thinking, using proven fundamentals in practical modern ways.

A browser-based CLI for https://metadoc.io

CLI First Development

I’m excited by the deno compile feature because it aligns with my own flavor of modern software development, a CLI-First Development Strategy.

My explorations in this concept have led to the use of runtime-agnostic libraries, such as author/shell (a cross-runtime library for building CLI tools). This library helps bring an “executable-like” CLI experience to web applications, while still being able to rapidly produce Node-based CLI tools using the same/similar code base.

author/shell CLI running in the terminal (left) and browser (right)

The net affect of this approach is the ability to port application logic to different runtimes. Different experiences can be built upon the same core logic, even across different runtimes.

Historically, the challenge has always been working with build processes. A build process is required to produce the executable. As mentioned earlier, there have been ways to do this, but it usually required a separate DevOps build process of some kind. The deno compile feature brings this to the runtime, reducing the overhead for releasing a project and the “CLI First” strategy I’ve become fond of.

Broader Use of JavaScript

The Deno commitment to executables has provided an opportunity to rethink the architecture of non-web projects.

The most notable experience I recall is thinking about the original design of NVM for Windows, a version manager for Node.js. In the beginning, there were version managers which relied upon Node. This felt illogical, because the approach requires Node in order to install Node.

I chose Go, which doesn’t require a runtime and opens the door for compiling to other operating systems. At the time, I wished there were a way to use JavaScript, but the paradox of requiring Node to install Node was too big of a hurdle. The absolute hardest part of that choice was abandoning the vast catalog of battle tested JavaScript I’ve written. While I’m glad Go is a part of my personal toolkit now, I wish I’d learned it under different circumstances.

How JS executables changed my thinking…

As I work on rt (the NVM4W successor), I’ve started to reconsider the use of JavaScript for creating JavaScript tools. Executables offer a way to eliminate the JS runtime paradox and leverage prior work. The final verdict is still out for rt (more experimentation required), but the sheer fact there are new options with reasonable workflows make this an exciting time to be a developer.

Remember to clap if you want to see more articles like these.

--

--

Corey Butler
The Startup

I build communities, companies, and code. Cofounder of Metadoc.io. Created Fenix Web Server & NVM for Windows.