npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

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 or npm 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