Create and Publish Your First NPM Package: A Comprehensive Guide
Martin Persson
Posted on August 12, 2023
Table of Contents
- Introduction
- Prerequisites
- Getting Started
- Configuration
- Writing Your First TypeScript File
- Creating the Source Directory and Files
- Adding Jest for Testing
- Publishing to NPM
- 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.
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.
- 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 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:
{
"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):
"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:
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:
{
"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:
{
"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:
console.log("Hello world")
Run Your Code: Now you're ready to run your code! In your terminal, execute the following command:
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:
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:
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:
"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:
"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.
Open your terminal and enter the following command:
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:
"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:
npm publish
You could also automatically increment the version while publishing. (thanks to @tqbit for pointing that out)
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:
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!
Posted on August 12, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.