Getting Started: Packaging your TypeScript library for npm

As TypeScript and its community grows so too does its ease of access for new developers. The idea of setting up your first npm package for your TypeScript library can be intimidating; you might be reading this after scouring a number of other posts and GitHub issues. This is the easiest way to get your TypeScript library ready to be published to NPM. This blog post assumes you are using TypeScript v2.1 or higher as the process is different prior to this version.

Setup the TypeScript compiler options

One of the most commonly missed steps is ensuring that your tsconfig.json is setup properly as to allow for npm to properly reference this awesome library you’ve been working hard on. There are a couple requirements:

  • a module must be defined, “commonjs” is recommended.
  • declaration must be set to true

For example:

{
    "compilerOptions": {
        "target": "es2016",
        "module": "commonjs",
        "sourceMap": true,
        "declaration": true
    }
}

Definitions, typings, and types, oh my!

The strategy for including type definitions in your npm packages has seen several iterations over the years — but gone are the days of needing to publish to repositories to be consumed by tsd and typings. So dawns the era being able to include definition files directly in your packages.

As of TypeScript 2.1 you can include a definition file directly in your project and expose it for consumption through your library’s package.json file. Let’s assume in our root we have our myAwesomeLib.ts. Since we setup declarations in our compiler config we will also output a myAwesomeLib.d.ts and myAwesomeLib.js file in the same directory. We will need to setup package.json to recognize our entry point as well as telling it that we have a type definition available.

If your TypeScript project is more than a simple file and you are using external module pattern you should leave the generated per-file definitions in their default location alongside the generated .js and the original TypeScript files. They will be resolved through the default d.ts file your package.json points to. We’ll go over how to exclude your TypeScript and map files for publishing below.

Note: If your file name is index.ts and in your root folder you don’t need this step but it’s still recommended.

We will need to perform the following:

  • Give your package a name
  • Ensure all your dependencies are declared
  • set “main” to the relative path of your myAwesomeLib.js (note that it is the javascript file not the typescript file)
  • set “types” to the relative path of your myAwesomeLib.d.ts

For example:

{
  "name": "myAwesomeLib",
  "version": "0.0.1",
  "main": "./myAwesomeLib.js",
  "types": "./myAwesomeLib.d.ts",
  "dependencies": {
  }
}

gitignore, npmignore, and prepping for consumption

Everything inside your folder will be exposed by default. So let’s use an .npmignore to ensure we are including only what’s necessary and definitely excluding anything secret. If there is no npmignore and you have a gitignore then npm will use that.

Since we are using TypeScript we are going to want to exclude a number of things including:

  • Configs such as typings.json, tsconfig.json, .vscode, and your typings folder
  • Generated map files if you configured your project to use them
  • The actual .ts files as this will cause any consumer using TypeScript to incur your unintended wrath of type errors. note: we want to include the definition files as this is what will be used by consuming TypeScript projects.

Here’s an example but make sure you evaluate your specific project:

# ignore certain configs and folders
typings/
typings.json
.vscode/
tsconfig.json

# igore the map files
**/*.map

# ignore the .ts files
*.ts

# include the .d.ts files
!*.d.ts

Testing your package locally

Before we deploy we are going to want to ensure our package is functioning properly.

Open a command prompt or powershell and navigate to the root of your package to perform the following:

npm install . -g

Alternatively you can create symlink package that points to your working directory by running the following in your root directory:

npm link

Create and setup TypeScript in a test project that will act as a consumer. Inside the root of this folder open a command prompt or powershell and install our local package through the filesystem:

npm install ../path/to/your/myAwesomeLib --save

Your consuming project must be setup to use “commonjs” as its module loader in the tsconfig.json in order to properly resolve npm packages in the node_modules folder. If setup properly you should be able to reference your myAwesomeLib as follows:

import * as myAwesomeLib from "myAwesomeLib"

More information is available in the npm docs.

NOTE: As of npm v5 the above steps for testing locally are a bit different and can cause problems with your TypeScript library. Namely they no longer install dependencies and no longer enforce the npmignore. To get a true representation of what your package will look like run the following in the root of your library:

npm pack

This will generate a tar file – the same one that gets uploaded when you publish to live. You can then use the local installation by doing the following in your consuming project root:

npm install ../path/to/your/myAwesomeLib/myawesomelib-0.0.1.tgz --save

For more information you can review the changelog for v5 here.

Time to publish

Once you’ve verified your project works as expected you’re ready to publish. First step is to create a user account if you don’t have one. Run the following command and follow the prompts:

npm adduser

You can find the npm docs for this step here.

To trigger a publish run the following in the rooter folder of your project:

npm publish

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s