[wp-trac] [WordPress Trac] #12009: Add support for HTML 5 "async" and "defer" attributes
WordPress Trac
noreply at wordpress.org
Fri Jun 16 01:22:23 UTC 2023
#12009: Add support for HTML 5 "async" and "defer" attributes
-------------------------------------------------+-------------------------
Reporter: Otto42 | Owner: 10upsimon
Type: enhancement | Status: assigned
Priority: high | Milestone: 6.3
Component: Script Loader | Version: 4.6
Severity: normal | Resolution:
Keywords: has-patch has-unit-tests 2nd- | Focuses:
opinion | performance
-------------------------------------------------+-------------------------
Comment (by joemcgill):
Replying to [comment:115 azaozz]:
Since we’re nearing the end of the merge window for 6.3, I want to revisit
some of the things raised in this conversation and get final clarification
on a path forward. Let me summarize my current understanding of the main
concerns you have raised:
1. Your opinion is that supporting inline after scripts is unnecessary, in
general
2. The implementation method in the current PR for delaying inline scripts
is unsafe
3. Supporting `async` and `defer` could conflict with future dynamic
module imports
First, I’ll restate the reasons that we’ve chosen to keep support for
inline scripts when added to a script that has an async or defer
attribute. There are over 5000 cases in
[https://wpdirectory.net/search/01H2EJ1E82DX0JCAMYSS35GD0T plugins] and
808 cases in [https://wpdirectory.net/search/01H2EM8SFQAB67C1TSRHZS2AJA
themes] on the wp.org repos where `wp_add_inline_script()` is used, with
the vast majority (>90%) of them using the `after` position. Even in core,
there are
[https://github.com/search?q=repo%3AWordPress%2FWordPress%20wp_add_inline_script&type=code
many places] where data from the server is being supplied to an inline
script in an `after` position. An example is in
[https://github.com/WordPress/wordpress-
develop/blob/ba9a2f8b83211fbdee1621fd4f39dcb11908b817/src/wp-admin/site-
editor.php#L94-L114 site-editor.php], where settings from the server are
dynamically supplied to the front end to be used after a core script is
loaded. Without a way to delay those inline scripts until after the handle
to which they are attached has loaded, those handles will always need to
be loaded as a blocking script. After inline scripts are very useful
because they do not require polluting the global namespace with a variable
defined in the before inline script, and the script itself doesn’t have to
be updated to read from that global variable: with an inline script,
existing libraries can be used as-is. Our implementation allows script
handles with inline scripts attached to be deferred or loaded
asynchronously without the need to rewrite the inline logic, allowing more
scripts to adopt `async` or `defer` strategies, including scripts in core
that are currently blocking but could be delayed in the future (outside
the scope of this PR, but something that I'd like to see us explore).
Regarding your concerns about the safety of the implementation, there are
very important distinctions between scripts that are executed using
`eval()` and scripts that are dynamically injected into the DOM during
script execution (i.e., the approach we’re using). Most important is that
sites implementing a content security policy (CSP) will not execute `eval`
unless they include the `unsafe-eval` keyword. Dynamic scripts are handled
completely separately, including external scripts and inline scripts. By
using the `strict-dynamic` source expression, only trusted scripts are
allowed to dynamically add scripts to the DOM. This trust is achieved by
outputting a `nonce-{random}` attribute on the script tag. With
[https://web.dev/strict-csp/#what-is-a-strict-content-security-policy
strict CSP], browsers block executing scripts at parse time if they lack a
valid nonce, and our delayed inline script loader does the exact same
thing by making sure that inline scripts are only dynamically added if the
original `script[type=text/plain]` has a valid nonce matching the CSP. In
summary, dynamically adding scripts to a DOM is quite different and safer
than running `eval()` on a text string. If you have more specific concerns
about the security of this approach, please specify so they can be
addressed.
Finally, I’ve looked into the dynamic module loading you raised in
[https://core.trac.wordpress.org/ticket/12009#comment:116 your previous
comment] and am not seeing any incompatibility with adding support for
adding `async` and `defer` attributes to scripts. From what I can tell,
any scripts that are registered as modules in the future would be able to
be written in a way that includes dynamic imports without ever needing to
interact with the Script Loader, since all of the logic to dynamically
import external modules would be handled within the script itself.
Having said all that, what needs to be determined is whether the support
for inline scripts needs to be completely removed from the implementation
for an initial commit, or if there are further modifications that need to
be made in order to leave that support in place. Additionally, if you have
any other final changes that you would like to see addressed before
commit, please list them so we can ensure they are addressed.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/12009#comment:124>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list