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
# 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));"
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
$ npx pkg index.js
Leave a Reply