Published on

Create your own typescript library with Parcel.js

Overview

If you find yourself writing the same typescript code over and over again it might be time to put this code into a reusable package.

There are many ways of doing this. Bundlers like Rollup has been around for quite some time, but require quite a lot of setup. Modern alternatives like Parcel provides almost zero config out of the box but can also be configured if you have specific requirements.

The finished code

The repo

The published package

Getting started

mkdir parcel-library-starter
cd parcel-library-starter
npm init -y

Install Parcel

npm install --save-dev parcel

Define project configuration in package.json

{
  "name": "@ihaback/your-typescript-lib",
  "version": "1.0.0",
  // The source field defines the entry point for your library
  "source": "src/index.ts",
  // The main field defines the target output of your library
  "main": "dist/main.js"
  // The types field will output a dist/types.d.ts file containing type definitions for your library
  "types": "dist/types.d.ts",
  // To add an ES module target, add the module field to your package.json
  "module": "dist/module.js"
}

Create the entrypoint file in src/index.ts

// Chunk an array into smaller arrays of a specified size
export const chunk = (arr: Array<any>, size: number) => {
  return Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
    arr.slice(i * size, i * size + size)
  )
}

Setup a basic tsconfig.json file in the root of the folder

{
  "compilerOptions": {
    "target": "ES5",
    "lib": ["ES2015"],
    "types": ["jest"],
    "esModuleInterop": true
  }
}

Setup a .gitignore file in the root of the folder

node_modules
dist
.parcel-cache
.cache
coverage

Add dev and build commands to package.json

When you build your package Parcel will automatically transpile your code into a dist folder, and generate types that can be used in a repo that consumes this package. The dev command is handy during development.

{
  "scripts": {
    "dev": "parcel watch",
    "build": "parcel build"
  }
}

Add dependencies for basic linting

npm i eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser prettier eslint-config-prettier eslint-plugin-prettier @parcel/packager-ts @parcel/packager-ts @parcel/transformer-typescript-types -D

Add a .eslintrc.js in the root of the project

module.exports = {
  env: {
    es2021: true,
    node: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
  },
  plugins: ['@typescript-eslint', 'prettier'],
  rules: {
    'prettier/prettier': [
      'error',
      {
        endOfLine: 'auto',
      },
    ],
  },
}

Add a .eslintignore in the root of the project

node_modules
.parcel-cache
dist
.eslintrc.js
package.json
package-lock.json
coverage

Add a lint script to your package.json

{
  "scripts": {
    "lint": "eslint . --fix"
  }
}

Add testing to your project with jest

npm i jest ts-jest @types/jest -D

Add a test for your code in src/index.test.ts

import { chunk } from '.'

describe('chunk', () => {
  test('should chunk array into smaller arrays of a specified size', () => {
    const bigArray = Array.from({ length: 100 }, (v, i) => i)

    const chunkedArray = chunk(bigArray, 25)

    expect(chunkedArray).toHaveLength(4)
  })
  test('should not chunck into multiple arrays if source array is less or equal to chunk size', () => {
    const bigArray = Array.from({ length: 100 }, (v, i) => i)

    const chunkedArray = chunk(bigArray, 100)

    expect(chunkedArray).toHaveLength(1)
  })
})

Add script for triggering tests and update package.json

{
  "scripts": {
    "test": "jest --coverage"
  },
  "jest": {
    "preset": "ts-jest"
  }
}

Prepare to publish your package to npmjs.com

Sign up on npmjs.com

Add a .npmignore file in the root of the project

**/.eslintrc.js
**/.eslintignore
**/.parcel-cache
**/.github/README.md
coverage

Update your package name to include your npmjs.com username

"name": "@your-username-here/your-package-name-here"
"name": "@ihaback/your-typescript-lib"

Publish your package to npmjs.com

npm login
npm publish --access public