[wp-trac] [WordPress Trac] #47285: Better Management of External Asset Dependencies

WordPress Trac noreply at wordpress.org
Wed May 15 18:36:16 UTC 2019


#47285: Better Management of External Asset Dependencies
-------------------------------------+-----------------------------
 Reporter:  justlevine               |      Owner:  (none)
     Type:  feature request          |     Status:  new
 Priority:  normal                   |  Milestone:  Awaiting Review
Component:  Script Loader            |    Version:
 Severity:  major                    |   Keywords:
  Focuses:  javascript, performance  |
-------------------------------------+-----------------------------
 **Tl;Dr**: there **must** be a way for WordPress Plugins to indicate
 compatible versions of external dependencies, so as to reduce enqueuing
 multiple copies of the same external library. The issue is urgent with the
 ecosystem's migration to Blocks.

 **Problem**
 We've all been there; you install 3 plugins, and your website is enqueuing
 four copies of FontAwesome, and two copies of Bootstrap. Plus an extra one
 of each from your theme. Plus 3 different datepicker libraries and two
 `<select>` enhancements.

 For most end-users, the buck stops there a their websites are left wasting
 precious resources loading things they don't need, further proof for
 detractors that WordPress and Performance are contradictory. For tech-
 savvy users and developers the headache just begins, and they begin to
 dequeue assets by trial-and-error, making sure everything is still
 compatible. And again each time anything updates.

 Then there's the impending nightmare scenario: with the move from
 encompassing plugins to individual functionality Blocks, and the
 encapsulated dependencies each one will inevitably need to include to
 function autonomously (especially if/when the new Block Installer kills
 the need for All-in-One block plugins), **the number of unnecessary,
 duplicate dependencies is about to grow exponentially**.

 **Solution**
 WordPress needs to allow developers to define what external libraries and
 compatible versions their code requires, so it can automatically load only
 one copy of the necessary assets.

 **Proposal**
 ''Warning: I'm nowhere close to being a DevOps expert. While I stand by
 the issue and generic solution, there's a 95% chance that the the proposal
 is ineffecient at best, and inherently flawed at worse. This goes doubly
 for any functions I'm making up on the spot.''

 **1.** Allow users to semantically define what external dependencies
 they're using.

 While WordPress is smart enough not to load identical asset handles, those
 handles are semantically meaningless. It's bad practice to give your
 external asset a generic name (there are times where you ''need'' a
 specific version or copy of an asset, else you'll have conflicts and
 incompatibilities), you currently end up with `plugin-bootstrap`, `my-
 bootstrap`, `bootstrap-four`, and `bootstrap`, with no way to know that 2
 of them are the exact same file, and the 3rd one's source will work
 perfectly with that version.

 A function, such as `wp_define_asset_library($handle, $library_name)`,
 would let WordPress know that all four files are actually Bootstrap, and
 you probably need to enqueue only one one them.

 Want to use FontAwesome Pro instead of the free version? You could then
 simply dequeue all of them with the `$library_name`, instead of trying to
 figure out what each plugin author decided to call the one they bundled.

 **Bonus**: Throw in a conditional `is_library_registered($library_name)`,
 and Block Authors could support both jQuery.Datepicker and PickaDate, and
 you wouldn't need to be running two JS libraries that do the same thing
 just because you're using blocks from two different authors! Hashtag Open
 Ecosystem.

 ''Note: a standard naming convention for dependency names would need to be
 agreed upon. I'd suggest using the official repository name, but as I said
 in my disclaimer, I don't know squat.''

 **2.** Let Developers define supported versions of the library.

 By giving a extra argument to our function above, and we've solved the
 headache of version conflicts!

 Defining `$vers`, WordPress will be able to look at all 3 different
 versions of `bootstrap` and automagically know which one to include!
 Plugin A requires `4.1.1`, Plugin B  `^4.0`, and Plugin C is still stuck
 with `~3.0.5`, and suddenly you've been able to drop a redundant library
 but your legacy plugin is still working fine!

 Imagine a world where you could use jQuery 3.4 without worrying about
 WordPress' precious back-compat. Heck, imagine being confident enough to
 get rid of jQuery as a frontend dependency althogether, because you know
 for certain only one plugin is using it, and it offers a vanilla JS
 alternative (via the conditional in #1)!

 **Bonus**: If two versions need to be included, WordPress could even tell
 the plugin to 'auto-encapsulate' one of them! Say goodbye to manual 'No
 Conflict Modes' and hours of plugin support time wasted telling end-users
 "Our plugin is incompatible with one of your other installed plugins.
 Disable them one-by-one until you find the culprit, and then bet it's
 developer to update it's version of select2", and hello to increased
 interoperability!

 ''Note: suggested practice would be for the developer to include the most
 up-to-date version compatible with their plugin, while declaring
 compatibility for earlier versions. WordPress would would then include the
 most-recent version(s) from whichever source meets the criteria.''

 **Implementation & Backwards Compatibility**
 Again, I'm no expert, but from my utterly uninformed point of view, this
 is easy to implement both without breaking backwards compatibility, and
 possible improving it going forward.

 `wp_register_script` and `wp_register_style` get one extra parameter:
 `$library_name`. `$ver` gets a check to see if it's a number or the
 min/max version syntax. If we're worried about human readability then you
 put `$library_name` as the fifth argument and if it's a boolean you treat
 it as the old in footer.

 Ditto for if you use `wp_enqueue_whichever` to register the asset when
 enqueuing. If the script is already registered, it checks whether there's
 an associated library before doing the enqueue process (below).

 A new function `wp_define_asset_library($handle, $library_name, $ver)`
 (yeah this shouldn't be the actual name) lets either the plugin developer,
 or ''more importantly'' the user, easily associate any external assets
 declared the old way with an external library.

 The `$wp_scripts` global, essentially stays the same but with the new
 array value. I'm not a performance expert but maybe another global
 `$wp_script_libraries` contains a multidimensional array of
 `$library_name`s, with the defined handle and version of each.

 The enqueue process checks if `$library_name` is defined, and if so begins
 the automagical process of figuring out which asset to enqueue:
 -parses the version requirements for all the same libraries.
 -If several are in the same range it enqueues the highest compatible
 version version.
 -any versions that aren't in a range, and any assets that don't have an
 external library are enqueued normally.


 `wp_dequeue/deregister_style_library($library_name, $versions)` and
 `wp_dequeue_script_library`, gets rid of all associated assets in that
 range.

 `is_library_registered($handle, $vers)` let's you do cool things like
 support multiple libraries based on what other plugins, or choose whether
 to to register an asset altogether (e.g. use jQuery.Datepicker if it - or
 jQuery is enqueued, else register a vanilla JS version).

 Similarly, `$is_enqueued_multiple_times(handle)`, let's authors prepend a
 `$noconflict_prefix` when necessary.

 ---------------------
 Again, I'm sure there's a bunch of unseen issues with this, but end of the
 day the switch to Blocks (and especially the push for individual blocks
 decoupled from a larger plugin) is going to bring around an external
 library apocalypse.

 We need to find and implement a solution, and soon!

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/47285>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list