How to Build and Publish NPM packages with Webpack

Stan Georgian
ITNEXT
Published in
5 min readMay 28, 2020

--

Photo by Pankaj Patel on Unsplash

Foreword

Recently I published my first NPM package 😊 and these are the problems I encountered and that’s how I solved them.

My library is a low-level implementation of an event listener for swipe events. I first wrote the code some years ago and even though today there are other solutions for this problem, I still thought about improving it a little and making it public. In this way, I also bring my small contribution to the open-source community.

Even-though the extra features and the wrapping didn’t take me long to implement them, however, it took me just as long to figure out how to deploy it properly.

The current version of my package is 1.0.3 and that’s only because 1.0.0, 1.0.1 and 1.0.2 were just failed builds…

It took me a while to figure how to export my library and make it available, based on the case, for both global scope (window), but also to be able to be imported as a module. Not to mention the particularities of the NPM platform.

So without any further talk here is my entire workflow and how can you do it.

The recipe

I. Project setup

My stack for front-end is Angular for web applications — I consider a web application to be a website that contains user-generated content — and for all others, small scripts or simple websites with static content, just like my personal website georgianstan.ro, I use TypeScript, SCSS, and PUG along with Webpack.

I prefer this stack because it not only allows you to move fast but also helps you meet all the requirements of a good NPM package.

  • available in global scope if the code is linked using a <script src=".."></script> tag
  • available using import or require if the code is a module
  • it has TypeScript support

And this one is purely personal:

  • if there is any styling code (CSS), then it’s included and managed by the JavaScript file; this way I only need to import one file in my project

So as not to lengthen this article for no reason I decided to wrap all the code in a GitHub project, that works as a boilerplate / framework for what we are trying to accomplish, and based on it I’ll explain the important parts 😊 .

Go ahead and download the repository or look over the code examples here.

Project Structure

Files and folders explained:

  • dist — distribution of our code
  • src — here we’ll write the code for our library
  • test — test folder for our code
  • .npmignore — same as .gitignore, but for npm; what files to be ignored when we publish our package
  • index.html — if you want to manually test your code on the browser
  • postcss.config.js — automate routine CSS operations; default, it’s configured to use autoprefixer for CSS
  • jest.config.js and setupJest.ts — config rules for Jest, which is used for testing
  • tsconfig.json — config rules for TypeScript
  • webpack.config.js — config rules for our code bundler

The other ones:

  • .eslintrc.js, .prettierrc — rules for linting and code formatting

II. NPM Config

To build a valid NPM package, you need to add the following properties in package.json:

"main": "./dist/my-library.js",
"types": "./dist/my-library.d.ts",
"files": [
"dist"
],

These properties represent the path to the main file and its data types, if there are any.

III. TypeScript config

We know that tsconfig.json is used to configure TypeScript. In order to emit types for your code, all you need to do is to add the following property in this file inside compilerOptions property.

“declaration”: true

IV. Webpack config

For Webpack, the most important configuration is represented by the following options:

Code HERE
  • target — use web or node based on the environment in which your code will be used
  • entry — entry point/points of our library
  • output.filename — the filename of the distributed code
  • output.library — this will be the name of the object which will be exported

The property libraryTarget is used to indicate what global object will be used to mount the library. To make the library build available on both browsers and Node.js, we used output.globalObject option to 'this' . 'this' means the global object of the environment, in case of a web browser 'this' will be the object window.

In simple terms, if our library code looks like this:

Code HERE

then the previous rules will allow us to do this

.html file

<script src="./dist/my-library.js"></script><script>
const { isPrimeNumber } = window.MyLibrary;
</script>

but also this

.js or .ts file

import { isPrimeNumber } from 'npm-package-name or path-to-the-file';

You can read more about this, on their official documentation page.

V. Publishing the code

To publish the code, open a terminal and navigate to the root folder of your project.

The first step is to log in to npm

npm login

After this, you can submit your package using:

npm publish

Before this, be sure that you built your code. For this you can add one script in package.json with this value:

"prepublishOnly": "webpack --mode=production",

This command will be executed when you run, npm publishbut before publishing the code.

Extra tips

  1. If you want to delete your package from npm, then use this command:
npm unpublish [package_name]

2. Each time you deploy a new version of your library, be sure to update the version from package.json

"version": "1.0.0", -> "version":"1.0.1"

A good description of this three-digit versioning system can be found here.

3. Test locally

You can test your package locally using this command:

npm link

For example

RAW

In conclusion, I hope you found this information useful. I know that if you are a beginner in both Webpack and code bundling you may find this article loosely.

For this, you can take a look at the documentation written here, where a series of steps that you can follow are presented in a more compressed way.

Or if you have some more accurate questions about something that is not clear then you can always leave me a message on twitter @georgianstan09 😊.

--

--