-
Notifications
You must be signed in to change notification settings - Fork 384
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
Don't tree-shake allowed child classes of amp-date-picker
if it's in the DOM
#4339
Conversation
Since this is JS-driven, child classes won't be in the document during tree-shaking. So if amp-date-picker is in the tags and the class is an allowed child of it, don't tree-shake it.
private function is_class_allowed_in_amp_date_picker( $class ) { | ||
// Some prefixes, some full class names. | ||
$allowed_class_beginnings = [ | ||
'CalendarDay', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be missing some classes, though I tried to be thorough.
I looked at the components that have styles.
This doesn't include components that are just an .svg
, like CalendarIcon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do any of these component names get carried over to be class names in the DOM? If so, they should be included in this list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, all of these appear as names in the DOM as classes, except for DateInput
, DateRangePicker
, DateRangePicker
:
For those 3 that didn't appear, I couldn't find them, when using most of the snippets in the amp-date-picker documentation. I should probably remove those, though maybe I just missed a case where they are used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 3 that I couldn't find in the DOM as class names are removed in 5bffd65
Some classes should have exact matches, like amp-date-picker-calendar-contrainer
The component name is expected to be followed by a letter or _ For example, CalendarDay could be CalendarDay_table. Also, DayPicker could be DayPickerNavigation.
Hi @westonruter, |
There's probably no need to iterate through the classses, this could simply return in_array().
'SingleDatePicker', | ||
]; | ||
|
||
if ( preg_match( '#^(' . implode( '|', $class_prefixes ) . ')[a-zA-Z_]+#', $class ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be made simpler/faster like so:
if ( preg_match( '#^(' . implode( '|', $class_prefixes ) . ')[a-zA-Z_]+#', $class ) ) { | |
if ( in_array( strtok( $class, '_' ), $class_prefixes, true ) ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, committed in 36cba7d
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted, then re-committed in 5bffd65
return true; | ||
} | ||
|
||
return in_array( $class, [ 'amp-date-picker-calendar-container', 'amp-date-picker-resize-bug' ], true ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return in_array( $class, [ 'amp-date-picker-calendar-container', 'amp-date-picker-resize-bug' ], true ); | |
return 'amp-date-picker-' === substr( $class, 0, 16 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Committed in eea565f
private function is_class_allowed_in_amp_date_picker( $class ) { | ||
// Some prefixes, some full class names. | ||
$allowed_class_beginnings = [ | ||
'CalendarDay', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do any of these component names get carried over to be class names in the DOM? If so, they should be included in this list.
Co-Authored-By: Weston Ruter <westonruter@google.com>
This reverts commit 36cba7d.
This now searches for something like DayPickerNavigation_, instead of just verifying that it starts with DayPicker.
Co-Authored-By: Weston Ruter <westonruter@google.com>
'CalendarDay', | ||
'CalendarMonth', | ||
'CalendarMonthGrid', | ||
'DayPicker', | ||
'DayPickerKeyboardShortcuts', | ||
'DayPickerNavigation', | ||
'KeyboardShortcutRow', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm using this function in the console:
function gatherClassNames( elements ) {
const classNames = new Set();
const add = ( className ) => {
if ( !/^i-amphtml-/.test( className ) ) {
classNames.add( className.replace( /_.+/, '' ) );
}
};
for ( const element of elements ) {
element.classList.forEach( add );
gatherClassNames( element.children ).forEach( add );
}
return classNames;
}
And I'm invoking it via:
gatherClassNames(document.querySelectorAll('amp-date-picker'))
I'm not able to find any other class names in use when looking at the amp-date-picker
examples.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, great function to get the class names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The KeyboardShortcutRow
class only appears on clicking the ?
icon in the bottom right. But so far, I couldn't find more classes that appear via user interaction.
return true; | ||
} | ||
|
||
return 'amp-date-picker-' === substr( $class, 0, 16 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, is this not redundant with:
amp-wp/includes/sanitizers/class-amp-style-sanitizer.php
Lines 650 to 655 in eea565f
// Class names for amp-date-picker, see <https://www.ampproject.org/docs/reference/components/amp-date-picker>. | |
case 'amp-date-picker-': | |
if ( ! $this->has_used_tag_names( [ 'amp-date-picker' ] ) ) { | |
return false; | |
} | |
continue 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I think it is redundant.
What do you think of deleting that snippet you shared?
Otherwise, it might be confusing if that's there, and there's a call below of ->is_class_allowed_in_amp_date_picker()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd defer to @schlessera for his recommendation, since he highly optimized this method.
I'd probably rather change this method to:
return in_array( strtok( $class, '_' ), $class_prefixes, true );
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, as explained in my comment above, the logic needs to be integrated into the switch statement that already has the datepicker included, otherwise this is getting a big performance hit again.
This would then take care of the 'amp-date-picker-' === substr( $class, 0, 16 )
bit, which would be a given once you enter here.
Keep in mind that this logic runs 20k to 30k times on a single request for a regular page. It is important to keep this highly optimized when making changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@schlessera what do you think of this approach: b6f1a23?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -662,6 +662,12 @@ private function has_used_class_name( $class_names ) { | |||
} | |||
} | |||
|
|||
// If the document has an amp-date-picker tag, check if this class is an allowed child of it. | |||
// That component's child classes won't be present yet in the document, so prevent tree-shaking valid classes. | |||
if ( $this->has_used_tag_names( [ 'amp-date-picker' ] ) && $this->is_class_allowed_in_amp_date_picker( $class_name ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be integrated into the switch logic for the datepicker above that starts at line 651. Otherwise, we will always run the optimized loop, and then always run another check for the datepicker, suddenly making the entire loop work twice as much (and thus much slower).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, good point that this would be a big performance cost always running this other check.
Maybe I'm not understanding your suggestion.
But on moving this into the switch for the datepicker at line 651:`
diff --git a/includes/sanitizers/class-amp-style-sanitizer.php b/includes/sanitizers/class-amp-style-sanitizer.php
index e9e2b4be6..5f807791a 100644
--- a/includes/sanitizers/class-amp-style-sanitizer.php
+++ b/includes/sanitizers/class-amp-style-sanitizer.php
@@ -649,7 +649,7 @@ class AMP_Style_Sanitizer extends AMP_Base_Sanitizer {
switch ( substr( $class_name, 0, 16 ) ) {
// Class names for amp-date-picker, see <https://www.ampproject.org/docs/reference/components/amp-date-picker>.
case 'amp-date-picker-':
- if ( ! $this->has_used_tag_names( [ 'amp-date-picker' ] ) ) {
+ if ( ! $this->has_used_tag_names( [ 'amp-date-picker' ] ) || ! $this->is_class_allowed_in_amp_date_picker( $class_name ) ) { // Though this conditional will probably never be false.
return false;
}
continue 2;
@@ -662,12 +662,6 @@ class AMP_Style_Sanitizer extends AMP_Base_Sanitizer {
}
}
- // If the document has an amp-date-picker tag, check if this class is an allowed child of it.
- // That component's child classes won't be present yet in the document, so prevent tree-shaking valid classes.
- if ( $this->has_used_tag_names( [ 'amp-date-picker' ] ) && $this->is_class_allowed_in_amp_date_picker( $class_name ) ) {
- continue;
- }
-
if ( ! isset( $this->used_class_names[ $class_name ] ) ) {
return false;
}
...this won't allow the classes in is_class_allowed_in_amp_date_picker()
static $class_prefixes = [
'CalendarDay',
'CalendarMonth',
'CalendarMonthGrid',
'DayPicker',
'DayPickerKeyboardShortcuts',
'DayPickerNavigation',
'KeyboardShortcutRow',
];
...as they don't begin with amp-date-picker-
.
But maybe I'm not understanding your point. And your point about the performance cost is well taken.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return true; | ||
} | ||
|
||
return 'amp-date-picker-' === substr( $class, 0, 16 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, as explained in my comment above, the logic needs to be integrated into the switch statement that already has the datepicker included, otherwise this is getting a big performance hit again.
This would then take care of the 'amp-date-picker-' === substr( $class, 0, 16 )
bit, which would be a given once you enter here.
Keep in mind that this logic runs 20k to 30k times on a single request for a regular page. It is important to keep this highly optimized when making changes.
* @return bool Whether the class is allowed as a child of <amp-date-picker>. | ||
*/ | ||
private function is_class_allowed_in_amp_date_picker( $class ) { | ||
$class_prefixes = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be either a const array, or a static variable. Otherwise, you're creating and filling up a fresh new array every single time this method runs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, this is applied in 01a8e8f
On Alain's suggestion, as this would have to be recreacted every time.
…picker-tree-shaking * 'develop' of github.com:ampproject/amp-wp: (285 commits) Add PHPStan config files to libraries Remove erroneous unset Use US spelling analyze instead of analyse Remove static analysis step from common scripts section in travis.yml Fix missing unset Readd condition for running php-stan Raise PHPStan level in plugin to 2 Raise PHPStan level in plugin to 1 Fix conditional running of test steps Remove wrong psot-update action in ampproject/common again Better attempt at normalizing Composer file Normalize Composer file Update Composer lock file Run PHPStan in Travis Fix PHPCS issues Fix weird *NEVER* array unset error Fix stub sanitizer Typehint array being unset Skip analysing view template Fix bug in AMP_DOM_Utils referencing inexistent property ...
Nice, thanks! |
Summary
Prevents tree-shaking of valid child classes of
amp-date-picker
, if that tag is in the document.When adding the markup and styling that Weston shared to a Custom HTML block:
...it's not tree-shaken:
Fixes #4334
Checklist