Add runtime CSS minification, !important replacement, and tree shaking#1048
Add runtime CSS minification, !important replacement, and tree shaking#1048westonruter merged 32 commits intodevelopfrom
Conversation
* Compress CSS output with compact format, removing whitespace and comments. * Reduce length of generated class names for inline styles. * Unify logic for handling inline style attributes with handling stylesheets in style/link.
…oser install in Travis build
…tion instructions
…uring end of body
…c selectors (following replace-important package) Eliminate illegal_css_important_qualifier validation error now that transformed
73ad61a to
fd04b20
Compare
* Handle CSS parse errors. * Let spec inform which @-rules are allowed. * Improve handling of vendor-prefixed properties in whitelist/blacklists. * Inform when !important qualifier is removed from rules with selectors (that aren't keyframes).
…lid class references
| $selectors = array(); | ||
| if ( $should_tree_shake ) { | ||
| foreach ( $selectors_parsed as $selector => $class_names ) { | ||
| if ( count( $class_names ) === count( array_intersect( $class_names, $this->used_class_names ) ) ) { |
There was a problem hiding this comment.
Better to use array_diff here instead maybe.
…ent false matches
There was a problem hiding this comment.
Great Work
Hi @westonruter,
This PR is a big step forward for the plugin. It opens a lot of possibilities, including Gutenberg support.
As you know, the Gutenberg build/style.css file was too big for the 50 KB limit before.
It looks like there's still some discussion here. I added a few minor points, but I'm happy to approve this when it's ready.
| * | ||
| * @param array $query_vars Query vars. | ||
| * @return array Query vars. | ||
| */ |
There was a problem hiding this comment.
Nice improvements here with the DocBlocks and @since tags.
| 'error_message' => 'CSS !important', | ||
| 'regex' => '!important', | ||
| ), | ||
| 'css_spec' => array( |
There was a problem hiding this comment.
This corresponds well to the css_spec in the amphtml repo's validator-main.protoascii.
| /** | ||
| * Class AMP_Response_Headers | ||
| */ | ||
| class AMP_Response_Headers { |
There was a problem hiding this comment.
It's nice you you put this in a separate class 👍
| @@ -0,0 +1,116 @@ | |||
| <?php | |||
| /** | |||
| * Tests for Theme Support. | |||
There was a problem hiding this comment.
This DocBlock should probably be Tests for AMP_Response_Headers, and the same below.
| } | ||
| } | ||
|
|
||
| return $stylesheet; |
There was a problem hiding this comment.
Would it help to call the validation_error_callback here if $stylesheet is empty and it's from a <link>? This would account for when a stylesheet has no rules that pertain to DOM classes. Like if a plugin enqueues a stylesheet for its shortcode on every request.
if ( empty( $stylesheet ) && ( 'link' === $node->nodeName ) && ! empty( $this->args['validation_error_callback'] ) ) {
// Call validation callback
We'd probably have to deprecate amp-default.css to do this.
|
@westonruter this packages were developed by @camelburrito (from the UNCSS doc with @pbakaus): |
|
@amedina yes, I referred to
|
Just occurred to me that we could help guard against this from happening by adding logic to skip removing selectors that reference Nevertheless, there would be no way to statically account for class names assigned via @pbakaus Any other key dynamic content cases to have in mind? |
b278bc2 to
9a6cec0
Compare
…dd/css-tree-shaking
9a6cec0 to
313f0b9
Compare
|
@westonruter sounds sensible! Thats the only ones I have in mind right now. |
|
@westonruter usually the ones associated with And on the replace-important improvements feel free to edit the code here |
@camelburrito I added initial support for this via the @kienstra This is ready for review to merge so we can get this testing. I want to follow up later with some more improvements including the added ability to knowingly bypass removal of elements, attributes, and styles that are invalid but which a given site cannot afford to be removed. I'm thinking we'd want CSS over the 50KB limit to default to not be removed, even if that means it is invalid AMP. In terms of implementation here, I think this can be implemented by allowing the |
There was a problem hiding this comment.
Approved
Hi @westonruter,
This PR looks good, and it's approved. There's a small point about test_body_style_attribute_sanitizer(), but it's not a blocker.
Also:
allowing the
validation_error_callbackto return false as a way to prevent removal from happening
That sounds good, finalize_stylesheet_set() could check the return value of the validation_error_callback before removing the stylesheet.
| * @type callable $validation_error_callback Function to call when a validation error is encountered. | ||
| * } | ||
| */ | ||
| protected $args; |
| array(), | ||
| ), | ||
| 'styles_with_dynamic_elements' => array( | ||
| implode( '', array( |
There was a problem hiding this comment.
Great idea to use implode() here for the long document.
| * @param array $expected_errors Expected error codes. | ||
| */ | ||
| public function test_body_style_attribute_sanitizer( $source, $expected_content, $expected_stylesheets ) { | ||
| public function test_body_style_attribute_sanitizer( $source, $expected_content, $expected_stylesheets, $expected_errors = array() ) { |
There was a problem hiding this comment.
Maybe the 3rd $expected_errors parameter isn't necessary, given that the dataProvider get_link_and_style_test_data always has a 3rd array item: array(). But this isn't a blocker to approving.
There was a problem hiding this comment.
Yeah, you're right. But I suppose it aligns with the other tests and opens the door to testing for validation errors in the future.
AMP_Response_Headersclass. See Incorporate Server Timing API #990.-moz-bindingandbehavior).styleattributes.amp-keyframesappears anywhere but end ofbody, just move it to the end of thebody.!importantqualifiers.@keyframesto opacity, transform and -vendorPrefix-transform.:not(.classname). Also strip strings.Fixes #990.
Fixes #930.
Fixes #688.
Closes #610.
Ideas for later: