Javascript bundler mysteries! Can we do that on browser ?

Important Note!

Automatic Node.js polyfills are removed with webpack 5!!! check it here


So, I was working on some experimental crypto stuff today when I literally became the guy on the famous meme myself.

The idea is to create a simple digital signature using secp256k1. For more info check secp256k1 , Elliptic Curve Digital Signature Algorithm

I was trying a simple gist that will :

  • create a keypair
  • take a message
  • hash it
  • sign the hash with the private key
  • verify the signature with public key

Example code is here :

const crypto = require("crypto")

const EC = require('elliptic').ec;
const hash = data => crypto.createHash('sha256').update(data).digest("hex")
// Create and initialize EC context
// (better do it once and reuse it)
const ec = new EC('secp256k1');

// Generate keys
const keys = ec.genKeyPair();
const publicKey = keys.getPublic("hex")
const privateKey = keys.getPrivate("hex")

console.log(privateKey,publicKey)

const sign = (data, privateKey) => ec.keyFromPrivate(privateKey).sign(hash(data)).toDER()
const verify = (data, signature, publicKey) => ec.keyFromPublic(publicKey, "hex").verify(hash(data), signature)

const data = "Hello"
const signature = sign(data, privateKey)

console.log(signature.join("."),verify(data,signature, publicKey))

Now I try to run my code : node index.js . IT WORKS!

Afterwards, I wanted to be able to sign on the browser as well. Since crypto is a core node module I wasn't expecting it first to work on browser.

My first attempt was to use parcel-bundler .

  • Create an index.html
  • Call <script src="./index.js"> in index.html
  • Run parcel index.html
  • Voilá! On the browser it works!

But then I was like "Why does it work ?"

I wanted to know where crypto module was required. So added a new line to my code on top:

const crypto = require("crypto")
console.log(require.resolve('crypto'))
const EC = require('elliptic').ec;

...

When I run node index.js that console.log prints the String crypto only. But on the browser console there was something uncanny!

Did you see that ../../.config/yarn/global/node_modules/crypto-browserify/index.js too ?

I packed up my backpack, kissed me darling mother and went on an adventure of stalking code, sniffing the github repos. Even though I thought it was going to be a needle in the haystack I came across some resources which actually revealed the mystery.

Turns out browserify has a builtins.js that maps some of the nodejs core modules to their browser equivalents and in build-time, requires them.

I found out parcel and webpack use a webpack-core library called node-libs-browser to replace those modules with their browser equivalents.

I couldn't find any explanation about this feature in any of their documentation. Even though it bugs me to find out there is some magic happening behind the curtains, sometimes it is nice to have those kind of out of the box features. This feature did not only saved me time, but also added fun to this evening!

Peace!