Create your own typescript library with Parcel.js
Tags: npm, typescript, opensource
Published: 2022-04-16 21:20:51

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](https://rollupjs.org/guide/en/) has been around for quite some time, but require quite a lot of setup. Modern alternatives like [Parcel](https://parceljs.org/) provides almost zero config out of the box but can also be configured if you have specific requirements.

### The finished code

[The repo](https://github.com/ihaback/parcel-library-starter)

[The published package](https://www.npmjs.com/package/@ihaback/your-typescript-lib)

### 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

```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

```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

```json
{
    "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.

```json
{
  "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
```js
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
```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
```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
```json
{
  "scripts": {
    "test": "jest --coverage",
  },
  "jest": {
    "preset": "ts-jest"
  }
}
```
### Prepare to publish your package to npmjs.com
[Sign up on npmjs.com](https://www.npmjs.com/signup)

### 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
```json
"name": "@your-username-here/your-package-name-here"
```
```json
"name": "@ihaback/your-typescript-lib"
```

### Publish your package to npmjs.com
```
npm login
```
```
npm publish --access public
```