Skip to content

Steps to create a reusable TypeScript node package

Jaime Cham edited this page Sep 5, 2019 · 4 revisions

We have some code that we want to share between different TypeScript/Node projects, so we want to create an NPM package that we can import into both projects.

0. Collect the source files:

  • Create a directory for the project, and add source files (preferably under a subdirectory, e.g. /src).
  • The files, such as src/mylibrary.ts would look like this:
import {Observable} from "rxjs"
export function taplog<X>(label: string, ...vars: any[])
  : (s: Observable<X>) => Observable<X> {
  return (s: Observable<X>) => s.pipe(
    tap(x => console.log(label, x, ...vars))
  )
}

1. Initial setup:

  • Create a package.json, or run npm init:
{
  "name": "cbjs",
  "version": "0.7.0",
  "description": "Utilities and common functions and classes for TypeScript, React, RxJS projects",
  "main": "dist/index.js",
  "scripts": {
    "test": "jest --config jest.config.json",
    "build": "tsc"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/cardinalblue/cbjs.git"
  },
  "keywords": [
    "JavaScript",
    "TypeScript",
    "React",
    "RxJS"
  ],
  "author": "Jaime Cham",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/cardinalblue/cbjs/issues"
  },
  "homepage": "https://github.com/cardinalblue/cbjs#readme"
}

2. Install the dependencies:

General dependencies:

npm install react rxjs

etc.

You might also need the types to be installed:

npm install @types/react

Make sure TypeScript is installed:

npm install -D typescript

Make sure Babel dependencies are installed:

npm install -D @babel/core @babel/preset-env @babel/preset-typescript

For tests install the Jest dependencies:

npm install -D jest ts-jest babel-jest @types/jest

3. TypeScript configuration

In the root directory create a tsconfig.json file:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "declaration": true,
    "outDir": "./dist",
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "**/__tests__/*"]
}

4. Babel configuration

In the root directory create a babel.config.js file:

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          node: 'current',
        },
      },
    ],
  ],
};

5. Jest configuration

In the root directory create a jest.config.json file:

{
  "transform": {
    "^.+\\.(t|j)sx?$": "ts-jest"
  },
  "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
  "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"]
}

To run tests do:

npm test

6. Node module exporting

In the package.json above we referred to a file as "main": "dist/index.js",, which is main entry point to our package and allows us to use its definitions like:

import { MyClass } from 'cbjs'

So we create a file src/index.ts that pulls in all of our source files together:

export * from './util'
export * from './util_react'
export * from './util_rx'
export * from './contexter'
export * from './domainer'
export * from './firestore_sync'
export * from './firestore_sync_types'
export * from './input_streamer'

etc.

This index.ts file will get built into index.js.

7. Build it:

npm build

8. Push the package to GitHub:

The usual git init and pushing to GitHub.

9. Importing and using our package:

Once it is in GitHub we can use it in our other projects served directly from GitHub (we'll cover pushing it to the public npm repository in another blog post).

In the project we want to use it in, we can just add it:

npm install https://github.com/cardinalblue/react-contenteditable

or

yarn add https://github.com/cardinalblue/react-contenteditable

And then as mentioned above, in our source files:

import { MyClass } from 'cbjs'

const m = new MyClass(100)