How to set up ES module library for the frontend JavaScript

Marcin Wosinek - Aug 29 '21 - - Dev Community

This article will show how to set up an npm library package as an ES module 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:

{
  "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"
}
Enter fullscreen mode Exit fullscreen mode

The library itself is very simple, library/index.js:

const valueA = "function A",
  valueB = "function B";

export function functionA() {
  return valueA;
}

export function functionB() {
  return valueB;
}
Enter fullscreen mode Exit fullscreen mode

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:

import { functionA } from "../../library";

console.log("Hello!", functionA());
Enter fullscreen mode Exit fullscreen mode

Alternatively, I could import the library as a whole:

import * as library from "../../library";

console.log("Hello!", library.functionA());
Enter fullscreen mode Exit fullscreen mode

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. The only change to webpack configuration was switching to production mode - otherwise, the build was full of comments. The resulting build command:

    "build": "webpack --mode=production" 
Enter fullscreen mode Exit fullscreen mode

Esbuild config

I used similar generate as above (esbuild-starter), and switched to minified output - so both bundlers are used in similar circumstances. The build command:

    "build": "esbuild --bundle src/index.js --outfile=dist/main.js --minify"
Enter fullscreen mode Exit fullscreen mode

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

(()=>{"use strict";console.log("Hello!","function A")})();
Enter fullscreen mode Exit fullscreen mode

Webpack (or Babel) is pretty smart about minification - it reduces all my code into a static value that is always the output.

esbuild

(()=>{var o="function A";function n(){return o}console.log("Hello!",n());})();
Enter fullscreen mode Exit fullscreen mode

esbuild is less efficient with simplification, but it correctly removes the other exported function.

Links

I cover basics of bundler in those video courses:

Summary

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

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player