Publishing JavaScript/TypeScript packages on npm registry
Published on July 14, 2021 · 7 min read · 0 reading right now · 1 views
Introduction
I recently published my NodeJS CLI project called
projman
on the npm registry. It is written in TypeScript, so there were some additional steps to be taken when publishing it on npm.
This guide documents the steps to publish a JS as well as TS package on npm. I'm assuming you already have a JS or TS project setup, and just looking into how to publish that project.
There are some additional steps to be done for publishing TS projects, which I'm gonna mark as
TS
expilicity. Non-
TS
steps can be followed for JS projects.
This guide will use
npm
but if you prefer
yarn
, you can check the
yarn docs
to get see the equivalent command.
If this guide doesn't cover what you are looking for, check out the npm docs . They are really great :)
Let's get started 🚀 !!!
Prerequisites
-
You must have
npm(comes with NodeJS) oryarninstalled(duh! xD). -
You must have a npm account. You can signup here .
Login using
npm login
After you have signed up, open your terminal & run
npm login
. It will ask you for your
username
,
password
and
email
. This will verify your account so that during the publishing of a package, npm will publish through your account.
You can also check if you are logged in or not using
npm whoami
. This should return your username if you are logged in. In case you are not logged in, it will throw an error saying
This command requires you to be logged in
.
You can also logout using
npm logout
.
Configuring
package.json
Before publishing you package, you need to configure some stuff on your package's
package.json
file. Lets see what those configuration are:
For JS packages
The following is a
package.json
file for a JS package.
{
"name": "<name-of-the-package>",
"version": "<package-version>",
"description": "<description>",
"main": "<main-entry-point>",
"types": "<types>",
"scripts": {
"start": "node index.js"
},
"repository": {
"type": "git",
"url": "<repo-url>"
},
"keywords": ["keyword1", "keyword2"],
"author": "xxxx",
"license": "<license>",
"bugs": {
"url": "<repo-url>"
},
"homepage": "<homepage>",
"dependencies": {},
"devDependencies": {}
}
While you may be familiar with some properties like
name
,
scripts
,
dependencies
&
devDependencies
, let's see some non-familiar properties which you should look into.
-
version- This property specifies the version of your package. You should follow the Semantic Versioning(aka semver) scheme for versioning your packages. Read more about semver here .ex. "version": "1.0.1" -
main- This should be the main entry point of your package. What does it mean? Suppose youimportorrequirea package likeconst foo = require('package'), thefoovariable will be the object/function that you exported from your package'smainentry point.ex. "main": "modules.js" // relative path is usedIf you don't provide any value for
main, it will default toindex.js. -
types- This is used to provide type definitions for your package. It points to a declaration file(having extension of.d.ts). This is used when you have a JS package, but you want to provide support for TS as well.Sidenote: You should check Definitely Typed . It contains lots of TS definitions for JS packages.
ex. "types": "index.d.ts" -
repostiory- Provides information about the package's repository. -
bugs- The URL to make an issue in case a bug is discovered by a user, and they want to report it to the package's maintainer. -
homepage- The homepage of the package. In case you have made a fancy website for you package. Most of the time, people just point it the repository's URL.
package.json
for TS package
There's a slight variation in our
package.json
for a TypeScript package.
But first, we need to look at the directory structure of typical TS project.
.
├── dist
│ ├── ....js # other js files
│ ├── index.d.ts # declaration file
│ └── index.js # main entry point
├── src
│ ├── ....ts # other ts files
│ └── index.ts
├── package.json
└── tsconfig.json
src
contains all our source TypeScript files, and
dist
contains the transpiled code which we get by running the TypeScript compiler.
dist
is something you don't want to push into your repository, therefore, it usually gets ignored by git(through
.gitignore
file which we will talk about later).
Let us now see the
package.json
file for TS package:
{
"name": "<name-of-the-package>",
"version": "<package-version>",
"description": "<description>",
"main": "dist/<main-entry-point>",
"types": "dist/<types>",
"scripts": {
"build": "tsc",
"prepack": "npm run build"
},
"repository": {
"type": "git",
"url": "<repo-url>"
},
"keywords": ["keyword1", "keyword2"],
"author": "xxxx",
"license": "<license>",
"bugs": {
"url": "<repo-url>"
},
"homepage": "<homepage>",
"dependencies": {},
"devDependencies": {}
}
The only things that has been changed are:
-
main- The prefixdist/has to be added to the main entry point. -
types- The prefixdist/has to be added here as well. -
scripts- You might notice we have a new script calledprepackin thescriptsproperty.prepackis a command that is ran by npm itself, before publishing a package.In this case,
prepackis used to build our TypeScript package by running the TypeScript compiler before publishing.
Setting up
tsconfig.json
for TS packages
There are certain configurations(only two) that we need to setup for a TS package. Chances are you already have it setup, but lets go through it quickly.
Here's an example
tsconfig.json
file(most of the part has been stripped out).
{
"compilerOptions": {
...
"outDir": "./dist",
"declaration": true,
...
},
}
The main configurations are:
-
outDir- which basically tells our TS compiler in which directory to put the compiled JS output in. This is the reason why we are adding thedist/prefix in ourpackage.json.You can change it to your liking, but don't forget to update package.json as well.
-
declaration- Setting this totruewill cause our TS compiler to output a declaration file as well. The declaration file ends with extension.d.ts. This is what we are putting in ourtypesproperty of package.json.
So, these are the main properties we need to take care in our tsconfig.json file. We are now one step closer to publishing our package!!!
Configuring
.gitignore
&
.npmignore
If you are putting your codebase in a git repository, chances are you already have a
.gitignore
file.
.gitignore
is used to ignore certains files and directories so that they won't be uploaded to the git repo(only in absence of
.npmignore
file).
As it turns out, during the publishing of your package,
npm
will already ignore the files/directories that are in your
.gitignore
file.
But, Why would you wanna ignore certain files from being published?
Read this great article on why we should ignore certain un-necessary files from being published.
.gitignore
vs
.npmignore
It's a pretty common case that you might want to ignore certain files from being pushed to git repo, but want those ignored files to be published on the npm registry. How would you do that?
Introducing
.npmignore
. This file is used to prevent certain files/directories from being published. It's just like
.gitignore
but this time,
npm
will look into the
.npmignore
file to check what files/directories it will ignore.
In absence of
.npmignore
file, npm uses the
.gitignore
file ignor files/directories. More info in
this stackoverflow
thread.
Using
.npmignore
for TS packages
For a TS package, you would not want to publish your
src
directory which contains all the TypeScript files, instead you would want to publish the
dist
directory where all the compiled JS code lives.
But since, you have your
dist
directory ignored in
.gitignore
file. How would you publish this
dist/
directory?
No worries,
.npmignore
to the rescue!!!
As we learned above, if
.npmignore
file in present, npm will ignore the
.gitignore
file, and use
.npmignore
instead. So, here's how your
.gitignore
&
.npmignore
file should look like:
// .gitignore
node_modules/
dist/
.env
// .npmignore
node_modules/
src/
.env
Can you spot the difference?
Right!
.gitignore
has
dist/
where as
.npmignore
has
src/
on the list of directories to ignore.
Now, let's move onto the final step!!!
Publishing packages using
npm publish
You can publish your package from the npm command itself. That's really cool!
npm has an option called
publish
to publish your packages(obviously :p). This step requires you to be logged in. Check out the
first section
to login.
Here's how the whole thing comes together.
You run
npm publish
in the current directory of the package you want to publish.
npm
will run the
prepack
command(See
the prepack script
) to build our TypeScript project(you can ignore this line if you have a JS package).
and then, it will zip all the contents of current project while ignoring certain files/directories present in
.npmignore
(or
.gitignore
), and publish it on the npm registry and that's it!! You should see your package published on the npm registry.
Hooray 🎉 !!!
So that concludes this guide on how to publish your package using
npm
:)
Further reading
-
Awesome npm - A curated list of awesome npm tips and packages.
-
The official npm docs .
-
The npm docs on configuring
package.json.