# Building Typescript NPM Packages With Parcel 2

> See how easy it is to build a TypeScript NPM package using Parcel 2.

- Canonical: https://dennisokeeffe.com/blog/2021-10-15-building-typescript-npm-packages-with-parcel-2
- Published: 2021-10-15
- Updated: 2021-10-15
- Tags: nodejs, typescript, npm, parcel

Parcel 2 has [just been released](https://parceljs.org/blog/v2/) and along with it comes some improvements on top of the zero configuration experience we already know and love.

The zero-configuration capability draws massive appeal when writing and maintaining your own NPM packages.

In today's post, we'll look at how to build a small TypeScript NPM package using Parcel 2 and then install it into another NPM project to see it in action.

Note: this post will be deploying a GitHub NPM package. It will not cover the requires from an older post about [creating your first GitHub NPM Package](https://blog.dennisokeeffe.com/blog/2020-07-05-your-first-github-npm-package-in-five-minutes), but you will still be able to follow along. It is very similar for publishing NPM packages in general.

Source code for the final package can be found [here](https://github.com/okeeffed/hello-parcel-2-npm-packages) and the example project that uses the package [here](https://github.com/okeeffed/hello-parcel-2-npm-packages-using-pkg-example)

## Prerequisites

1. Basic familiarity with [npm](https://www.npmjs.com/).
2. Basic familiarity with [Node.js](https://nodejs.org/en/).
3. My post ["Your First Github NPM Package in 5 Minutes"](https://blog.dennisokeeffe.com/blog/2020-07-05-your-first-github-npm-package-in-five-minutes).
4. Familiarity with [TypeScript](https://www.typescriptlang.org/).

## Getting started

First, we will create our project that contains our package code.

```s
$ mkdir hello-parcel-2-npm-packages
$ cd hello-parcel-2-npm-packages
# Create a src directory to host the package contents
$ mkdir src
# initialise npm project with basics
$ npm init -y
$ npm install --save-dev parcel @tsconfig/recommended
# Create the required working files and a TypeScript configuration file
$ touch src/index.ts src/math.ts tsconfig.json
```

At this stage, our project is now ready to start working with.

Something worth noting: we are not actually installing TypeScript yet. We will see later that Parcel can do that for us based on the configuration requirements that it detects! You can of course install this yourself, but I wanted to demonstrate how helpful Parcel can be.

## Setting up our tsconfig.json file

Inside of `tsconfig.json`, add the following:

```json
{
  "extends": "@tsconfig/recommended/tsconfig.json"
}
```

The library `@tsconfig/recommended` that we installed comes with configuration files that are recommended for use. Since this is a simple example, we will use the recommended configuration by using the `extend` keyword in our local `tsconfig.json` file.

## Add in our library files

We are going to build an unbelievably contrived "math" library that will only contain the functions `add`, `subtract`, `divide` and `multiply`.

I use this contrived example as it is a good example of how to use TypeScript and Parcel to build a package.

Within `src/math.ts`, add the following:

```ts
/**
 * Adds two numbers together.
 *
 * @param x First argument.
 * @param y Second argument.
 * @returns Result of addition.
 */
export const add = (x: number, y: number): number => x + y;

/**
 * Subtract the second argument from the first.
 *
 * @param x First argument.
 * @param y Second argument.
 * @returns Result of subtraction.
 */
export const subtract = (x: number, y: number): number => x - y;

/**
 * Multiplies two numbers together.
 *
 * @param x First argument.
 * @param y Second argument.
 * @returns Result of multiplication.
 */
export const multiply = (x: number, y: number): number => x * y;

/**
 * Divides the first argument by the second.
 *
 * @param x First argument.
 * @param y Second argument.
 * @returns Result of division.
 */
export const divide = (x: number, y: number): number => x / y;
```

I won't explain the above: it is simple arithmetic. We are just exporting contrived versions of the functions.

We will let `index.ts` be the entry to our package, so inside of that file we will want to export those functions:

```ts
export { add, subtract, multiply, divide } from "./math";
```

I am being explicit with my export statement here (in case we have any functions we don't accidentally want to export), but you can also just export the whole `math` file for our example.

At this stage, we are almost ready to build our package.

## Setting up package.json for Parcel 2 and the GitHub NPM registry

Finally, the last thing we want to do is setup some key-value pairs in our `package.json` file. Mine will look like the following:

```json
{
  "name": "@okeeffed/hello-parcel-2-npm-packages",
  "version": "1.0.0",
  "description": "My first npm package built on Parcel 2",
  "source": "src/index.ts",
  "main": "dist/main.js",
  "module": "dist/module.js",
  "types": "dist/types.d.ts",
  "scripts": {
    "watch": "parcel watch",
    "build": "parcel build"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@tsconfig/recommended": "^1.0.1",
    "parcel": "^2.0.0"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/okeeffed/hello-parcel-2-npm-packages.git"
  },
  "bugs": {
    "url": "https://github.com/okeeffed/hello-parcel-2-npm-packages/issues"
  },
  "homepage": "https://github.com/okeeffed/hello-parcel-2-npm-packages#readme",
  "publishConfig": {
    "registry": "https://npm.pkg.github.com/"
  }
}
```

Here are some explainers:

1. I've set the package name to `@okeeffed/hello-parcel-2-npm-packages` which will be what we export from in our example project.
2. The `source` key tells Parcel where the entry to our project is.
3. `main.` is the target output file of our build as CommonJS while `module` is our destination for an ES module. See more [here](https://parceljs.org/getting-started/library/#project-setup).
4. `types` is the destination for the TypeScript definition file. Parcel will manage this for us!
5. Under `scripts`, we add a `watch` script to run Parcel in watch mode for development, and a `build` script to build your project for release.

At this point, we already just want to build, so run `npm run build` in your terminal.

You will notice in the output that Parcel lets you know that it detected the package and installs everything it needs. Once installed, you will then get the output from the build:

```s
$ npm run build

> @okeeffed/hello-parcel-2-npm-packages@1.0.0 build
> parcel build

✨ Built in 115ms

dist/main.js       794 B    48ms
dist/module.js     525 B    38ms
dist/types.d.ts    826 B    37ms
```

Amazing! We see our three files being build out.

If we go back and check out `package.json` file now, we will see a change to our `devDependencies` which Parcel managed for us based on the detected configuration:

```json
{
  "devDependencies": {
    "@parcel/packager-ts": "^2.0.0",
    "@parcel/transformer-typescript-types": "^2.0.0",
    "@tsconfig/recommended": "^1.0.1",
    "parcel": "^2.0.0",
    "typescript": "^4.4.4"
  }
  // ... rest omitted for brevity
}
```

It installed `typescript` along with the required `@parcel/*` namespace packages.

## Publishing the package

I already have everything configured that I need to publish my package to the GitHub repository under the `@okeeffed` namespace, so I can just run `npm publish`.

```s
$ npm publish
npm notice
npm notice 📦  @okeeffed/hello-parcel-2-npm-packages@1.0.0
npm notice === Tarball Contents ===
npm notice 255B  README.md
npm notice 794B  dist/main.js
npm notice 1.3kB dist/main.js.map
npm notice 525B  dist/module.js
npm notice 1.3kB dist/module.js.map
npm notice 826B  dist/types.d.ts
npm notice 481B  dist/types.d.ts.map
npm notice 111B  kratos.json
npm notice 953B  package.json
npm notice 58B   src/index.ts
npm notice 824B  src/math.ts
npm notice 55B   tsconfig.json
npm notice === Tarball Details ===
npm notice name:          @okeeffed/hello-parcel-2-npm-packages
npm notice version:       1.0.0
npm notice filename:      @okeeffed/hello-parcel-2-npm-packages-1.0.0.tgz
npm notice package size:  1.9 kB
npm notice unpacked size: 7.5 kB
npm notice shasum:        9d7a9334e4c882889cf675b0bc66d2012c4d544f
npm notice integrity:     sha512-tbvdBfNuz4Z/D[...]iz9IZy5ToZ1+A==
npm notice total files:   12
npm notice
+ @okeeffed/hello-parcel-2-npm-packages@1.0.0
```

Peaches! We published our package! Now is the time to see it in use.

## Playing around with our new package

From whichever folder you choose, we can create another project:

```s
$ mkdir hello-parcel-2-npm-packages-
using-pkg-example
$ cd mkdir hello-parcel-2-npm-packages-
using-pkg-example
# Intializing a new project
$ npm init -y
# Install prerequisites
$ npm install --save-dev typescript tslib @tsconfig/recommended @swc-node/register
$ touch index.ts tsconfig.json
```

I have installed some prerequisite libraries here to run a `ts` file with Node.js.

Update `package.json` so that it matches the following:

```json
{
  "name": "hello-parcel-2-npm-packages-using-pkg-example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "node -r @swc-node/register index.ts"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@swc-node/register": "^1.3.5",
    "@tsconfig/recommended": "^1.0.1",
    "tslib": "^2.3.1",
    "typescript": "^4.4.4"
  }
}
```

There isn't anything too special here, but know that we have a script `dev` that will run our `index.ts` file with Node.js after letting SWC Node handle the transformation.

Finally, it is time to installed our package.

```s
$ npm install @okeeffed/hello-parcel-2-npm-packages

added 1 package, and audited 2 packages in 2s

found 0 vulnerabilities
```

Again, I already have the configuration for my `~/.npmrc` file to be allowed to publish and install from that namespace.

Inside of `index.ts`, add the following:

```ts
import {
  add,
  subtract,
  multiply,
  divide,
} from "@okeeffed/hello-parcel-2-npm-packages";

function main() {
  console.log(add(2, 1));
  console.log(subtract(2, 1));
  console.log(multiply(2, 2));
  console.log(divide(2, 2));
}

main();
```

Here I am use calling our main function to run our code which logs out examples of all of our functions.

While you are here, begin to play around with the imports and functions. Notice that because Parcel handled the type output, we are already getting type information for our functions.

![First type error for no arguments.](https://cdn.dennisokeeffe.com/assets/2021-10-15-building-typescript-npm-packages-with-parcel-2/1-no-arguments.png)

![Second type error for invalid arguments.](https://cdn.dennisokeeffe.com/assets/2021-10-15-building-typescript-npm-packages-with-parcel-2/2-invalid-argument-type.png)

Finally, if we run `npm run dev` we can see our desired output and the package working as expected:

```s
$ npm run dev

> hello-parcel-2-npm-packages-using-pkg-example@1.0.0 dev
> node -r @swc-node/register index.ts

3
1
4
1
```

## Summary

Today's post demonstrated how awesome Parcel 2 can be. It makes life super easy when you can focus on the code and let it handle the output.

We built a (super contrived) package as a demonstration and installed it into another project to see the results of the output from Parcel 2.

I strongly recommend that you check out the [Parcel documentation](https://parceljs.org/) for more information on how to use Parcel and have a play around! I certainly will be updating a few of my repos to let Parcel handle the hard work.

## Resources and further reading

- [NPM](https://www.npmjs.com/).
- [Node.js](https://nodejs.org/en/).
- [Source code](https://github.com/okeeffed/hello-parcel-2-npm-packages)
- [Source code for the project using the new package](https://github.com/okeeffed/hello-parcel-2-npm-packages-using-pkg-example)
- [Parcel](https://parceljs.org/)
- ["Creating your first GitHub NPM Package" blog post](https://blog.dennisokeeffe.com/blog/2020-07-05-your-first-github-npm-package-in-five-minutes)

_Photo credit: [`biljaminai`](https://unsplash.com/@biljaminai)_
