Npm Publish
Published:
How to publish an npm package
Publishing your own npm (Node Package Manager) package is straightforward. Here’s a concise guide:
Steps
-
Sign Up / Log In
Go to the npm official website and sign up or log in. - Initialize Your Project
In your project directory, run:npm initThis will create a
package.jsonfile. -
Write Your Package Code
Add your source code and documentation files. - Login via CLI
Authenticate in your terminal:npm login - Publish Your Package
Run:npm publish
Typical Project Structure
my-npm-package/
├── package.json
├── README.md
├── index.js
└── bin/
└── lib/
└── ... (your modules)
About the bin Field and CLI Scripts
The bin field in your package.json specifies executable files that should be installed as command-line programs when your package is installed globally (or as a dependency).
When Do You Need a bin File?
- If your package provides a CLI (Command Line Interface) tool, you need a
binentry. - If your package is only a library (used via
require/import), you usually do not need abinfield.
Example: Adding a CLI Script
Suppose you want users to run a command like mycli after installing your package.
package.json:
{
"name": "my-npm-package",
"version": "1.0.0",
"bin": {
"mycli": "./bin/mycli.js"
}
// ... other fields
}
bin/mycli.js:
#!/usr/bin/env node
console.log('Hello from my CLI!');
Make sure to add execute permission:
chmod +x bin/mycli.js
How Does the Script Work?
- When users install your package globally (
npm install -g my-npm-package), npm will create a symlink so they can runmyclidirectly from the command line. - The
#!/usr/bin/env nodeline tells the system to use Node.js to run the script.
Why Might a Package Not Have a bin Field?
- If the package is not intended to be used as a CLI tool, there is no need for a
binentry. - Most utility libraries (like lodash, axios, etc.) do not provide CLI commands, so they omit the
binfield.
Using commander for CLI Development
commander is a popular library for building command-line interfaces in Node.js. It helps you parse arguments, define commands, and generate help messages easily.
Basic Example
Install commander:
npm install commander
Create a CLI script (bin/mycli.js):
#!/usr/bin/env node
const { program } = require('commander');
program
.name('mycli')
.description('An example CLI using commander')
.version('1.0.0');
program
.command('greet <name>')
.description('Greet someone')
.action((name) => {
console.log(`Hello, ${name}!`);
});
program.parse(process.argv);
For local testing, you can use
yarn link(ornpm link) to create a symlink and debug your package locally before publishing.
After you finish testing, it’s recommended to remove the link to avoid conflicts:
- In your project directory, run:
yarn unlink # or npm unlink - Optionally, in the global package directory, you can also run:
yarn unlink <package-name> # or npm unlink <package-name>
This ensures your project uses the published version of the package instead of the local symlink.
Now, after publishing and installing your package globally, you can run:
mycli greet Devin
# Output: Hello, Devin!
For more features and advanced usage, see the commander documentation.
NPM Package Case Studies
1. Optimizing Static Image Size with imgzip
To address the issue of oversized static image assets in the project, I created and published a CLI tool called imgzip as an npm package. This tool compresses image files efficiently while maintaining visual quality, significantly reducing bundle size and improving page load speed.
See more info about devin-img-zip
- npm package: devin-img-zip on npm
- Project details here
2. Automating Multilingual Workflows with a Private NPM Package
Our project involves multilingual support. To improve development efficiency, we built a private npm package for automating the translation of locale files. This tool significantly streamlines the i18n process by managing YAML-based translations and supporting batch processing for multiple languages.
Hosted privately, not publicly available on npm registry. See more info at i18n tool