🎉 I'm releasing 12 products in 12 months! If you love product, checkout my new blog workingoutloud.dev

Back to home

Building Typescript NPM Packages With Parcel 2

Parcel 2 has just been released 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, 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 and the example project that uses the package here

Prerequisites

  1. Basic familiarity with npm.
  2. Basic familiarity with Node.js.
  3. My post "Your First Github NPM Package in 5 Minutes".
  4. Familiarity with TypeScript.

Getting started

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

$ 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:

{ "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:

/** * 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:

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:

{ "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.
  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:

$ 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:

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

$ 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:

$ 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:

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

$ 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:

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.

First type error for no arguments.

Second type error for invalid arguments.

Second type error for invalid arguments.

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

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

Photo credit: biljaminai

Personal image

Dennis O'Keeffe

@dennisokeeffe92
  • Melbourne, Australia

Hi, I am a professional Software Engineer. Formerly of Culture Amp, UsabilityHub, Present Company and NightGuru.
I am currently working on Visibuild.

1,200+ PEOPLE ALREADY JOINED ❤️️

Get fresh posts + news direct to your inbox.

No spam. We only send you relevant content.

Building Typescript NPM Packages With Parcel 2

Introduction

Share this post