Replace Meteor base Jquery for the NPM one

I’m looking to upgrade the 1.11 version included by default with meteor to the NPM package which is in the version 3+. I’ve seen a couple of post on how to do this but they are quite old and at the end someone establishes the method is no longer working and that meteor is loading both the old and the new JQuery. Is there anyone that could point me in the right direction?

From History.md:

jquery is no longer in the default package list after running meteor create , however is still available thanks to blaze-html-templates . If you still require jQuery, the recommended approach is to install it from npm with meteor npm install --save jquery and then import -ing it into your application. #8388

If you have jquery in your .meteor/packages file, first remove it (meteor remove jquery or just delete the line in the file), then follow the above guidance.

Relevant issue: https://github.com/meteor/meteor/issues/10289

We ended up forking the jquery package and modifying it very much in the spirit of this PR: https://github.com/meteor/meteor/pull/10498/files

2 Likes

If you don’t use animations and care for your bundle size, you may consider this as a very thin replacement of jQuery: https://www.npmjs.com/package/cash-dom . It uses the same syntax. I have it in production and nothing to complain about.

1 Like

…also, if you don’t have to support some ancient legacy browsers :frowning:

I need some help. I updated my app from Meteor 1.8.1 to Meteor 1.9 hoping to rid myself of a duplicate jquery bundling and now I have three copies in my client bundle.

In my .meteor/packages I don’t have jquery added, I removed it after the update to Meteor 1.9. In my package.js I have "jquery": "^1.11.1" under dependencies.

In my bundle-visualizer it shows the following copies of jquery:

web.browser(modules)node_modulesjquerydistjquery.js
web.browser(jquery)node_modulesmeteorjqueryjquery.js
web.browser(aldeed_tabular)node_modulesmeteoraldeed:tabuarnode_modulesjquerydistjquery.js

When I do a meteor list --tree I only get the following packages that depend on jquery and all of them list jquery@1.11.10:

aldeed:autoform@6.3.0                                          
├─┬ jquery@1.11.10 
cultofcoders:persistent-session@0.4.5         
├─┬ amplify@1.0.0                             
│ └── jquery@1.11.10 (expanded above)                        
├── jquery@1.11.10 (expanded above) 
iron:router@1.1.2                                             
├─┬ iron:controller@1.0.12                                    
│ ├─┬ iron:dynamic-template@1.0.12               
│ │ ├── jquery@1.11.10 (expanded above) 
├─┬ iron:location@1.0.11                                         
│ ├── jquery@1.11.10 (expanded above) 
├─┬ meteortoys:blueprint@4.0.0                              
│ ├── jquery@1.11.10 (expanded above) 
tap:i18n@1.8.2                                          
├── jquery@1.11.10 (expanded above)  
themeteorchef:html5-sortable@0.1.6            
└── jquery@1.11.10 (expanded above)                      
twbs:bootstrap@3.3.6                          
└── jquery@1.11.10 (expanded above)  

So this is why I assumed I could just npm install --save jquery@1.11.1 (there is no NPM version @1.11.10) and then meteor remove jquery.

When I meteor npm ls I get the following jquery dependencies:

├─┬ datatables.net-bs@1.10.20
│ ├─┬ datatables.net@1.10.20
│ │ └── jquery@1.11.1 deduped
│ └── jquery@1.11.1 deduped
├── jquery@1.11.1
├─┬ owl.carousel@2.3.4
│ └── jquery@1.11.1 deduped
├─┬ parsleyjs@2.9.2
│ └── jquery@1.11.1 deduped
├─┬ pnotify@3.2.1
│ └── jquery@1.11.1 deduped

I understood it that the Meteor packages would find the NPM jquery package? And it seems that all the versioning is okay.

Do the Meteor packages need to be forked and have {weak: true} set for the dependencies? What am I doing wrong?

For the extra jquery in aldeed:tabular, I believe that’s from having the following jquery dependency code at meteor-tabular/.npm/package/npm-shrinkwrap.json:

{
  "dependencies": {
    "datatables.net": {
      "version": "1.10.12",
      "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.12.tgz",
      "from": "datatables.net@1.10.12"
    },
    "jquery": {
      "version": "3.1.1",
      "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.1.1.tgz",
      "from": "jquery@>=1.7.0"
    }
  }
}

Would I need to fork this and remove the above? Modify it?

Is there away to have the bundle-visualizer display versions and/or any data besides the paths? That would be helpful in this situation.

1 Like

I think the same issue applies for underscore, which is also hard-wired in some older ui packages

Something else that’s strange is if I remove my NPM jquery package, then bootstrap instantly errors out in my browser console when I load my app. My bootstrap package is the old Meteor version twbs:bootstrap (currently working on replacing with NPM version).

This is odd because it seems to indicate that a Meteor package with a jquery dependency is correctly looking and finding it in the node_modules folder. And this is without a {weak: true} attribute. If this is the case, then why is Meteor (seemingly) bundling it in above at web.browser(jquery)node_modulesmeteorjqueryjquery.js. As all the Meteor packages listed in meteor list --tree should be finding and using the NPM version.

I solved the aldeed:tabular inclusion of jquery. In the package.js file of that package they have the following:

Npm.depends({
  'datatables.net': '1.10.12'
});

When building in Meteor, this creates a node_modules folder with jquery and datatables.net folder that get shipped with the client (because datatables.net has a jquery dependency of jquery: >=1.7).

The weird thing is in the aldeed:tabular README it says to meteor npm install --save jquery@1.11.2 datatables.net-bs. datatables.net-bs depends on datatables.net so all of these get installed into your Meteor app’s node_modules. But aldeed:tabular never finds them and installs them both inside its own node_modules folder that gets shipped to the client.

I downloaded aldeed:tabular and removed the NPM.depends and the package works and doesn’t ship its own jquery or datatables.net-bs. I’m not sure why NPM.depends isn’t working correctly, but that fixed that particular copy of jquery shipping. On the README there’s something about it needing to find Meteor’s jquery or it would install its own. So maybe there’s a disconnect there now that I’m only shipping the NPM jquery. But why it re-installed datatables.net-bs over again with the exact same version? This shaved 200-300KB off my bundle! Now focusing on what seems to be the Meteor jquery getting included.

UPDATE: I thought the duplicate datatables.net-bs may have been that the README says to run meteor npm install --save datatables.net-bs which can install a present-day version later than 1.10.12 that mismatches the above NPM.depends. Then with the mismatch it install its own jquery and datatables.net-bs package??? But I tried removing and installing datatables.net-bs@1.10.12 and uncommenting out the NPM.depends and no luck. It rebuilt its own node_modules with jquery and datatables.net-bs.

Is there any known bugs or limitations around NPM.depends? I may try to make a small repo to see if I can reproduce for a bug report.

I did some more experimenting and removed every Meteor package I could that uses jquery or I copied it into packages and removed the jquery dependency. The goal was to remove every mention of jquery from meteor list --tree which I successfully did. Not even under blaze-html-templates@1.1.2 which I didn’t edit.

I ran my app and I got a jQuery not found error from Blaze:

var DOMBackend = {};
Blaze._DOMBackend = DOMBackend;

var $jq = (typeof jQuery !== 'undefined' ? jQuery :
           (typeof Package !== 'undefined' ?
            Package.jquery && Package.jquery.jQuery : null));
if (! $jq)
  throw new Error("jQuery not found");

Shouldn’t the new version of Blaze find my npm jquery?

So I did meteor add jquery which according to the Meteor 1.8.3 changelog says that it’s supposed to reference the npm version. I don’t think that’s happening though because after meteor add jquery my app started to run again but bundle-visualizer also reported two copies of jquery.

Upon looking at the files updated by PR#10498 I see the jquery package referencing version 3.4.1. So is the disconnect that Blaze needs jquery@^3.4.1 and is importing it as a Meteor package because it’s not satisfied my my npm package.js version "jquery": "^1.11.1"?

That’s the only thing I can think of. That or I’m completely lost in how all of this is supposed to work.

UPDATE: As an experiment I removed and then added jquery@3.0.0 in my npm package.js file to see if Blaze would find it since it seems to have a dependency option on npm jquery@3.0.0 on this line:

api.use('jquery@1.11.9 || 3.0.0', { weak: true });

But upon doing that, then remove meteor jquery I still get the above jQuery not found errors. So I meteor add jquery, run the app, and bundle-visualizer still reports two versions.

Yeah, the package infrastructure around jQuery is a mess.

Around Meteor 1.8.3 they did add the ability to use a npm version, without bundling it’s own copy of 1.12.x.
But, since jquery is a non-core package, it’s updates aren’t pinned to meteor versions, so the version of jquery installed is the thing that matters.
The new version that you want is jquery@3.0.0

Since you have several packages that depend on jquery@1.11.10, you’ll need to use the new special syntax to weaken the package dependencies.
In your .meteor/packages add:

jquery@3.0.0!

With the exclamation mark.
There’s further explanation on another topic here: Why is aldeed:autoform@6.3.0 trying to pull in jquery@1.11.6

Atmosphere packages and Npm.depends always bundle their dependencies completely separately, which causes a lot of duplication.
This is why the guide recommends that package authors should switch to using peer-dependencies and ask consumers to install npm packages at the top level, so that they can be deduplicated
https://guide.meteor.com/writing-atmosphere-packages.html#peer-npm-dependencies

So you’ve done the right thing by forking and removing Npm.depends with the required packages installed at the top level

3 Likes

Ah… thanks for connecting the dots. That fixed the issue! I was getting confused. So just for sanity, the line:

api.use('jquery@1.11.9 || 3.0.0', { weak: true });

means use either the Meteor jquery package at 1.11.9 or the new NPM friendly still-Meteor version 3.0.0. The 3.0.0 by itself has nothing to do with any NPM version, it just leaves off the jquery for brevity?

So then by adding jquery@3.0.0! and weakening all those Meteor package jquery dependencies, it will now use whichever version of jquery I have installed via meteor npm correct? And this is at the risk of that NPM-installed jquery having problems, side-effects, etc. with those Meteor packages?

Just want to make sure I’m understanding.

I was looking at Meteor’s underscore package and it does not appear to be updated like jquery@3.0.0 so you would still be double-bundling if you have have a NPM top-level or package dependency on underscore right? So Meteor and/or the community could do the same thing to underscore as they did for jquery? momentjs:moment has the same issue. It’s a common dependency however it’s not a core Meteor package.

Luckily I don’t use moment or underscore in any of my NPM packages, so there’s no double-bundling of those.

I’ll do a PR for aldeed:tabular about updating the NPM.depends.

Thanks so much for the clarity!

3 Likes