Multiple library versions conflict with submodules.

Do you want to request a feature or report a bug?
I want to report a potential bug.

I created also a stackoverflow topic, but then decided that it may be a bug, so…
https://stackoverflow.com/questions/48825061/webpack-different-version-of-the-same-library

What is the current behavior?

I have a project, which uses the current version of lodash library 4.17.5.

This project has as its dependency another module, which is basically lite version of codemirror. https://www.npmjs.com/package/vue2-codemirror-lite-js

The codemirror module uses JSHINT as it’s dependency, and JSHINT relies on the lodash version 3.x.

Now, as I have a lodash 4.x version in my project, whenever a require is called in JSHINT it requires a 4.x version instead of 3.x version and complains about lack of methods, which are no longer supported by lodash 4.x.

Specifically: _.contains is not a function as contains method was replaces with includes method in versions 4.+

In my node_modules/lodash I have a lodash 4.x version while in my node_modules/jshint/node_modules/lodash is version 3.x

I use a webpack 3.11.0

If the current behavior is a bug, please provide the steps to reproduce.

What is the expected behavior?

Webpack should bundle modules in a way which would allow for automatic module version resolution.

If this is a feature request, what is motivation or use case for changing the behavior?

Please mention other relevant information such as the browser version, Node.js version, webpack version, and Operating System.

My webpack config:

var path = require('path')
var config = require('../config')
var utils = require('./utils')
var webpack = require('webpack')
var projectRoot = path.resolve(__dirname, '../')

module.exports = {
 entry: {
  app: './src/main.js'
 },
 output: {
  path: config.build.assetsRoot,
  publicPath: process.env.NODE_ENV === 'production' ? "." + 
  config.build.assetsPublicPath : config.dev.assetsPublicPath,
  filename: '[name].js'
},
 resolve: {
extensions: ['.js', '.vue'],
alias: {
  'src': path.resolve(__dirname, '../src'),
  'assets': path.resolve(__dirname, '../src/assets'),
  'components': path.resolve(__dirname, '../src/components'),
  'scss': path.resolve(__dirname, '../src/scss'),
  'services': path.resolve(__dirname, '../src/services'),
  'ui': path.resolve(__dirname, '../src/components/UI'),
  'utility': path.resolve(__dirname, '../src/util.js'),
},
modules: [
  path.join(__dirname, '../node_modules')
]
},
resolveLoader: {
modules: [
  path.join(__dirname, '../node_modules')
],
},
module: {
 rules: [
  {
    test: /\.vue$/,
    enforce: 'pre',
    loader: 'eslint-loader',
    include: projectRoot,
    exclude: /node_modules/
  },
  {
    test: /\.js$/,
    enforce: 'pre',
    loader: 'eslint-loader',
    include: projectRoot,
    exclude: /node_modules/
  },
  {
    test: /\.vue$/,
    loader: 'vue-loader'
  },
  {
    test: /\.(js|js.flow)$/,
    loader: 'babel-loader',
    include: projectRoot,
    exclude: /node_modules/,
  },
  {
    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
    loader: 'url-loader',
    options: {
      limit: 10000,
      name: utils.assetsPath('img/[name].[hash:7].[ext]')
    }
  },
  {
    test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
    loader: 'url-loader',
    options: {
      limit: 10000,
      name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
    }
  }
]
},
plugins: [
 new webpack.LoaderOptionsPlugin({
  options: {
    eslint: {
      formatter: require('eslint-friendly-formatter')
    },
    vue: {
      loaders: utils.cssLoaders(),
      postcss: [
        require('autoprefixer')({
          browsers: ['last 2 versions']
        })
      ]
    }
  }
})
]
}

I found a ‘hackish’ way to solve the issue, but still it doesn’t feel to be the right solution. If I alias the gloabl lodash as lodash4, and the lodash required by subsubdependency lodash, and then in my modules import/require lodash4 instead of lodash it works.

 // This is a hack which solves the issue, but still a hack.
'lodash4': path.resolve(__dirname, '../node_modules/lodash'),
'lodash': path.resolve(__dirname, '../node_modules/jshint/node_modules/lodash'),

This is a part of the ouput from npm ls command.

image

Author: Fantashit

2 thoughts on “Multiple library versions conflict with submodules.

  1. modules: [
      path.join(__dirname, '../node_modules')
    ]

    This forces all modules to resolve from the root node_modules.

    modules: [
      'node_modules'
    ]

    This resolves node_modules hierachically. This is the default. Just omit this configuration.

  2. I see that this import wiil now resolve the top level lodash and thus include lodash 4.x into the bundle.

    However codemirror depends on lodash 3.x and will now be using 4.x. Isn’t this a dangerous approach? What happens if codemirror functionality now breaks? Shouldn’t we resolve the dependency issue at build time by flattening the node modules tree?

Comments are closed.