Here are my learnings when writing a npm package

Want to publish your first npm package, here is the steps that involved

Saravanan Ramupillai's photo
Saravanan Ramupillai
·Oct 1, 2021·

4 min read

Writing a library and giving to the community is always feels awesome, with that in mind i started writing a small React hooks for the github's hotkey library to simplifying its usage. I thought to distribute as package so that others also can use it if they find it useful. But following are the things i took my more hours.

1. Choosing the bundler

Since webpack is my favourite bundler i picked it up front, but i spent an hours to try out Rollup and Parcel but it requires my more time understanding their constructs. For the sake of time i stick with webpack.

Since i am only targeting modern browsers that supports ESM natively, I planned ship a only a latest code, ignoring legacy browsers like eg: ie11, edge < 16, so my webpack config became only a few lines.

const config = {
  mode: "production",
  entry: "./use.hotkey.js",
  output: {
    filename: "hotkey.js",
    // hinting webpack that, this is a library with 
    // native ESM module
    library: {
      type: "module"
    },
    // Tell webpack emit ESM code
    module: true,
  },
  experiments: {
    outputModule: true
  },
  // Ignore all peer-dependencies from bundling
  externals: {
    react: "react"
  },
  target: ["web", "es2020"],
  node: false,
}

2. Ignoring Peer Dependencies:

When writing a react hooks, we need a react package to use built in hook, so we will install it, but when bundling a package, we do not want include react because it will be available on the consumer land since consumer application also a react application.

In webpack, by using externals we can ignore react from being bundled into the package.

  // Ignore all peer-dependencies from bundling
  externals: {
    react: "react"
  },

We need to also makes sure that, react is not going into dependency section in pakcage.json, it has to be installed as peerDependency so that npm will resolve this package in the consumer application.

{
    "name": "",
    "version": "",
    "dependencies": {...},
    // installing as peer dependency
    "peerDependencies": {
       "react": "^17.0.0"
     }, 
}

4. Specifying package Entrypoint :-

This is important step in writing a package where we will specify which file to load when consumer imports our package. eg:

// At consumer application
import { useHotkey } from "@letslearn/hotkey"

In package.json we have exports, module, main keys to specify when file to load based on where our package is being used.

// package.json of library
{
   "name": "@letslearn/hotkey",

   // resolved when consuming in nodejs enviroment with ESM syntax
   "exports": "dist/hotkey.js" // ----> import {} from "@letslearn/hotkey"

   // resolved when consuming in nodejs environment with CommonJs module syntax
   "main": "dist/hotkey.cjs" // ----> const <variable> = require("@letslearn/hotkey")

   // resolved when consuming in browser with ESM syntax
   "module": "dist/hotkey.js" // ----> import {} from "@letslearn/hotkey"
}

4. Testing :-

When building a package it is essential to test as same as consumer of this packages by installing a package. In npm, we can install a package from file location

// At consumer application
npm install -S file:<relative path to package folder>

// eg:
npm install -S file:../hotkey

This command will install the package as like we install from npm registry. So it becomes easy to test our package like how consumer will do. And inside package.json the entry will looks like this

  "dependencies": {
    "hotkey": "file:../hotkey"
  },

5. Publishing :-

We use npm publish command to publish our package, but we need publish only the built package not the src. so we can one of life cycle hook of npm to build the package before publishing.

  "scripts": {
    "build": "rm -rf dist && webpack",
    // run build before publish
    "prepublishOnly": "npm run build"
  },

Also we do not want our packages to include unwanted files, like our source code, node_modules etc, that will increase the bundle size. To do so, we have .npmignore file much similar to .gitignore file.

// .npmignore file: ignoring node_modules
node_modules

And thats it, these are essential information to know for building and publishing npm package. Here is the full config https://github.com/saravanan10393/letslearn/tree/main/hotkey.

 
Share this