Enhancing the Scripts API with a loading strategy

Overview

This post outlines a proposal to add a script loading strategy enhancementenhancement Enhancements are simple improvements to WordPress, such as the addition of a hook, a new feature, or an improvement to an existing feature. to coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress.’s existing Scripts APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways..  

The underlying goal of this effort is to make it easier for WordPress pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party and theme developers and core to use “modern” loading approaches for JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a user’s browser. https://www.javascript.com/. (like defer and async), which will help WordPress sites load faster and operate more smoothly, giving users a better experience.

Why add a loading strategy?

Data from the Web Almanac project (query) indicates that render blocking JavaScript is a significant problem on the web, with 77% of mobile pages having render-blocking scripts in the document <head> . This query shows that approximately 40% of WordPress sites stand to benefit from deferring additional scripts. Adding defer or async to script tags enables script loading without “blocking” the rest of the page load, resulting in more responsive sites overall better user experience.

Currently WordPress core as well as plugins and themes register scripts with the wp_enqueue_script and/or wp_register_script functions. Although these functions include the ability to control the placement of the script (with the in_footer parameter), they don’t include support for adding modern attributes such as defer or async to script tags. 

To add async or defer today, developers must resort to less flexible and more fragile approaches, such as directly filtering the tags at the point of output (using  the script_loader_tag filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output.), or handling the tagtag A directory in Subversion. WordPress uses tags to store a single snapshot of a version (3.6, 3.6.1, etc.), the common convention of tags in version control systems. (Not to be confused with post tags.) output directly using wp_print_script_tag and the wp_script_attributes filter.

Using the first approach and directly filtering the tag can easily break: for example if two plugins both try to filter a tag, or if a tag has unexpected attributes already (eg. adding defer to a tag that already has async). Using the the second approach developers must carefully handle dependencies and output manually – things that that the Scripts API usually helps take care of.

How the loading strategy works

Developers specify a loading strategy when registering or enqueueing a script. For example, a defer strategy can be specified when the script isn’t required immediately during the page load cycle. WordPress will then determine which scripts can actually use a strategy based on logic for each strategy. For example, to ensure that scripts are executed in the order they are enqueued, defer can only be used on a script if every script that depends on that script can also be deferred. Inline script tags added with wp_add_inline_script would also be considered to ensure proper execution order.

The implementation would come with several initial built-in loading strategies: defer, async, and the default blocking behavior.

Out of scope for this feature

The loading strategy does not enable direct control of script tag attributes. This idea was originally proposed 10 years ago in #22249 and several approaches were considered on that ticketticket Created for both bug reports and feature development on the bug tracker. including a script attribute filter. This proposal takes a step back and aims to solve the script loading strategy aspect more comprehensively and directly while avoiding exposing the potential complications of direct attribute control.

It is worth noting that it is already possible to control attributes on wp_enqueue_script tags directly using the script_loader_tag filter. However, this is a bit of a “brute force” approach which is limited and fragile because it doesn’t consider dependencies and multiple plugins can take conflicting actions on the same tag. 

What are potential concerns with this feature?

One big concern with adding this feature to the WordPress Script API is potentially introducing a breaking change. wp_enqueue_script is a fundamental API in WordPress core, and any breaking changes could have widespread implications. Possible breakage is a possible reason that adding custom attributes as proposed in #22249 was never added to core.

This new proposal aims to ensure that there is 100% backwards compatibility, resulting in zero risk of breakage. The loading strategy will ensure that all existing uses continue to function as expected; for example, passing the boolean in_footer attribute will still control script placement. In addition, it will ensure that scripts continue to be executed in the order they are enqueued – as described above in the “How the loading strategy works” section.

Conclusion and Next Steps

Giving developers the ability to specify a loading strategy will enable them to use more advanced JavaScript loading methods while still ensuring that enqueued scripts are executed in the correct order. A “strategy” approach is also forward thinking: as the web evolves, new strategies can be developed and made available to WordPress developers. After gathering feedback, we will proceed to discussing the implementation approach and, ultimately, proposing a patchpatch A special text file that describes changes to code, by identifying the files and lines which are added, removed, and altered. It may also be referred to as a diff. A patch can be applied to a codebase for testing..

Have you tried using defer or async with WordPress (or do you already)? How do you think this enhancement would change that? Please leave your feedback about this proposal in the comments below and if you can, join us at our weekly performance team chats, where we are likely to discuss this proposal in the future.

Thanks to @flixos90, @tweetythierry and @mxbclang for help writing and reviewing this post and for the many contributors who have added to the discussion around this enhancement already.

#core, #feature-projects, #javascript, #performance, #proposal