Create and Publish Your First NPM Package: A Comprehensive Guide
Tags: tutorial, typescript, npm, testing
Published: 2023-08-12 12:53:24

#Table of Contents
- [Introduction](#introduction)
- [Prerequisites](#prerequisites)
- [Getting Started](#getting-started)
  - [Setting Up Your Development Environment](#setting-up-your-development-environment)
- [Configuration](#configuration)
  - [Rollup](#rollup)
  - [Typescript](#typescript)
- [Writing Your First TypeScript File](#writing-your-first-typescript-file)
- [Creating the Source Directory and Files](#creating-the-source-directory-and-files)
- [Adding Jest for Testing](#adding-jest-for-testing)
  - [Configuring Jest for TypeScript](#configuring-jest-for-typescript)
  - [Writing a Test](#writing-a-test)
- [Publishing to NPM](#publishing-to-npm)
  - [Add publish scripts](#add-publish-scripts)
  - [Logging into NPM](#logging-into-npm)
  - [Publishing the Package](#publishing-the-package)
- [Conclusion](#conclusion)

#Introduction

Node Package Manager (NPM) is the world's largest software registry, housing over a million packages that enable developers to share and borrow packages, and assemble them in powerful new ways. An NPM package is a reusable piece of code that you can download and install into your projects, encapsulating functionality that can be easily shared across different projects or even with the community at large.

You can find the complete code and examples for this tutorial in the [GitHub repository](https://github.com/Mumma6/npm-package-tutorial).

#Why Create an NPM Package?

Creating an NPM package allows you to:

- **Modularize Code:** Break down complex applications into manageable, reusable components.
- **Share Your Work:** If you've created a function or component that others might find useful, packaging it allows you to share it easily with others.
- **Contribute to the Community:** Many developers contribute packages to NPM that the entire community can benefit from. By publishing a package, you too can contribute to this ecosystem.
- **Control Versions:** Easily manage different versions of the code across different environments.

#What Will This Tutorial Cover?

In this tutorial, we'll guide you through the process of creating, packaging, and publishing a basic NPM package using TypeScript. Along the way, we'll demonstrate best practices in modular development and introduce you to tools such as Jest for testing and Rollup for bundling. Whether you're looking to share your own projects with the world, learn about TypeScript's powerful type system, or just organize your code more effectively, this guide will get you started on the right track.

The key components we'll explore include:

- **TypeScript:** How to leverage TypeScript for adding strong typing to your package, enhancing code quality and maintainability.
- **Jest:** We'll incorporate Jest for unit testing, ensuring the reliability of your package.
- **Rollup:** We'll use Rollup to bundle your TypeScript files, making them ready for distribution.
- **Packaging and Publishing:** The essential steps to prepare your package for distribution, including setting up the package.json file and publishing to the NPM registry.

By the end of this tutorial, you'll have a clear understanding of how to build a robust, reusable package with TypeScript and have the knowledge to contribute your own packages to the broader development community.

#Prerequisites

Before we begin, please ensure you meet the following prerequisites:

- **Node.js and NPM installed:** Make sure you have both Node.js and NPM installed on your computer. You can download them from the [official website](https://nodejs.org/en).
- **Basic Understanding of TypeScript:** This tutorial assumes that you have some familiarity TypeScript. You don't need to be an expert, but you should know the basics.
- **An Account on NPM:** If you plan to publish your package to the NPM registry, you'll need an account. You can [sign up here](https://www.npmjs.com/signup) if you don't have one.


#Getting Started

##Setting Up Your Development Environment

- **Creating a New Project Folder:** Create a new folder and open up your editor.
- **Initializing a New Project:** The first thing we need to do is run `npm init` in the terminal and follow the prompts.

You should now have a package.json file, and it should look something like this:

```Typescript
{
  "name": "my-package",
  "version": "1.0.0",
  "description": "my npm package",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Martin Persson",
  "license": "ISC"
}
```

**Installing Dependencies:** To get started with our project, we'll need to install several dependencies that will help us in development, testing, and bundling our NPM package. Here's a breakdown of the dependencies and what they're used for:

- **TypeScript:** The core compiler for TypeScript.
- **Jest:** A JavaScript testing framework.
- **Rollup:** A module bundler for JavaScript.
- **ts-jest:** A preprocessor with source map support to help use TypeScript with Jest.
- **@types/jest:** The TypeScript definitions for Jest.
- **rollup-plugin-typescript2:** A plugin to use TypeScript with Rollup.
- **nodemon:** A utility that will monitor for any changes in your source and automatically restart your server.
- **concurrently:** We'll be using concurrently to run multiple npm scripts simultaneously during development.

To install the dependencies, run the following commands:

**Typescript**
`npm install typescript`

**Jest**
`npm install jest @types/jest ts-jest`

**Rollup**
`npm install rollup rollup-plugin-typescript2`

**Nodemon**
`npm install nodemon`

**Concurrently**
`npm install concurrently`

In your `package.json`, you should see all the dependencies that we installed (note: you might have different versions than the ones listed below):

```Typescript
"dependencies": {
    "@types/jest": "^29.5.3",
    "concurrently": "^8.2.0",
    "jest": "^29.6.2",
    "nodemon": "^3.0.1",
    "rollup": "^3.28.0",
    "rollup-plugin-typescript2": "^0.35.0",
    "ts-jest": "^29.1.1",
    "typescript": "^5.1.6"
  }
```

#Configuration

##Rollup

Rollup is a powerful module bundler that we'll use to bundle our TypeScript files, making them ready for distribution. We'll need to create a configuration file for Rollup to understand how to bundle our package.

Create a new file in your project root called rollup.config.js, and add the following code:

```Typescript
const typescript = require("rollup-plugin-typescript2")
const pkg = require("./package.json")

module.exports = {
  input: 'src/index.ts',
  output: [
    {
      file: pkg.main,
      format: 'cjs',
      exports: 'named',
      sourcemap: true,
      strict: false
    }
  ],
  plugins: [
    typescript()
  ],
}
```

##Typescript

To set up TypeScript for our project, we'll create a `tsconfig.json` file at the root of our project directory. This file guides TypeScript on how to compile our code and includes the following configurations:

```Typescript
{
  "compilerOptions": {
    "outDir": "dist",
    "module": "esnext",
    "target": "es5",
    "lib": ["es6", "dom", "es2016", "es2017"],
    "sourceMap": true,
    "allowJs": false,
    "declaration": true,
    "moduleResolution": "node",
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist", "rollup.config.js"]
}
```

#Writing Your First TypeScript File

Now that we have TypeScript and Rollup configured, we'll need to update our `package.json` file to include the necessary scripts and main entry point.

**main:** This points to the compiled entry file of our package. We'll set it to `dist/index.js`, the location where Rollup will compile our TypeScript code.

**scripts:** Here, we'll define various commands that help in the development, building, and watching of our project:

- build: This command will run Rollup with the configuration file, compiling our TypeScript code into the `dist` folder.
- dev: This command uses concurrently to watch TypeScript files and restart the server with nodemon whenever changes are detected.

Here's how the updated package.json file should look:

```Typescript
{
  "name": "my-package",
  "version": "1.0.0",
  "description": "my npm package",
  "main": "dist/index.js",
  "scripts": {
    "build": "rollup -c",
    "dev": "concurrently \"tsc --watch\" \"nodemon ./dist/index.js\""
  },
  "author": "Martin Persson",
  "license": "ISC",
  "dependencies": {
    "@types/jest": "^29.5.3",
    "concurrently": "^8.2.0",
    "jest": "^29.6.2",
    "nodemon": "^3.0.1",
    "rollup": "^3.28.0",
    "rollup-plugin-typescript2": "^0.35.0",
    "ts-jest": "^29.1.1",
    "typescript": "^5.1.6"
  }
}
```

#Creating the Source Directory and Files

In this section, we will set up our main source folder and create a simple "Hello World" program. Follow these steps:

- **Create the src Directory:** This will be the main directory for all our TypeScript source files.
- **Create the index.ts File:** Inside the src directory, create a file named index.ts.
- **Edit the index.ts File:** Open the index.ts file and add the following code:

```Typescript
console.log("Hello world")
```

Run Your Code: Now you're ready to run your code! In your terminal, execute the following command:

```Typescript
npm run dev
```

You should see the "Hello world" message printed to your terminal. Additionally, thanks to Nodemon, any changes you make to the `index.ts` file will be automatically detected and rerun, allowing you to see your updates in real time.

#Adding Jest for Testing

Testing your code is a fundamental practice in software development that can help you catch errors early and make sure that your code functions as expected. With Jest, a popular JavaScript testing framework, you can write and run tests in a structured and efficient way.

In this section, we'll walk through setting up Jest for a TypeScript project, writing a test for a simple function, and running the test.

##Configuring Jest for TypeScript

Since Jest is originally designed for JavaScript, we need to configure it to work with TypeScript files. Follow the steps below:

Create a new file named `jest.config.js` in your root directory and add the following configuration:

```Typescript
module.exports = {
  preset: 'ts-jest',
  testMatch: ["**/__tests__/**/*.test.ts"],
};
```

- **preset:** 'ts-jest': This line tells Jest to use the ts-jest preset, which contains the settings necessary to transpile TypeScript code.
- **testMatch:** This is an array of glob patterns that Jest uses to detect test files. The given pattern "**/__tests__/**/*.test.ts" will match any .ts files inside a __tests__ directory that end with .test.ts.

This basic configuration is enough to get started with testing TypeScript files, but Jest can be customized further depending on your specific needs.

##Writing a Test

Now, let's write a test for our `sayHello` function. The function code looks like this and you can add it to your `index.ts` file:

```Typescript
export const sayHello = (name: string) => `Hello, ${name}`
```

Create a test folder in your directory called __tests__ and inside create a file named `index.test.ts`.

Before we can run our test, we need to add:

```Typescript
"test": "jest",
```
To our "scripts" section inside `package.json`.

To run the test, type `npm run test` in the terminal.

If everything is set up correctly, Jest will find and run the test file, and you should see a success message in your terminal.

#Publishing to NPM

After setting up and testing your TypeScript project, it's time to publish it to the npm registry. Here's how you can do it:

##Add publish scripts

Before we can publish our package we need to make updates to our scripts inside `package.json`. Add the following:

```Typescript
   "prepare": "npm run build",
   "prepublishOnly": "npm test"
```

##Logging into NPM

Before publishing your package, you need to log into npm, which requires a user account. If you don't have an account, you can [sign up here](https://www.npmjs.com/signup).

Open your terminal and enter the following command:

```Typescript
npm login
```
You'll be prompted to enter your username, password, and email address associated with your npm account.

##Publishing the Package

Before publishing your package, ensure that you have chosen a unique name for it. The name must be one that hasn't been used before on npm. Update the "name" field in your package.json file to your chosen name.

Example:

```Typescript
"name": "your-unique-package-name",
```

With everything set up and your code tested, you're ready to publish your package.

Verify Your package.json File: Ensure that your package.json file includes all necessary details, such as name, version, description, main entry file, etc.

Publish the Package: Run the following command:

```Typescript
npm publish
```

You could also automatically increment the version while publishing. (thanks to @tqbit for pointing that out)

```Typescript
npm version patch --no-git-tag-version && npm publish --access public
# Instead of patch, you can use 'minor' or 'major'
```

After successfully publishing your package, you can verify its availability by visiting your npm profile. Log in to npm's website and navigate to the "packages" section under your profile. Here, you should see your newly published package listed among any others you may have published previously.

If everything looks good, congratulations! You've successfully published a TypeScript package to npm. Now others can install and use your package by running:

```Typescript
npm install your-unique-package-name
```

Remember to maintain and update your package as needed, responding to issues and continuing to enhance its functionality. Happy publishing!

**Note:** If you encounter a 403 Forbidden error during the publishing process, it may be related to the package name already being used. In this case, choose a different, unique name and try again.

#Conclusion
Creating, testing, and publishing a TypeScript package to the NPM registry is a fulfilling process that adds value to the broader development community. In this tutorial, we've walked through every step of this journey—from setting up your development environment, understanding dependencies like TypeScript, Jest, and Rollup, to writing your first piece of code and creating unit tests. Finally, we learned how to prepare and publish the package, making it available for others to use.

The principles and practices detailed in this guide not only enable you to contribute your own packages to the NPM ecosystem but also provide a solid foundation for modular development. By understanding how to break down code into reusable components, you can write cleaner, more maintainable code, whether you're working on personal projects or contributing to larger team efforts.

As you continue to explore and grow as a developer, remember that the community is an ever-evolving space filled with opportunities for learning and collaboration. Whether it's by enhancing your existing packages, creating new ones, or contributing to others, you're now equipped with the skills and knowledge to engage actively with the development world.

Happy coding, and don't hesitate to share your creativity and expertise with the community!