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;
When testing the module on my React + Webpack app, the app crashed:
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;
Cool! Our React app is not crashing anymore! But we do get an annoying compilation warning right now:
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;
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 🌟
Top comments (0)