Compile a single executable from your Node app with Node.js 20 and ESBuild

Introduction

Node.js 20 was released very recently. Along with several other features, you can now compile your Node.js project into a single executable that can be run in environments without Node.js installed. It’s important to note that t…


This content originally appeared on DEV Community and was authored by Chad R. Stewart

Introduction

Node.js 20 was released very recently. Along with several other features, you can now compile your Node.js project into a single executable that can be run in environments without Node.js installed. It’s important to note that this is still experimental and may not be suitable for use in production.

Node.js has instructions on how to set up these single executables: https://nodejs.org/api/single-executable-applications.html

Unfortunately, when compiling the executable, you will not compile dependencies into your executable. To solve this problem, we will leverage a JavaScript bundler to bundle our dependencies into one file before compiling it into our single executable.

Prerequisites:

  • Node.js 20

Please note: While TypeScript is used in this article, it is not necessary.

Putting Together our Project

First, we need a project that we will build into our executable.

We’ll first define our server.

server.ts

import express from "express";
import https from "https";
import fs from "fs";
import path from "path";

export const app = express();

//Initialize Request Data Type
app.use(express.json({ limit: "10mb" }));

app.get("/", (req, res) => res.send("Hello World!!"));

const port = 3000;
app.listen(port, () => {
    console.log(`Server is live on ${port}`);
});

We define our package.json next:

package.json

{
  "name": "node-executable-example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "esbuild server.ts --bundle --platform=node --outfile=server-out.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "esbuild": "0.17.17",
    "express": "^4.18.2"
  },
  "devDependencies": {
    "@types/express": "^4.17.17",
    "@types/node": "^18.15.7",
    "typescript": "^5.0.2"
  }
}

Please note the build script. Esbuild will take our .ts file and bundle it with our dependencies into a single .js file server-out.js. You can actually run this file once it is created using node server-out.js to check if the bundling was done correctly.

We then define our tsconfig.json

tsconfig.json

{
  "compilerOptions": {
    "target": "es2022",
    "lib": ["es2022"],
    "module": "commonjs",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

We now define our sea-config.json file.

This is a configuration file building a blob that can be injected into the single executable application (see Generating single executable preparation blobs for details)

sea-config.json

{
  "main": "server-out.js",
  "output": "sea-prep.blob"
}

Now that we have everything we need, we can begin putting together our single executable.

Creating the Single Binary File

Begin by installing all the dependencies we’ll need by running this command:

npm install

Once npm install is completed, we run the command:

npm run build

This will create our server-out.js which will be our bundled file we will make into an executable.

Note: If you rather, you can follow the instructions from the Node.js guide starting from step 3 as the following steps will be exactly the same, located here: https://nodejs.org/api/single-executable-applications.html

Generate the blob to be injected:

node --experimental-sea-config sea-config.json 

Create a copy of the node executable and name it according to your needs:

cp $(command -v node) server

Note: If you are on a Linux Distro (such as Ubuntu), you can skip the next steps and move straight to running the binary.

Remove the signature of the binary:

On macOS:

codesign --remove-signature server

On Windows (optional):
signtool can be used from the installed Windows SDK. If this step is skipped, ignore any signature-related warning from postject.

signtool remove /s server

Inject the blob into the copied binary by running postject with the following options:

  • server - The name of the copy of the node executable created in step 2.
  • NODE_SEA_BLOB - The name of the resource / note / section in the binary where the contents of the blob will be stored. sea-prep.blob - The name of the blob created in step 1.
  • --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 - The fuse used by the Node.js project to detect if a file has been injected.
  • --macho-segment-name NODE_SEA (only needed on macOS) - The name of the segment in the binary where the contents of the blob will be stored.

To summarize, here is the required command for each platform:

On systems other than macOS:

npx postject server NODE_SEA_BLOB sea-prep.blob \
    --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 

On macOS:

npx postject server NODE_SEA_BLOB sea-prep.blob \
    --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 \
    --macho-segment-name NODE_SEA 

Sign the binary:

On macOS:

codesign --sign - server 

On Windows (optional):
A certificate needs to be present for this to work. However, the unsigned binary would still be runnable.

signtool sign /fd SHA256 server 

Run the binary:

./server

You should now have a running Node server similar if you just ran node server-out.js

If you wanted to see a completed example, go here: https://github.com/chadstewart/ts-node-executable-article-example

  • If you found this article interesting, please feel free to heart this article!
  • If you’re interested in learning more about Front-End Engineering, follow me here on Dev.to and Twitter
  • If you’re looking for jobs, I’d highly recommend checking out @TechIsHiring on Twitter, LinkedIn or TechIsHiring's website https://www.TechIsHiring.com/ for posted jobs and other resources!
  • Want to check out a curated list of jobs, job seekers and resources from TechIsHiring? Check out TechIsHiring's Newsletter


This content originally appeared on DEV Community and was authored by Chad R. Stewart


Print Share Comment Cite Upload Translate Updates
APA

Chad R. Stewart | Sciencx (2023-05-01T16:46:46+00:00) Compile a single executable from your Node app with Node.js 20 and ESBuild. Retrieved from https://www.scien.cx/2023/05/01/compile-a-single-executable-from-your-node-app-with-node-js-20-and-esbuild/

MLA
" » Compile a single executable from your Node app with Node.js 20 and ESBuild." Chad R. Stewart | Sciencx - Monday May 1, 2023, https://www.scien.cx/2023/05/01/compile-a-single-executable-from-your-node-app-with-node-js-20-and-esbuild/
HARVARD
Chad R. Stewart | Sciencx Monday May 1, 2023 » Compile a single executable from your Node app with Node.js 20 and ESBuild., viewed ,<https://www.scien.cx/2023/05/01/compile-a-single-executable-from-your-node-app-with-node-js-20-and-esbuild/>
VANCOUVER
Chad R. Stewart | Sciencx - » Compile a single executable from your Node app with Node.js 20 and ESBuild. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2023/05/01/compile-a-single-executable-from-your-node-app-with-node-js-20-and-esbuild/
CHICAGO
" » Compile a single executable from your Node app with Node.js 20 and ESBuild." Chad R. Stewart | Sciencx - Accessed . https://www.scien.cx/2023/05/01/compile-a-single-executable-from-your-node-app-with-node-js-20-and-esbuild/
IEEE
" » Compile a single executable from your Node app with Node.js 20 and ESBuild." Chad R. Stewart | Sciencx [Online]. Available: https://www.scien.cx/2023/05/01/compile-a-single-executable-from-your-node-app-with-node-js-20-and-esbuild/. [Accessed: ]
rf:citation
» Compile a single executable from your Node app with Node.js 20 and ESBuild | Chad R. Stewart | Sciencx | https://www.scien.cx/2023/05/01/compile-a-single-executable-from-your-node-app-with-node-js-20-and-esbuild/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.