Problem/Motivation

This is the next step that began with the new jQuery-checking lint rules added in #3191023: Add eslint rules to check for jQuery usage. These rules were added to core/.eslintrc.jquery.json. In this issue, we added a set of JS linting rules that check for various uses of Jquery. Currently, the majority of these rules are disabled. We plan to create issues for each of these disabled rules, where that specific rule is enabled, and in doing so exposes that specific use of jQuery.

Proposed resolution

Remove where possible, do not copy jQuery source

We are not going to copy the source code of jQuery or implement a similar function into Drupal if it can't be done natively. It might be an option in the future but we're not there yet. If replacing a method means rewriting a part of jQuery or adding a global "utility" function, it is not worth it at this time. jQuery isn't broken and we can always try to use a custom built version of jQuery.

The goal is - wherever possible - refactor these jQuery uses to Vanilla (native) JavaScript so Drupal core has less of an overall dependency on jQuery. While it may not be possible to fully eliminate jQuery, reducing the ways it is used will make maintainability far easier.

If the replacement is hard to read

It's a little subjective but when the vanilla JS is getting too much in the way of understanding the code, it's not worth it. We either need to wait for browsers to be better or re-architect the script instead of trying to replace small pieces of it.

eslint configuration

In the child issues where eslint is configured to look for a specific type of jQuery use - that type of jQuery use will effectively be forbidden in Drupal core from that point forward. For example, once eslint checks for "jquery/no-css" (by changing "jquery/no-css" : 0 to , "jquery/no-css" : 2 Drupal CI tests will no longer allow uses of jQuery's css() function in core.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Comments

bnjmnm created an issue. See original summary.

bnjmnm’s picture

longwave’s picture

Recently we fixed the DrupalCI script so it automatically runs PHPCS across all of core if the relevant config file is changed: #3224583: The testbot does not run PHPCS on all files when core/phpcs.xml.dist is changed

To help out with the child issues in this meta it seems like we should do the same if the ESLint config file is changed.

nod_’s picture

We should also look at dynamic uses of jQuery such as the InvokeCommand from the ajax API.

While they're not deprecations and jQuery is still going to be around we might still warn people or add a BC layer that keep things working (1nd at that point might be better to keep jQuery around.

So I guess we should consider deprecating InvokeCommand.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

nod_’s picture

I think we're making it hard on ourselves in the issues by trying to replace the selector part AND the manipulation part at the same time.

I think it'd be faster to leave the jquery selecting alone and address it later so we can have progress on removing jquery manipulation methods from the codebase.

mstrelan’s picture

I agree with #7 except in cases where a selected element is only used once in a function and we're already touching that part of the function. Might as well update the selector then if it's easy.

nod_’s picture

To expand a bit on what I meant.

There are 2 parts of using jQuery, selecting items and acting on the list of selected items.

Currently we're trying to change both at the same time:

// From
$(context).find('selector').addClass('test');
// To
context.querySelectorAll('selector').forEach((el) => el.classList.add('test'));

With the problem of making sure querySelector/querySelectorAll doesn't return an empty set. That means we need to check all replacements to ensure that there are guards at the proper place in addition to removing the use of the specific jquery method we're looking to retire. It could introduce the problem of dealing with non existing elements differently depending on the file we're looking at.

I propose that we simplify our lives and do the selector replacement somewhere else. That will hugely simplify the review and limit the possibility of breaks in our code. Using the example above it would look something like this:

// From
$(context).find('selector').addClass('test');
// To
Array.from($(context).find('selector')).forEach((el) => el.classList.add('test'));

This will handle empty sets nicely and make sure that changes are scoped to only what we need to pass the new eslint rules. In a future step (once we removed all use of jquery methods) we will be able to transparently transform jquery selectors with something like

(function ($) {

  // No change to the code needed!
  $(context).find('selector');

}(customSelectorFunctionThatLooksLikejQuery));

Doing that would possibly allow for an automated replacement of the various jquery methods like it was done for the once patch. That won't work for all cases but from what I can see it'll simplify the majority of the replacement works.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

andy-blum’s picture

Is there a reason we're looking to replace jQuery usage method-by-method? Would it not be easier to divide the jQuery replacement library by library?

IMO, it would be a simpler task, and more approachable for contributors to work on a single library at a time, keeping the issue scoped to fewer files.

longwave’s picture

Method-by-method lets us add each method as we complete them to .eslintrc.jquery.json, which then prevents them from being used in core again. It should also be more straightforward for contributors, as once we have a pattern for a particular method we should be able to apply it consistently to all the uses of that method, which is also easier for reviewers. Library-by-library seems like we might come up with different ways of refactoring the same method, or that we have to go looking for how each method was updated in a previous library issue, and reviewing becomes more difficult.

nod_’s picture

@andy-blum, we already tried the library by library approach for code clean-up/refactor. It was not fun, see #1415788: Javascript winter clean-up and the table from the issue summary it took many, many, many years to go through all of them.

method by method across all files is the way to go like longwave explained :)

andy-blum’s picture

@nod_ / @longwave should this and the child issues still be applied to 9.5.x or should we be targeting one of the D10 branches?

andy-blum’s picture

Version: 9.5.x-dev » 10.1.x-dev

Per slack discussion moving to 10.1.x

All children should also be updated to 10.1.x.

darvanen’s picture

#5: I agree we should look at deprecating InvokeCommand.

If I've noticed a missing method (replaceWith for one) from the child issues should I add it? Is that method contained within a different issue somewhere?

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

nod_’s picture

Since this is picking up again, going to post some more guidelines.

Remove where possible, do not copy jQuery source

We are not going to copy the source code of jQuery or implement a similar function into Drupal if it can't be done natively. It might be an option in the future but we're not there yet. If replacing a method means rewriting a part of jQuery or adding a global "utility" function, it is not worth it at this time. jQuery isn't broken and we can always try to use a custom built version of jQuery

If the replacement is hard to read

It's a little subjective but when the vanilla JS is getting too much in the way of understanding the code, it's not worth it. We either need to wait for browsers to be better or re-architect the script instead of trying to replace small pieces of it.

smustgrave’s picture

Closed #3239142: Refactor (if feasible) uses of the jQuery wrap functions to use vanillaJS as won't fix. Moving credit from that ticket to here.

Do wonder what others thoughts are on

$('.ui-dialog-off-canvas') to $('.ui-dialog-off-canvas')[0]

To me that reads worse but will defer to the community, there are a number of issues in review like that.

pcate’s picture

Do wonder what others thoughts are on
$('.ui-dialog-off-canvas') to $('.ui-dialog-off-canvas')[0]
To me that reads worse but will defer to the community, there are a number of issues in review like that.

An alternative would be using the .first method: $('.ui-dialog-off-canvas').first() or using array destructuring: const [dialog] = $('.ui-dialog-off-canvas')

smustgrave’s picture

The array destructuring looks a little better to me. but will lean on javascript and frontend people to decide that. About 7-8 tickets in review that contain a change like that

nod_’s picture

I'm going to try and refocus the jQuery removal work and to do that I need to take a few decisions. I'm going to close a few issues that are most likely to introduce regressions and concentrate on the bigger topics.

The issues I'll be closing risk introducing problems with contrib and/or introduce too much extra code that looks similar to jQuery. jQuery can be handy, even elegant in some cases and the replacement will be harder to maintain.

I'm porting credit from closed issues to #3464044: Credit for work on the reduce jQuery issues because some of those issues have significant work behind them

quietone’s picture

Issue summary: View changes

Moved the approach in #18 to the issue summary.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.