How to create a module-based Node.js executable (#snippet)

Many of my projects include Node.js scripts to perform setup or teardown steps. And while I could run all of them with the node binary (node create-thumbnails.js), I prefer to remove the file extension and make the scripts executabl…


This content originally appeared on Stefan Judis Web Development and was authored by Stefan Judis

Many of my projects include Node.js scripts to perform setup or teardown steps. And while I could run all of them with the node binary (node create-thumbnails.js), I prefer to remove the file extension and make the scripts executables (./create-thumbnails). This approach saves characters, and makes me feel like a hacker!

My steps to create an executable are:

  • Remove the .js file extension (mv create-thumbnails.js create-thumbnails).
  • Make the file executable (chmod 744 create-thumbnails).
  • Add a shebang (#!/usr/bin/env node) to signal that the executing shell should use the node binary.

Et voilà, you just created a Node.js executable!

This approach has served me well for CommonJS-based scripts using the require function. But it's 2022, and I planned to adopt ECMAScript modules in Node.js executables. Unfortunately, it's not that easy.

This article summarizes the most valuable parts of Axel Rauschmayer's extensive guide "Node.js: creating ESM-based shell scripts for Unix and Windows". Head on over if you want to dive into cross-platform executables.

But what's the problem?

The Node.js binary is missing a flag to specify module files

There are three ways to enable ECMAScript modules in Node.js:

  1. use the .mjs file extension
  2. have a surrounding package.json with a "type": "module" field
  3. call node with the --input-type=module flag

My executables should work without a file extension, which rules out the first option. I also don't want to declare all files as module files or add a package.json, so the type field is out, too.

The --input-type flag looks promising at first, but it only works for strings you pipe into the Node binary yourself.

# pipe JavaScript code into the node binary
echo "import { mkdir } from 'node:fs/promises';" | node --input-type=module

Why's there no flag to enable modules when running a file?

I spent the last 15 minutes reading Node.js issues and discussions about the topic, and I still can't answer this question. If you want to read more, here's a very long GitHub discussion on why such a flag isn't available yet.

Knock yourself out, the discussion takes many turns, and folks have strong opinions!

A "hacky" solution to run module-based JavaScript executables

There are multiple ways to make ECMAScript module-based executables work. They all come with slightly different spins but use the same trick.

Axel recommends the following for UNIX environments.

#!/bin/sh
':' // ; cat "$0" | node --input-type=module - $@ ; exit $?

import * as os from 'node:os';

const {username} = os.userInfo();
console.log(`Hello ${username}!`);

This snippet is wild! In short, it does the following:

  • the cat command reads the current file (the executable itself)
  • the file content is then piped into node with the --input-type flag
  • all the original parameters are handed over to node, too ($@)
  • the node call's exit code is caught and propagated to the executable

This instruction makes the file read and pipe itself into the node binary because there's no flag to enable modules. Wow! 🤯

As said, this post is only for my reference. Here are more resources if you want to learn more about other approaches or make it work on Windows.


Reply to Stefan


This content originally appeared on Stefan Judis Web Development and was authored by Stefan Judis


Print Share Comment Cite Upload Translate Updates
APA

Stefan Judis | Sciencx (2022-08-01T22:00:00+00:00) How to create a module-based Node.js executable (#snippet). Retrieved from https://www.scien.cx/2022/08/01/how-to-create-a-module-based-node-js-executable-snippet/

MLA
" » How to create a module-based Node.js executable (#snippet)." Stefan Judis | Sciencx - Monday August 1, 2022, https://www.scien.cx/2022/08/01/how-to-create-a-module-based-node-js-executable-snippet/
HARVARD
Stefan Judis | Sciencx Monday August 1, 2022 » How to create a module-based Node.js executable (#snippet)., viewed ,<https://www.scien.cx/2022/08/01/how-to-create-a-module-based-node-js-executable-snippet/>
VANCOUVER
Stefan Judis | Sciencx - » How to create a module-based Node.js executable (#snippet). [Internet]. [Accessed ]. Available from: https://www.scien.cx/2022/08/01/how-to-create-a-module-based-node-js-executable-snippet/
CHICAGO
" » How to create a module-based Node.js executable (#snippet)." Stefan Judis | Sciencx - Accessed . https://www.scien.cx/2022/08/01/how-to-create-a-module-based-node-js-executable-snippet/
IEEE
" » How to create a module-based Node.js executable (#snippet)." Stefan Judis | Sciencx [Online]. Available: https://www.scien.cx/2022/08/01/how-to-create-a-module-based-node-js-executable-snippet/. [Accessed: ]
rf:citation
» How to create a module-based Node.js executable (#snippet) | Stefan Judis | Sciencx | https://www.scien.cx/2022/08/01/how-to-create-a-module-based-node-js-executable-snippet/ |

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.