📦 Bundle Node.js code into single executable binary

midnqp

Muhammad Bin Zafar

Posted on August 20, 2022

📦 Bundle Node.js code into single executable binary

Node.js 🐢, the asynchronous event-driven JavaScript runtime, has unparalleled support for file-system access, among other things - opening up the door to endless possiblities! However, Node.js often loses out to other runtimes/languages in cases where being able to package a single, executable application simplifies distribution and management of what needs to be delivered.

While there are components/approaches for doing this, they need to be better documented and evangelized so that this is not seen as a barrier for using Node.js in these situations. This is important to support the expansion of where/when Node.js is used in building solutions.

This article addresses 2 major concerns in the Node.js ecosystem: bundling and packaging. Let's talk about them briefly.

Bundling is the concept of merging the code, and all its dependencies into a single file. This is commonly seen for frontend development.

However, using the ESM packaging format has one advantage than CJS: tree-shaking. Tree-shaking is the concept of removing unused code from a dependency. Tools: esbuild, parcel, webpack, rollup, terser.

Packaging in Node.js is concept of creating a single executable binary, which includes the source code and the Node.js runtime. This way, Node.js will not be needed to be installed on end-user's machine.

During the process, the tool parses the source code, detects calls to require(), traverses the dependencies, and includes them into executable. Usually the source code is compiled into bytecode using the V8 engine. Tools: pkg, ncc, nexe.

esbuild to bundle

  • An extremely fast JavaScript and CSS bundler and minifier
  • Most convenient
  • Fastest in comparison
  • Support for TypeScript syntax, ESM, and CJS
  • Supports tree-shaking for ESM
  • Supports minification and source maps
# Output CommonJS bundle
$ npx esbuild index.js  --bundle --outfile=build.cjs \
--format=cjs --platform=node
Enter fullscreen mode Exit fullscreen mode
# Output ESM bundle
# Note that, you may not need the --banner flag.
# But, in some cases, require() and __dirname are needed.
$ npx esbuild index.js  --bundle --outfile=build.mjs \
--format=esm --platform=node --banner:js="
import {createRequire} from 'module';
const require = createRequire(import.meta.url);
import { dirname } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));"
Enter fullscreen mode Exit fullscreen mode

pkg to package

  • Package your Node.js project into an executable
  • Instantly make executables for Windows, Mac, Linux, etc
  • No need to install Node.js, or hundreds of dependencies
# Packaging tools work best with CJS. 
# These tools don't go well with ESM.

# To package into executable, just take the file outputted
# by `esbuild`, and pass it to `pkg`, and we're done!
$ npx pkg build.cjs
Enter fullscreen mode Exit fullscreen mode

This command will output 3 binary exectuable files build-linux, build-macos, and build-win.exe. You might want to run the executable file for your platform. Now you can simply distribute these files to your end-users or deploy in production - without installing Node.js or any dependencies or anything - just this one file!


Thanks for reading! Found it interesting? Give it a ❤️ or 🦄! Any topic you'd want to me cover? Let me know in the comments.

Have a great day!

💖 💪 🙅 🚩
midnqp
Muhammad Bin Zafar

Posted on August 20, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related