4

Library

I'm creating a React.js library and trying to package it as a UMD for distribution. In the library, the webpack.config.js file is as follows:

module.exports = {
  entry: [
    __dirname+'/modules/index.js'
  ],
  output: {
    path: path.join(__dirname, 'lib'),
    filename: 'index.js',
    library: 'MyLibrary',
    libraryTarget: 'umd'
  },
  externals: {
    root: 'React',
    commonjs2: 'react',
    commonjs: 'react',
    amd: 'react'
  },
  resolve: {
    extensions: ['', '.js']
  },
  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(true)
  ]
};

Running webpack correctly creates a UMD version in ./lib/index.js.

Consumer

However, when trying to consume this library in another project, Webpack mistakenly parses the require('react') statements within lib/index.js in MyLib and includes the React library twice.

The webpack.config.js file for the consumer is:

module.exports = {
  entry: [
    __dirname + '/src/index.js'
  ],
  output: {
    path: path.join(__dirname, 'dist'),
    pathinfo: true,
    filename: 'index.js'
  }
};

The entry point for the consumer is very simple (src/index.js):

React = require('react');
MyLib = require('my-lib');

console.log('React.Component', React.Component);

Running webpack in the consumer returns:

Version: webpack 1.12.11
Time: 1179ms
   Asset     Size  Chunks             Chunk Names
index.js  1.35 MB       0  [emitted]  main
   [0] multi main 28 bytes {0} [built]
   [1] ./src/index.js 199 bytes {0} [built]
 [170] ../my-lib/lib/index.js 165 kB {0} [built] [1 error]
    + 168 hidden modules

ERROR in ../my-lib/lib/index.js
Module not found: Error: Cannot resolve module 'react' in [...]my-lib/lib
 @ ../my-lib/lib/index.js 3:27-43

If I install react via npm within node_modules/my-lib then webpack will run without errors, but React.js will be included twice in the final output. Inspecting the built file shows that when Webpack encounters require('react') in node_modules/my-lib/lib/index.js it attempts to included a new version from the local node_modules directly instead of the already available version included from src/index.js.

I feel like I'm missing something really obvious here, but I'm not able to make any progress.

Ben Sargent
  • 41
  • 1
  • 3
  • Note: I found a workaround by forcing webpack in the consumer to resolve the root `node_modules` directory first (and thus find the instance of react already included). However this doesn't feel correct... `root: [ __dirname, path.resolve('./node_modules') ]` – Ben Sargent Jan 15 '16 at 20:56

1 Answers1

2

In node_modules/react/lib/ReactTransitionGroup.js React is included as a relative dependency:

var React = require('./React');

I don't know why in this specific file React is included this way instead of everywhere else in the React package.

var React = require('react');

Anyway, because of this, then React is included twice, as a node module (require('react')) and as a file module (require('./React.js')). Webpack will treat them as two different modules and will add them twice.

I have avoided this duplication making this relative module be an external dependency that points to the same React. The same as you did with the React module, but for both. Then it is only bundled once.

webpack.config.js

var reactExternals = {
  root: 'React',
  commonjs2: 'react',
  commonjs: 'react',
  amd: 'react'
};
var reactDOMExternals = {
  root: 'ReactDOM',
  commonjs2: 'react-dom',
  commonjs: 'react-dom',
  amd: 'react-dom'
};

module.exports = {
  entry: [
    __dirname+'/modules/index.js'
  ],
  output: {
    path: path.join(__dirname, 'lib'),
    filename: 'index.js',
    library: 'MyLibrary',
    libraryTarget: 'umd'
  },
  externals: [
    {
      'react': reactExternals,
      './React': reactExternals,
      'react-dom': reactDOMExternals
    }
  ],
  resolve: {
    extensions: ['', '.js']
  },
  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(true)
  ]
};
dreyescat
  • 13,558
  • 5
  • 50
  • 38
  • Thanks for the answer. I tried this but it didn't make a difference. I also tried doing the same thing using lodash instead of react to see if there was something particular about react and saw the same issue with lodash. – Ben Sargent Jan 15 '16 at 20:53
  • @BenSargent I have updated the `webpack.config.js` to ignore `react-dom` as externals too. In my config file it is also in externals because I consider it a `peerDependency` like `react`. Maybe it helps. – dreyescat Jan 15 '16 at 22:23