ignoring node_modules

I’m sure this has been talked about before, but I can’t find a clear issue for it. I’m playing around with using webpack with server-side node modules (using target: node). I started to like the idea of bundling of everything into a single js file because that would be cool for deployment, but what kills that idea is binary dependencies. They definitely can’t be bundled in, though you might know of a hack that lets me alias them or something.

Is there any way to tell the system ignore bundling anything coming from node_modules, and just leave it as a require statement?

I don’t know if the IgnorePlugin means that, but if so, trying it results in an error: plugins: [ new webpack.IgnorePlugin(/.*/, /.*node_modules.*/) ]

%% webpack --config webpack.node.config.js

/Users/james/projects/jlongster4/node_modules/webpack/lib/Compilation.js:203
                factory.create(module.context, dependencies[0], function(err, dependantModul
                                     ^
TypeError: Cannot read property 'context' of null
    at Tapable.<anonymous> (/Users/james/projects/jlongster4/node_modules/webpack/lib/Compilation.js:203:24)

Author: Fantashit

6 thoughts on “ignoring node_modules

  1. var node_modules = fs.readdirSync('node_modules').filter(function(x) { return x !== '.bin' });
    
    {
      target: "node",
      externals: node_modules,
      output: {
        libraryTarget: "commonjs2"
      }
    }
  2. You can also use webpack-node-externals to achieve this result:

    var nodeExternals = require('webpack-node-externals');
    ...
    module.exports = {
        ...
        externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
        ...
    };
    
  3. I just published webpack-externals-plugin. It has the advantage of supporting external modules that were installed after the initialization of the webpack compiler.

      plugins: [
        new ExternalsPlugin({
          type: 'commonjs',
          include: __dirname + '/node_modules',
        }),
      ],
  4. Bit different take but this is my preference. Instead of reading the file system, this just reads the package.json’s dependency names and includes them all as externals.

    The benefit to this approach is that I only exclude node_modules when compiling webpack libraries, and those dependencies should all be in the package.json for the library being webpack’ed.

    (I transpile my config with Babel)

    import packageJSON from './package.json'
    const { dependencies = {}, devDependencies = {}, peerDependencies = {}, optionalDependencies = {} } = packageJSON
    const dependencyNames = Array.from(new Set( [ ...Object.keys(dependencies)
                                                , ...Object.keys(devDependencies)
                                                , ...Object.keys(peerDependencies)
                                                , ...Object.keys(optionalDependencies)
                                                ] ))
    const externals = dependencyNames.reduce((externals, name) => ({ ...externals, [name]: true }), {})
    export default { externals 
                   , /** rest of config here */
                   }

    I have a few issues with the two popular approaches:

    regex to externalize non-relative paths

    • Almost good but frail when using webpack aliases to common areas in your app (they will look as though they are a node_module when really they should be bundled).

    Reading node_modules approach

    • Scoped modules go in a subdirectory within node_modules, if you try and import ‘@myscoped/package’ the external is only good for ‘@myscoped’ and your scoped modules will be bundled when they shouldn’t.
    • If you haven’t npm pruned prior to running webpack and your dependencies have changed there will be extra externals pulled in than should be.
    • There should be no scenario when you are importing a node_modules package within your library that is not called out in your package.json dependencies, but there will likely be many sibling libraries that get pulled in by NPM that you do not need to externalize.
    • npm 2 / 3 handle dependencies differently and there will be varying levels of recursion. Seems prone to breakage as library gets larger / more dependencies.

    If I am off on anything here please set me straight.

  5. @cchamberlain Great suggestion. I updated webpack-node-externals to accept modulesFromFile flag, that will read the modules from the package.json file instead of the node_modules dir:

    // webpack.config.js
    var nodeExternals = require('webpack-node-externals');
    ...
    module.exports = {
        ...
        externals: [nodeExternals({
            modulesFromFile: true
        })], // in order to ignore all modules in package.json when bundling
        ...
    };
  6. Here is my way to prevent node_modules from being bundled:

    { externals: [function (context,req,cb) {
            !/^\./.test(req)
              ? cb(null,req)
              : cb(null,false);
      }] 
    }

    Output bundle requests then look like this (require isn’t declared in result bundle):

    /***/ (function(module, exports) {
    
    module.exports = require("path");
    
    /***/ }),

Comments are closed.