How to set up ES module library for the frontend JavaScript
Tags: javascript, webpack, esbuild
Published: 2021-08-29 16:29:35

This article will show how to set up an npm library package as an [ES module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) that can be easily used in other packages, with a minimum size impact. 

# Library code
I generated the `package.json` with `npm run -y`. The only difference was adding `"type": "module"`. `library/package.json`:
```JSON
{
  "name": "library",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
```

The library itself is very simple, `library/index.js`:
```JS
const valueA = "function A",
  valueB = "function B";

export function functionA() {
  return valueA;
}

export function functionB() {
  return valueB;
}
```
By moving values to const, I was hoping to trick bundler leave some redundant code, but they managed pretty well.

# Application code
As simple the library is the test application `webpack/src/index.js` & `esbuild/src/index.js`:
```JS
import { functionA } from "../../library";

console.log("Hello!", functionA());
```

Alternatively, I could import the library as a whole:
```JS
import * as library from "../../library";

console.log("Hello!", library.functionA());
```

But in my simplified example, both bundlers manage just fine to leave unnecessary code behind.

## Webpack config
I generated my code with my [webpack-starter](https://how-to.dev/how-to-quickly-start-a-webpack-project). The only change to webpack configuration was switching to production mode - otherwise, the build was full of comments. The resulting build command:
```JSON
    "build": "webpack --mode=production" 
```

## Esbuild config
I used similar generate as above ([esbuild-starter](https://github.com/how-to-js/esbuild-starter)), and switched to minified output - so both bundlers are used in similar circumstances.  The build command:
```JSON
    "build": "esbuild --bundle src/index.js --outfile=dist/main.js --minify"
```

# Build output
Both bundlers build the application code as they should - importing the one method we used and ignoring the other one. Interestingly, we didn't need to set `"sideEffects": false` to make it happen - just using ES modules seems to be enough. 

## Webpack output
```JS
(()=>{"use strict";console.log("Hello!","function A")})();
```
Webpack (or [Babel](https://babeljs.io/)) is pretty smart about minification - it reduces all my code into a static value that is always the output.

## esbuild
```JS
(()=>{var o="function A";function n(){return o}console.log("Hello!",n());})();
```
esbuild is less efficient with simplification, but it correctly removes the other exported function.

# Links
* [repository](https://github.com/how-to-js/es-module-library)
* [branch](https://github.com/how-to-js/es-module-library)

I cover basics of bundler in those video courses:
* [webpack course (free)](https://www.udemy.com/course/beginners-course-for-webpack-5/?referralCode=CF61F1A7C095ED2A63B8)
* [esbuild course](https://www.udemy.com/course/beginners-course-for-esbuild/?referralCode=24FF32FE03658251D9EB)

# Summary
In this article, we have seen one of the approaches you can take to build a JS library as an ES module.