DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 964,423 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for πŸ“¦ Bundle Node.js code into single executable binary
Muhammad
Muhammad

Posted on • Updated on

πŸ“¦ 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!

Top comments (9)

Collapse
 
mhm13dev profile image
Mubashir Hassan

Interesting. Thanks for sharing

Collapse
 
midnqp profile image
Muhammad Author

Thanks @mhm13dev! I'm happy to know!

Collapse
 
bias profile image
Tobias Nickel

hmm, I always did not like that pkg only understand require statements, I never thought of using a compiler such as esbuild first.

Collapse
 
midnqp profile image
Muhammad Author • Edited on

@bias Another option would be to use TypeScript, and output CJS.

Collapse
 
tobecci profile image
Tochukwu Ojinaka

did not know this, thanks so much

Collapse
 
midnqp profile image
Muhammad Author

πŸš€ @tobecci You're always welcome!

Collapse
 
othimar profile image
PΓ©lΓ© Oussoumanou

I tried it with a simple example. It works. Really good. Thanks!πŸ‘

Collapse
 
midnqp profile image
Muhammad Author

That's fabulous πŸŽ‰ @othimar ! Wish you the best on your journey!

Collapse
 
raguay profile image
Richard Guay

I’ve ended up using caxa. Pkg didn’t work for my setup.

DEV has this feature:

Settings

Go to your customization settings to nudge your home feed to show content more relevant to your developer experience level. πŸ›