DEV Community

loading...
Cover image for Make your npm package work on both Node.js and browser
Aspecto

Make your npm package work on both Node.js and browser

nirsky profile image Nir Hadassi Originally published at Medium ・2 min read

I recently worked on an npm package that is supposed to be consumed on both Node.js environment and the browser (using React/Angular/etc..).

Things started getting complicated when the node branch of the code needed to require native Node.js packages — like fs.

Consider the following (simplified) code:

// node-handler.js
const fs = require('fs');

export const handle = () => { 
  fs.readFileSync(…);
  …
};

// browser-handler.js
export const handle = () => { … };

// index.js
const nodeHandler = require('./node-handler').handle;
const browserHandle = require('./browser-handler').handle;
const isNode = require('./config').isNode;

const handle = isNode ? nodeHandler : browserHandle;
Enter fullscreen mode Exit fullscreen mode

When testing the module on my React + Webpack app, the app crashed:

Alt Text

This happened even though the node-handler file wasn’t executed, this is due to Webpack nature of creating a bundle containing all the code.

Step 1: Postpone your requires

Instead of requiring fs in the global scope, we can require it only where we actually need it, that way we don’t require it when running in the browser:

// node-handler.js
export const handle = () => { 
  require('fs').readFileSync(…);
  …
};

// browser-handler.js
export const handle = () => { … };

// index.js
const nodeHandler = require('./node-handler').handle;
const browserHandle = require('./browser-handler').handle;
const isNode = require('./config').isNode;

const handle = isNode ? nodeHandler : browserHandle;
Enter fullscreen mode Exit fullscreen mode

Cool! Our React app is not crashing anymore! But we do get an annoying compilation warning right now:
Alt Text

While we can live with a warning ⚠️ , our end-users will probably not like this too much and will end up not installing our package.

Step 2: eval your require

This is not the most elegant solution (to say the least..), but it’s keeping Webpack quiet and your end-users happy. Instead of using require('fs'), we’re gonna use eval('require')('fs'):

// node-handler.js
export const handle = () => { 
  eval('require')('fs').readFileSync(…);
  …
};

// browser-handler.js
export const handle = () => { … };

// index.js
const nodeHandler = require('./node-handler').handle;
const browserHandle = require('./browser-handler').handle;
const isNode = require('./config').isNode;

const handle = isNode ? nodeHandler : browserHandle;
Enter fullscreen mode Exit fullscreen mode

And that’s it! Just two simple steps to make your npm package work on both Node.js and browser.

Good luck and may you be blessed with tons of stars 🌟

Discussion (0)

pic
Editor guide