Compiled bundle ignores “module.exports” values and exports empty object

Why does bundle ignore module.exports and exports only an empty object?

Here is an example. In real code there are React components instead of plain functions. To simplify things I use plain functions. I use Webpack to compile React components and make two bundles – one for client, one for server. The server bundle has module.exports. The browser bundle has ReactDOM.render.

ColorsComponents.js:

// const React = require('react');

// this is actually React.createClass with jsx syntax
const Green = function () {
    console.log('[Green]:');
}

// this is actually React.createClass with jsx syntax
const Red = function () {
    console.log('[Red]:');
}

module.exports = {
    Green: Green,
    Red: Red
};

browser.js entry chunk. This one is ok, this works as expected. I just include ready bundle on the page <script src="/js/browser.js" type="text/javascript" charset="utf-8"></script> and it works ok:

// const ReactDOM = require('react-dom');

const Red = require('./ColorComponents').Red;
const Green = require('./ColorComponents').Green;

ReactDOM.render(
    <Red />, document.getElementById('red')
)
ReactDOM.render(
    <Green />, document.getElementById('green')
)

server.js entry chunk. But the bundle from this entry chunk doesn’t work. It doesn’t export values:

const Red = require('./ColorComponents').Red;
const Green = require('./ColorComponents').Green;

module.exports = {
    Green: Green,
    Red: Red
};

And here is my server file (route.js) that requires server.js bundle and expects to import compiled React components from it:

const components = require('./server');
const Red = components.Red;
const Green = components.Green;

// But "components" is just an empty object:
console.log("['components']:", components); // [components]: {}

And webpack.config.js:

const path = require('path');

module.exports.default = {
    context: process.cwd(),
    entry: {
        server: ['.react/dev/server.js'],
        browser: '.react/dev/browser.js'
    },
    debug: 1,
    output: {
        filename: '[name].js',
        path: path.join(__dirname, 'react/stage'),
        publicPath: '/assets/js/',
    },
    module: {
        loaders: [{
            test: /\.js$/,
            loader: 'babel',
            exclude: /(node_modules)/,
            query: {
                presets: ["es2015", "stage-0", "react"]
            },
        }],
    },
}

Why does server.js bundle export empty object and doesn’t export specified values? What Webpacks’ technical restriction is that? What part of documentation explains it?

Author: Fantashit

11 thoughts on “Compiled bundle ignores “module.exports” values and exports empty object

  1. I’m facing the same problem. I’ve specified both library and libraryTarget, but no success.

    // /src/library.js
    module.exports = {
      foo: function() {
        console.log('bar');
      }
    };
    
    // /webpack.config.js
    output: {
          filename: 'library.js',
          path: './dist',
          library: 'library',
          libraryTarget: 'umd'
        }
    
    // in another node project
    var lib = require('library'); // returns empty object

    I’ve also tried other values for libraryTarget. :/

  2. I experienced the same problem before and the problem lies in the entry that you specified when targeting UMD

    entry: {
            server: ['.react/dev/server.js'],
            browser: '.react/dev/browser.js'
     }
    

    Webpack can’t figure out which one should be name as library. It would not make sense to have two entries that are named with the same library name. So it requires being a single file.

    I hope that helps 😄

  3. Haven’t had a chance to look into output.libraryExport, but I got this setup to work thanks to this blog post.

    ./src/library.js

    export default function example() { console.log('example'); }

    webpack.config.js

    module.exports = [{
      entry: './src/library.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'index.js',
        library: 'example',
        libraryTarget: 'umd',
        umdNamedDefine: true
      },
      ...

    package.json

    {
      "name": "example",
      "main": "dist/index.js"
    }

    client.js

    var example = require('example').default;
    example();
  4. @MeirionHughes answer works.

    output: {
        library: '',
        libraryTarget: 'commonjs'
      }
    

    The documentation definitely needs to be more clear.

    Cost me 2 hrs at the least trying to figure out something a simple as this.
    Or at least why is this not a default thing ?

  5. In my case, I had 2 entries: ['./src/index.scss', './src/index.js']
    Js MUST be second, otherwise you’ll get an empty object.

Comments are closed.