esm-executable
v1.0.1
Published
## intro
Downloads
1
Readme
creating shell scripts with node/esm
intro
Learn how to create an executable standalone script two different ways:
- node/esm
- npm package + node/esm
The finished package is available here:
- On GitHub as @frankg/demo
- On npm as @frankg/demo
node/esm as a standalone shell script
FILE EXTENSIONS
- .mjs interpreted as esm
- .js interpreted as esm when you include
"type": "module"
in package.json
Since we're creating a standalone script we don't have package.json we use .mjs
import * as os from "node:os";
const { username } = os.userInfo();
console.log(`Hello ${username}!`);
RUNNING WITH NODE
node hello.mjs
RUNNING STANDALONE
- edit script
#!/usr/bin/env node
import * as os from "node:os";
const { username } = os.userInfo();
console.log(`Hello ${username}!`);
- make it executable --
chmod u+x hello.mjs
- run it
./hello.mjs
node/esm as an npm package
creating the files
- create directory
mkdir demo; cd demo
- create package.json file
npm init -y
- add dependencies
pn add lodash-es
-- creates node_modules folder and package-lock.json file - add readme.md file
- add add two shell scripts
demo/
package.json
package-lock.json
readme.md
src/
homedir.mjs
versions.mjs
- add content to package.json
...
"type": "module",
"bin": {
"homedir": "./src/homedir.mjs",
"versions": "./src/versions.mjs"
},
...
- package.json contents -- confirm required publishing fields: name, version, license
{
"name": "esm-executable",
"version": "1.0.0",
"description": "## intro",
"main": "index.js",
"type": "module",
"bin": {
"homedir": "./src/homedir.mjs",
"versions": "./src/versions.mjs"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "MIT",
"dependencies": {
"lodash-es": "^4.17.21"
}
}
- populate homedir.mjs -- you can run with
node ./src/homedir.mjs
#!/usr/bin/env node
import { homedir } from "node:os";
console.log("Homedir: " + homedir());
- populate versions.mjs -- you can run with
node ./src/versions.mjs
#!/usr/bin/env node
import { pick } from "lodash-es";
console.log(pick(process.versions, ["node", "v8", "unicode"]));
how npm runs shell scripts
INSTALLING ON UNIX
A script such as homedir.mjs does not need to be executable on Unix because npm installs it via an executable symbolic link:
- when installing the package globally, the link is added to a directory that’s listed in $PATH.
- when installing the package locally (as a dependency), the link is added to node_modules/.bin/
publishing the package
Before we publish lets check the configuration
- .gitignore is honored
- .npmignore overides .gitignore
- see files excluded by default:
exclude by default
node_modules
.*.swp
._*
.DS_Store
.git
.gitignore
.npmignore
.npmrc
npm-debug.log
never exclude
package.json
README.md and its variants
CHANGELOG and its variants
LICENSE, LICENCE
Here are some things we can check
- check which files will be uploaded
npm publish --dry-run
- create an archive package as it's store on the registry
npm pack
- install globally with either of these two:
npm link
ornpm install . -g
- list globally installed packages
npm ls -g
-- see the package-name - create an npm account if needed
- upload to the registry
npm publish --access public
- access only needed first time - change access level if needed
- a new version is required for every upload -- use semver - major.minor.patch
avoiding the .mjs extension
Here's a magic trick to avoid having to use the .mjs extension throught your code.
- prepend your shell script files with the following snippet:
#!/bin/sh
":"; // ; cat "$0" | node --input-type=module - $@ ; exit $?
UPDATE: I took out the snippet and it still works with this
#!/usr/bin/env node
# see the package installed
npm ls -g
...
├── [email protected] -> ./../../../../../dev/code/scratch/typescript/esm-executable
...
# find the node path
which node
/Users/frankg/.nvm/versions/node/v18.15.0/bin/node
# show the executable shell scripts
ls /Users/frankg/.nvm/versions/node/v18.15.0/bin
lrwxr-xr-x 1 frankg staff 49B Sep 11 03:53 homedir -> ../lib/node_modules/esm-executable/src/homedir.js
lrwxr-xr-x 1 frankg staff 50B Sep 11 03:53 versions -> ../lib/node_modules/esm-executable/src/versions.js