Read more

Webpack: How to avoid multiple versions of jQuery

Emanuel
April 29, 2019Software engineer at makandra GmbH

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.

Illustration UI/UX Design

UI/UX Design by makandra brand

We make sure that your target audience has the best possible experience with your digital product. You get:

  • Design tailored to your audience
  • Proven processes customized to your needs
  • An expert team of experienced designers
Read more Show archive.org snapshot

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:

Emanuel
April 29, 2019Software engineer at makandra GmbH
Posted by Emanuel to makandra dev (2019-04-29 17:31)