Last summer, mostly while working from my kitchen table, I was involved in what was probably the biggest project I’ve been part of at CQL: updating multiple client websites from jQuery version 1.7.1 to version 3.4.1.
Now, you’re probably thinking, “But wait, isn’t the latest version of jQuery 3.5.1?!” Yes, but that didn’t exist at the time of this project’s formulation. We’ll get there later in this post, though, don’t worry. For now, back to my kitchen table.
I’ll admit to being more than a little bit intimidated when I was told that I’d be doing most of the development work for the project. There I was, barely a year out of college, about to be performing major surgery on a massive codebase used by fourteen brands across thirty-some websites.
Of course, I was far from alone in this endeavor: we had a thoroughly laid out plan of attack, and I had the wisdom and help of my CQL comrades to fall back upon in times of need.
And so, bolstered by the encouragement of our fearless project manager, the operation began…and promptly ran into a Godzilla-sized problem: going from jQuery v1.7.1 to v3.4.1 was simply too big of a jump to be able to do in one step.
In order to take advantage of the available helper tools, like the jQuery Migration plugin, we determined that we would need to update to version 1.12 as a first step, and then update to version 3.4.1 from there.
Introducing the Magnificent jQuery Migrate Plugin
If you’re going to be working on updating the jQuery version in your code, the jQuery Migrate plugin will be your best friend. jQuery Migrate is a splendidly helpful tool that eases the update process immensely by finding and pointing out pieces of code that need to be updated.
All you have to do is add it to your site, along with the version of jQuery that you’re updating to, and the plugin will provide the functionality of anything deprecated in the old jQuery version (so that your code doesn’t just error out). Then, it prints out a warning in the browser console stating what deprecated thing was used, along with a stack trace so that you can actually find it in your code.
Essentially, what the plugin does is yell at you through the browser console instead of just letting your code explode in a bloodbath of errors. It even spits out a stack trace to help you hunt down the offending code:
And, if that weren’t already marvelous enough, each version of the plugin includes a documentation page (warnings.md in the GitHub repository) that lists and explains all of the possible warnings that the tool might output, and how to fix them. These pages were my primary resource and I referred to them pretty much constantly while working on the updates.
Be Warned: Updating jQuery is Perilous
Okay, that might be a bit of an overstatement, but the point remains: even with such a noble guide as jQuery Migrate, there are still plenty of potential pitfalls. For instance, the plugin only outputs a particular warning in the browser console once per page load, even if the thing it’s warning about occurs in more than one place. Also, it only outputs a warning at all when code that uses a deprecated thing actually runs. This means that, unless you run through every last bit of functionality in your code, there might be some sneaky deprecated jQuery stuff hiding in your code that the migration tool won’t warn you about.
With that in mind, it would be a good idea to also run some searches in your codebase for each of the deprecated things instead of relying solely on the plugin to point out everything that needs to be updated. Another thing to keep in mind is that uses of jQuery aren’t necessarily limited to .js files: if you’ve got HTML/template files with
<script> tags in them, there could potentially be some jQuery hiding in there as well.
Yet another sneaky thing to watch out for is that some of the deprecated jQuery methods have the same name as other non-jQuery things. This means you might have to dig into the context to figure out if a particular piece of code actually is using jQuery or not. Plus, if you use variables as parameters to jQuery methods, you might have to add some logic to your code to ensure that those variables are always the correct types and can’t have invalid values.
Last but not least, don’t forget about any plugins or integrations you might have installed in your codebase. Sure, they might have been developed by somebody else, but if your code uses them and they use some deprecated jQuery, the end result is the same as if your code were using the deprecated thing directly. In other words, they’re still your problem, at least a little bit, and you’ll have to deal with them.
Hopefully, those plugins are well-maintained and you can simply update the version of the plugin that you’re using, but for those that aren’t regularly kept up, you might have to find a different plugin to replace it, or even update the plugin code yourself.
What About jQuery UI?
Sadly, jQuery UI is among the ranks of plugins that will need some special attention. Despite its popularity and affiliation with jQuery itself, there hasn’t been an official update released since 2016, and the latest version contains several uses of deprecated jQuery functionality. So, you’ll need to either find a forked version that someone else has already updated and/or make some updates yourself.
If you aren’t already using the latest version of jQuery UI, I would suggest planning in some extra time for handling that update, as the latest few versions brought with them some fairly significant changes. For instance, there were some potentially breaking changes regarding the Dialog widget, and the way widget overlays and layering are implemented was more or less completely redone, which opens the door for plenty of potential z-index issues.
Perhaps most notable is the introduction of a new default theme in version 1.12. This default theme is all fine and good if you want a UI plugin that can look nice out of the box, but it can really put a wrench in things if you already have your own branding and styles in place. Initially, we tried to work around this by adding some overrides to the styles in our codebase, but this approach brought more frustration than success and we eventually had to go in and just rip out much of the CSS that came with the new version of jQuery UI.
So, if you already have your own styles implemented for the jQuery UI widgets that you use, save yourself some pain right off the bat and go into the jQuery UI stylesheet, find any lines that set colors, background colors, or borders, and nuke ‘em.
So, What About that Latest Version of jQuery?
As mentioned earlier in this post, another jQuery update was released while we were working on this project. Well, technically, there were two updates – 3.5.0 and 3.5.1 – but really they went hand-in-hand. Version 3.5.1 was released shortly after 3.5.0 to fix a regression, so they’re like a single release.
In any case, I recently found myself once again working on updating the jQuery in the same codebase. Happily, it was a far less intensive process this time around. The changes made in versions 3.5.0 and 3.5.1 were security fixes regarding the HTML prefiltering that jQuery does when HTML strings are passed to/through any of jQuery’s manipulation methods (e.g.
.append(), .css(), .html(), .remove(), etc.).
What it boils down to is that any HTML strings used with jQuery won’t automatically be “translated” from self-closing tags to separate opening and closing tags. So, for instance, with the old version (3.4.1 or older), you could append an empty <div> to something by doing
$('.thing').append('<div/>') because jQuery’s prefiltering would replace the
'<div></div>'. With version 3.5.0 or newer, though, it would replace
'<div/>' with just
'<div>' and leave the tag open until the browser closes it, which would be either at the end of the string or when it reaches something that can’t be inside the still-open element.
Of course, depending on the context, that could be perfectly fine, but it would leave you somewhat at the mercy of the browser. So, you’ll probably want to go through your code and review any places where you’re using self-closing HTML tags with jQuery: if it’s a void element (e.g.
input), it’s fine as-is and you’re good to go. Otherwise, if it’s not a void element, you might want to rethink the string you’re using.
Behold the Power of Regex!
Now, if you’re thinking, “How the heck am I going to hunt down all the places in my code with self-closing tags?! That’ll take forever!” and you happen to use VS Code, then I have good news for you: I devised a way to make VS Code do the hunting for you! I put together a regular expression (a.k.a. regex) to find all self-closing tags within strings, regardless of how many spaces there might be before or after the brackets or slash, and regardless of whether the string is denoted by single quotes, double quotes, or backticks.
Here are some examples of what it does and doesn’t match (things highlighted in blue are matches):
Here’s the regex itself:
Note: In order for this to work in VS Code’s search panel, you’ll have to go into your settings and turn on the “Use PCRE2” option under Workspace >> Features >> Search.
Granted, that regex could probably be elaborated upon to further refine the search results, but, at a certain point, it becomes more worthwhile to just look through a few more irrelevant search results, and I was at that point. If you’re reading this and feel differently, by all means, feel free to improve upon my regex and I will happily applaud you for coming up with something better!
Further Musings on jQuery Updates
Looking back, I certainly wouldn’t call the project a walk in the park, but I am happy to report that it went well overall, and my teammates assure me that I was not, at any point, a rage monster. The project team was truly fantastic and fun to work with, even when what we were working on wasn’t particularly enjoyable. Considering how wide the impact of the project was and the huge amount of code that was modified, remarkably few issues were found in QA.
Now, if you’ve read this and are still feeling rather intimidated by the prospect of updating the jQuery version in your codebase, fear not! We at CQL have done this before and would be happy to help. All you have to do is contact us using the handy dandy button below.