Webpack: How to avoid multiple versions of jQuery

Updated . Posted . Visible to the public. Repeats.

To avoid multiple versions of a package, you can manually maintain a resolutions section in your package.json. We recommend you to do this for packages like jQuery. Otherwise the jQuery library attached to window might not include the functions of your packages that depend on jQuery.

Note: This is only an issue in case you want to use a package functionality from window e.g. $(...).datepicker() from your dev console or any other javascript within the application.

Background

By default yarn will create a folder node_modules that includes all packages and their dependencies. In the example below we see two packages of jQuery. Such duplicates will occur each time no common version could be found or for other reason (like in the example where a common version would have been possible).

yarn.lock

jquery@2.x:
  version "2.2.4"
  resolved "https://registry.yarnpkg.com/jquery/-/jquery-2.2.4.tgz#2c89d6889b5eac522a7eea32c14521559c6cbf02"
  integrity sha1-LInWiJterFIqfuoywUUhVZxsvwI=

"jquery@>=1.7.1 <4.0.0":
  version "3.4.0"
  resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.0.tgz#8de513fa0fa4b2c7d2e48a530e26f0596936efdf"
  integrity sha512-ggRCXln9zEqv6OqAGXFEcshF5dSBvCkzj6Gm2gzuR5fWawaX8t7cxKVkkygKODrDAzKdoYw3l/e3pm3vlT4IbQ==

package.json

{
  "dependencies": {
    "@rails/webpacker": "4.x",
    "bootstrap-datepicker": "1.8.0", # the package says it needs "jquery": ">=1.7.1 <4.0.0" as a dependency
    "jquery": "2.2.4",
}
node_modules/jquery
node_modules/bootstrap-datepicker/node_modules/jquery

Actual issue

Within the Rails Webpacker config we now provide a jQuery object to boostrap-datepicker:

config/webpack/environment.js

environment.plugins.prepend(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    'window.jQuery': 'jquery',
  })
)

And a jQuery object to window, to have access to jQuery from our dev console or any other javascript within the application.

app/webpack/packs/main.js

window.$ = jQuery
window.jQuery = jQuery

Now this will not allow us to use any functionality from boostrap-datepicker on the window object.

$('<div></div>').datepicker() // Uncaught TypeError: $(...).datepicker is not a function

Solution

You can maintain a resolutions section within your package.json. This allows you to force the same version of a package for all or an individual package. Another approach (not yet tested) is to set a resolve alias for jquery.

Force all dependencies to use jQuery 2.2.4

{
  "dependencies": {
    "@rails/webpacker": "4.x",
    "bootstrap-datepicker": "1.8.0",
    "jquery": "2.2.4",
  },
  "resolutions": {
    "jquery": "2.2.4"
  }
}

Force bootstrap-datepicker to use jQuery 2.2.4

{
  "dependencies": {
    "@rails/webpacker": "4.x",
    "bootstrap-datepicker": "1.8.0",
    "jquery": "2.2.4",
  },
  "resolutions": {
    "bootstrap-datepicker/jquery": "2.2.4"
  }
}

Carvet: Using resolutions will ignore any compatibilities. This might break the packages functionality.

Note: You can use yarn install --flat to find all duplicated packages in your project and add a resolution entry for each. You should throw away the changes in your package.json afterwards, as this approach will not work with real world projects.

References:

Last edit
Tobias Kraze
License
Source code in this card is licensed under the MIT License.
Posted by Emanuel to makandra dev (2019-04-29 15:31)