Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand @wordpress/dom as viable DOM functions library to close jQuery gap in the frontend #35477

Closed
felixarntz opened this issue Oct 8, 2021 · 6 comments
Labels
npm Packages Related to npm packages [Package] DOM /packages/dom [Type] Enhancement A suggestion for improvement. [Type] Performance Related to performance efforts [Type] Tracking Issue Tactical breakdown of efforts across the codebase and/or tied to Overview issues.

Comments

@felixarntz
Copy link
Member

As outlined in detail in this article, jQuery is the most common JS performance offender in WordPress themes and plugins (even though the post specifically focuses on themes). Lots of themes and plugins load jQuery (and only jQuery core, none of its extensions!) in the frontend, just to use it for a few basic DOM interactions, most of which could be easily accomplished with vanilla JS. The above post shows that removing jQuery in those use-cases and using vanilla JS can lead to 80% less JS being loaded, improving performance in the frontend.

Closing the DOM functionality gap between jQuery core and vanilla JS

One of the challenges to migrate away from jQuery core (other than just learning the vanilla JS DOM APIs) is that for some commonly needed DOM manipulations that jQuery offers functions for, there are no 1-to-1 replacements available in vanilla JS. A solution to this problem would be for WordPress core to offer a lightweight, unopinionated JS DOM library that closes the functionality gap between jQuery core and vanilla JS. Today, it's appealing to educate developers that they can use el.querySelectorAll( '.my-class' ) instead of $el.find( '.my-class' ), but this "easy learning experience" quickly comes to an end when you want to explain how to do $el.parents( '.my-class' ) in vanilla JS - since there is no easy-to-use equivalent for that.

Repurposing/expanding @wordpress/dom as frontend DOM library

@wordpress/dom is currently used primarily for the WordPress admin backend and editor, essentially to provide some commonly used DOM utility functions that mostly consist of a few lines of native DOM functions in vanilla JS. It even already includes a few of the functions that would normally require something like jQuery, such as wrap and unwrap. @wordpress/dom is also significantly smaller than jQuery core (in latest trunk, the minified files are ~16KB vs ~90KB respectively).

I'm proposing to expand the scope of this library to become a viable replacement for overly expensive DOM libraries like jQuery core.

  • This doesn't mean we should implement every function that jQuery core offers into this package - we don't want to recreate the problem.
  • It also doesn't mean that we should replicate the experience of writing jQuery code - the goal is to actually learn to use vanilla JS.
  • It merely means we should implement additional DOM utility functions that are commonly used in jQuery, but aren't available in vanilla JS.

Proposed scope of this issue

This issue serves as an initial discussion point for the proposal, and possibly as the main task of this effort, which is to implement the additional functions. I recently went over all jQuery DOM functions and compiled them in a spreadsheet, alongside a vanilla JS 1-line replacement where available, or a proposed new function, to be implemented in the library. Right now, this would be 42 functions overall, but that's only an initial proposal - we should review and discuss which ones make most sense to include, and also whether the signatures etc would be intuitive enough.

Proposed workstreams to reach this goal

  1. Define and implement additional functions to close jQuery to vanilla JS gap in @wordpress/dom (this issue)
  2. Eliminate lodash dependency from @wordpress/dom (related: Remove lodash dependency from WordPress packages. #17025)
  3. Explore other ways to reduce size of @wordpress/dom bundle, potentially also build smaller sub-bundles in addition, so that code that only needs 4 of those functions doesn't need to enqueue the whole @wordpress/dom
@felixarntz felixarntz added [Type] Enhancement A suggestion for improvement. [Type] Performance Related to performance efforts npm Packages Related to npm packages [Package] DOM /packages/dom [Type] Tracking Issue Tactical breakdown of efforts across the codebase and/or tied to Overview issues. labels Oct 8, 2021
@felixarntz felixarntz changed the title Expand @wordpress/dom as viable DOM functions library for the frontend Expand @wordpress/dom as viable DOM functions library to close jQuery gap in the frontend Oct 8, 2021
@khoipro
Copy link
Contributor

khoipro commented Oct 9, 2021

I suggest some additional functions should have curry function to keep everything works better.

Some from our internal lib:

const curry = (f, ...args) =>
	args.length >= f.length ? f(...args) : curry.bind(this, f, ...args)

const addClass = curry((className, els) =>
	map(el => {
		el.classList.add(className)
		return el
	}, els)
)

// Example: const activateNavItem = addClass(ACTIVE_CLASS, el)

@aristath
Copy link
Member

A couple of years ago I wrote a related article with a few example functions that we would probably want to add.
However, I'm not sure we should try to replicate jQuery functionality in @wordpress/dom...
I'd be in favor of a series of articles educating users how to do things in vanilla-JS instead of jQuery, but I fear that trying to replicate jQuery behavior is a slippery slope.

@felixarntz
Copy link
Member Author

felixarntz commented Oct 11, 2021

@aristath

However, I'm not sure we should try to replicate jQuery functionality in @wordpress/dom...

Can you elaborate why? :) My thinking is that jQuery is primarily a DOM library, and so is @wordpress/dom. Some of the functions that are already in @wordpress/dom replace functions of the same name and behavior in jQuery. Again, this isn't supposed to be a rewrite or full replacement of jQuery, just a vanilla JS set of utility functions that cover functionalities that jQuery offers with single functions but vanilla JS doesn't.

I'd be in favor of a series of articles educating users how to do things in vanilla-JS instead of jQuery

100%. But doing that will run into the problem that I mention in the issue description. In order to use vanilla JS instead of jQuery, developers will need to "rewrite" various DOM manipulation functions in vanilla JS format over and over again, so I think a lightweight vanilla JS DOM library to close that gap is essential to make those articles and learning curve successful.

but I fear that trying to replicate jQuery behavior is a slippery slope.

The goal is not to exactly replicate jQuery behavior, it's to have a vanilla JS DOM library that provides some of the utility functions that jQuery has but vanilla JS out-of-the-box lacks - like wrap, unwrap, parents, ...

@sgomes
Copy link
Contributor

sgomes commented Oct 11, 2021

Thank you for this proposal, @felixarntz! I've had my share of pain reworking themes away from jQuery, so I can definitely see where you're coming from! 🙂

In the context of IE 11 support, implementing these methods would have made a lot of sense. Some DOM traversal is simply painful in that scenario, and I've written partial or complete replacements for essential methods like matches and closest in the past.

However, now that Core has deprecated IE 11, it seems less important to offer a wide array of utility functions, since there's so much we can rely on.

Taking your example of parents, since wrap and unwrap are already available, most of the use I've seen in jQuery-dependant code has been something that could easily be implemented instead with closest, because it's referring to a single expected element up the hierarchy, rather than what parents actually retrieves, which is the full list. In fact, switching to closest is preferred in that situation, because it more accurately expresses the intent and ends up traversing less of the DOM. I'm not saying that there aren't legitimate uses of parents out there, but I'm not sure if they exist at a level that justifies preemptively implementing and maintaining that method in @wordpress/dom, in hopes that developers will make use of it when implementing their themes.

Particularly while there isn't a good WP-level mechanism for partial loading of these utilities, as you mention.

The last few default themes (since twentynineteen) haven't made use of jQuery (other than for admin, where performance is less crucial), but they haven't required much in the way of utility functions, other than the aforementioned polyfills/replacements for IE11 support. Of course this is just a tiny sample out of the sea of WordPress themes, and it's really just anecdotal evidence, but I personally haven't found a large need for a library of utility DOM methods if you can rely on what modern browsers currently provide. Perhaps a larger-scale study of how much JS gets used in WordPress themes and how much of it could benefit from Core utility methods is in order?

@annezazu
Copy link
Contributor

Is this still relevant? It's been a few years (almost 3!) since the latest updates here and I'm doing a sweep to see if this can be closed. Happy to keep it open but just wanted to nudge 😃

@felixarntz
Copy link
Member Author

@annezazu Happy to close this.

Given we now have the Interactivity API as a first-class citizen WordPress frontend JS API, there would be little justification to do this - given all the other benefits that using the Interactivity API comes with. Now we "just" have to encourage the plugin ecosystem to migrate 🙃

@felixarntz felixarntz closed this as not planned Won't fix, can't repro, duplicate, stale Mar 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
npm Packages Related to npm packages [Package] DOM /packages/dom [Type] Enhancement A suggestion for improvement. [Type] Performance Related to performance efforts [Type] Tracking Issue Tactical breakdown of efforts across the codebase and/or tied to Overview issues.
Projects
None yet
Development

No branches or pull requests

5 participants