DEV Community

Marcin Wosinek
Marcin Wosinek

Posted on • Originally published at how-to.dev

How to set up ES module library for the frontend JavaScript

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](https://github.com/how-to-js/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.

Discussion (0)