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

Implement load handlers #50

Merged

Conversation

kt-12
Copy link

@kt-12 kt-12 commented Mar 10, 2023

Trac ticket:


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

@10upsimon 10upsimon self-requested a review March 13, 2023 09:07
$output = <<<JS
let wpLoadAfterScripts = ( handle ) => {
let scripts = document.querySelectorAll(`[type="text/template"][data-wp-executes-after="\${handle}"]`);
scripts.forEach( (script) => { script.setAttribute("type","text/javascript") })

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kt-12 is this enough to get the browser to actually execute the script by just converting its type? I'm quite sure that during the discovery phase we has ascertained that this may need manual execution and that the browser would not automatically fire the JS tag just because its type was dynamically altered.

Can you confirm this please?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kt-12 upon further research, it seems to me that changing the type attribute alone will not execute the JS, and even inline injection/alteration would not. We're likely going to have to use appendChild() or a similar method, where we clone the text/template tag, change the attribute, find the DOM element that exists currently (i.e the text/template tag in question) and append the new JS tag after it. We would probably want to then remove the text/template element.

A series of events may look like this:

  • Iterate over all text/template tags as you currently do above
  • Reference that DOM element
  • Reference the full tag as text form, as a variable
  • Change the type to text/javascript as you're doing above
  • Use appendChild() to append the new script string after the DOM element referenced in point 2
  • Consider deleting the DOM element referenced in point 2 above, but you'd need to make a call if this has implications and whether we should keep it.

$output = <<<JS
let wpLoadAfterScripts = ( handle ) => {
let scripts = document.querySelectorAll(`[type="text/template"][data-wp-executes-after="\${handle}"]`);
scripts.forEach( (script) => { script.setAttribute("type","text/javascript") })

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kt-12 upon further research, it seems to me that changing the type attribute alone will not execute the JS, and even inline injection/alteration would not. We're likely going to have to use appendChild() or a similar method, where we clone the text/template tag, change the attribute, find the DOM element that exists currently (i.e the text/template tag in question) and append the new JS tag after it. We would probably want to then remove the text/template element.

A series of events may look like this:

  • Iterate over all text/template tags as you currently do above
  • Reference that DOM element
  • Reference the full tag as text form, as a variable
  • Change the type to text/javascript as you're doing above
  • Use appendChild() to append the new script string after the DOM element referenced in point 2
  • Consider deleting the DOM element referenced in point 2 above, but you'd need to make a call if this has implications and whether we should keep it.

@kt-12 kt-12 added the Script Loading Strategy Issues relating to the Script Loading Strategy (WPP) label Mar 14, 2023
@kt-12 kt-12 self-assigned this Mar 15, 2023
Copy link

@10upsimon 10upsimon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kt-12 minor observations, comments and small change requests noted.

*
* @return bool True if script present. False if empty.
*/
public function maybe_has_delayed_inline_script() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kt-12 this is a nitpick comment I guess, but I am wondering if maybe is the correct wording here, as it seems to be like you are indefinitely checking of a deferred or async script has inline scripts? This is not a case of maybe and seems like it's more a definite outcome?

If you agree, let's rename this to has_delayed_inline_script() as that is more true to the logic here.

If I've misunderstood, please comment as such thank you :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct. I used maybe as there are certain cases where the final strategy of a script might change before we print them effecting it's inline scripts decision. For example a defer may change to blocking, but we never know it in print_scripts action.

But i do agree maybe is not needed here, i'll remove that.

tests/phpunit/tests/dependencies/scripts.php Outdated Show resolved Hide resolved
tests/phpunit/tests/dependencies/scripts.php Outdated Show resolved Hide resolved
tests/phpunit/tests/dependencies/scripts.php Outdated Show resolved Hide resolved
kt-12 and others added 5 commits March 21, 2023 11:18
Co-authored-by: Simon Dowdles <72872375+10upsimon@users.noreply.github.com>
Co-authored-by: Simon Dowdles <72872375+10upsimon@users.noreply.github.com>
Co-authored-by: Simon Dowdles <72872375+10upsimon@users.noreply.github.com>
Copy link

@mukeshpanchal27 mukeshpanchal27 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @kt-12, I quick review and left some feedback and questions.

Comment on lines 323 to 327
'<script%1$s id=\'%2$s-js-after\' type=\'text/template\' data-wp-executes-after=\'%2$s\'>%4$s%3$s%4$s</script>%4$s',
$this->type_attr,
esc_attr( $handle ),
$after_non_standalone_handle,
PHP_EOL

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'<script%1$s id=\'%2$s-js-after\' type=\'text/template\' data-wp-executes-after=\'%2$s\'>%4$s%3$s%4$s</script>%4$s',
$this->type_attr,
esc_attr( $handle ),
$after_non_standalone_handle,
PHP_EOL
'<script%s id=\'%2$s-js-after\' type=\'text/template\' data-wp-executes-after=\'%s\'>\n%s\n</script>\n',
$this->type_attr,
esc_attr( $handle ),
$after_non_standalone_handle,

Similar to other scripts, use \n instead of PHP_EOL and use %s as it is sufficient for these changes as we don't need to add translators or change the order of the arguments.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mukeshpanchal27 I was trying the same initially but \n don't work when the parent string is in single quotes. It is instead printed as string \n. Numbered placeholder was added as there are multiple places i wanted the handle string and for numbered placeholder I need the enclosing string to be in single quotes.

src/wp-includes/class-wp-scripts.php Outdated Show resolved Hide resolved
@@ -771,6 +788,23 @@ public function add_data( $handle, $key, $value ) {
return parent::add_data( $handle, $key, $value );
}

/**
* Check all handles for any delayed inline scripts.
*

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Since annotation is missing.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mukeshpanchal27 We haven't fixed on the final @since yet. We have a separate task for this.

src/wp-includes/class-wp-scripts.php Outdated Show resolved Hide resolved
})
}
JS;
printf( "<script id='wp-executes-after-js'>\n%s\n</script>\n", $output );

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$this->type_attr is missing in script.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, but $this->type_attr is not available here so replicate the way function _print_scripts() was handling the same scenario.

Comment on lines 1847 to 1849
/**
* Prints a loader script if there is text/template registered script.
*/

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per PHP Documentation Standards, Use proper format for function

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. Usage of since is still missing as this will be handled together for the entire functionality in a separate task. Thanks @mukeshpanchal27.

let wpLoadAfterScripts = ( handle ) => {
let scripts = document.querySelectorAll(`[type="text/template"][data-wp-executes-after="\${handle}"]`);
scripts.forEach( (script) => {
script.setAttribute("type","text/javascript");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
script.setAttribute("type","text/javascript");

WP use $this->type_attr for script type. Please correct me if i miss anything.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mukeshpanchal27 this is the JS code for modifying type after a script is loaded on the DOM. So we can't use $this->type_attr

kt-12 and others added 3 commits March 28, 2023 14:24
Co-authored-by: Mukesh Panchal <mukeshpanchal27@users.noreply.github.com>
Co-authored-by: Mukesh Panchal <mukeshpanchal27@users.noreply.github.com>
@kt-12 kt-12 requested a review from joemcgill March 31, 2023 12:34
Copy link
Collaborator

@joemcgill joemcgill left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple small nits, but this seems ok to me. Pre-approving since nothing is blocking.

Comment on lines 805 to 807
if ( in_array( $this->get_intended_strategy( $handle ), array( 'defer', 'async' ), true ) ) {
// non standalone after scripts of async or defer are usually delayed.
if ( $this->has_non_standalone_inline_script( $handle, 'after' ) ) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These could be combined into a single if statement with &&

})
}
JS;
$type_attr = current_theme_supports( 'html5', 'script' ) ? '' : " type='text/javascript'";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could probably use $wp_scripts->type_attr since it's the same functionality, right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joemcgill we can't use it here as, type_attr is a private attribute.

$wp_scripts = wp_scripts();
if ( $wp_scripts->has_delayed_inline_script() ) {
$output = <<<JS
let wpLoadAfterScripts = ( handle ) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could probably be a regular function rather than an arrow function.

function wpLoadAfterScripts( handle ) {
  // functionality
}

* associated with a handle to type/javascript and execute them.
*/
function wp_print_template_loader_script() {
$wp_scripts = wp_scripts();
if ( $wp_scripts->has_delayed_inline_script() ) {
$output = <<<JS
let wpLoadAfterScripts = ( handle ) => {
function wpLoadAfterScripts() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still need to accept a handle param, right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@joemcgill
Copy link
Collaborator

Thanks @kt-12. I've already approved so this is good to merge whenever you're ready.

@10upsimon 10upsimon merged commit 4cc2502 into enhancement/add_text_template Apr 3, 2023
@10upsimon 10upsimon deleted the enhancement/implement_load_handlers branch April 3, 2023 05:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Script Loading Strategy Issues relating to the Script Loading Strategy (WPP)
Projects
None yet
4 participants