23

I have a library that can be used with both node.js and the browser. I am using CommonJS then publishing for the web version using webpack. My code looks like this:

// For browsers use XHR adapter
if (typeof window !== 'undefined') {
  // This adapter uses browser's XMLHttpRequest
  require('./adapters/xhr');
}
// For node use HTTP adapter
else if (typeof process !== 'undefined') {
  // This adapter uses node's `http`
  require('./adapters/http');
}

The problem I am encountering is that when I run webpack (browserify would do the same) the generated output includes http along with all it's dependencies. This results in a HUGE file which is not optimal for browser performance.

My question is how can I exclude the node code path when running a module bundler? I solved this temporarily by using webpack's externals and just returning undefined when including './adapters/http'. This doesn't solve the use case where other developers depend on my library using CommonJS. Their build will end up with the same problem unless they use similar exclude config.

I've looked at using envify, just wondering if there is another/better solution.

Thanks!

mzabriskie
  • 542
  • 1
  • 4
  • 10

4 Answers4

28

You may use IgnorePlugin for Webpack. If you are using a webpack.config.js file, use it like this:

var webpack = require('webpack')

var ignore = new webpack.IgnorePlugin(/^(canvas|mongoose|react)$/)

module.exports = {
  //other options goes here
  plugins: [ignore]
}

To push it further, you may use some flags like process.env.NODE_ENV to control the regex filter of IgnorePlugin

Avindra Goolcharan
  • 4,032
  • 3
  • 41
  • 39
daizhuoxian
  • 421
  • 6
  • 8
5

In order to exclude node_modules and native node libraries from being bundled, you need to:

  1. Add target: 'node' to your webpack.config.js. This will exclude native node modules (path, fs, etc.) from being bundled.
  2. Use webpack-node-externals in order to exclude all other node_modules.

So your result config file should look like:

var nodeExternals = require('webpack-node-externals');
...
module.exports = {
    ...
    target: 'node', // in order to ignore built-in modules like path, fs, etc. 
    externals: [nodeExternals()], // in order to ignore all modules in node_modules folder 
    ...
};
lyosef
  • 6,092
  • 2
  • 27
  • 20
1

This worked best for me

var _process;

try {
    _process = eval("process");  // avoid browserify shim
} catch (e) {}

var isNode = typeof _process==="object" && _process.toString()==="[object process]";

as Node will return true and not only will the browser return false, but browserify will not include its process shim when compiling your code. As a result, your browserified code will be smaller.

Edit: I wrote a package to handle this more cleanly: broquire

Steven Vachon
  • 3,814
  • 1
  • 30
  • 30
0

You can use require.ensure for bundle splitting. For example

if (typeof window !== 'undefined') {
    console.log("Loading browser XMLHttpRequest");

    require.ensure([], function(require){

        // require.ensure creates a bundle split-point
        require('./adapters/xhr');
    });
} else if (typeof process !== 'undefined') {
    console.log("Loading node http");

    require.ensure([], function(require){

        // require.ensure creates a bundle split-point
        require('./adapters/http');
    });
}

See code splitting for more information and a sample demo usage here

trekforever
  • 3,914
  • 25
  • 29