-
Notifications
You must be signed in to change notification settings - Fork 111
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
Add SVG output compression with performance testing #135
base: main
Are you sure you want to change the base?
Conversation
This algorithm has $O(log(N)$ or $O(c*N)$ growth - 1904labs#135 Refs: 1904labs#36, 1904labs#91, 1904labs#92
Welcome back!! I'll look over this tomorrow. |
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.
Looking pretty simple... welcome some comments on my questions.
if (name === 'animation-duration' || name === 'transition-duration') return; // dynamic properties | ||
|
||
const value = targetStyle.getPropertyValue(name); | ||
const declarations = tokenizeCssTextDeclarations(targetStyle.cssText); |
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.
Seems this is more costly to do this every time... probably should be working with the declarations
split out once, then in the loop we can go through each retaining the "kept" properties in one array and joining them up as we go (I get maintaining the order is important), so we are not constantly splitting the style up... we could map thing to a "keep/kill" pattern so that we replace the declaration[index]
with an empty string when sure we can elide it and then filtering them out just before the final squish?
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 tokenization is really cheap. I thought of doing it this way. But I was coding through a migraine aura..
If you could contribute it as a patch that would be appreciated 🙂
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 with you, cataract (eye) surgery yesterday... probably be a couple days before I can dive into wandering that code better, but this is very good so far :)
A question occurred to me just now, is it worth bypassing this logic if they're calling |
There is no legal restriction on this value. But 255 is a sane™️ limit. Refs: 1904labs#135
I personally think "yes". 10 seconds for 5000 nodes is objectively expensive at vast sizes. |
PERSONAL NOTE: I've had a setback on my eye surgery and will have to take some time away from computers (and thus this) for at least a few days. I WILL get this merged in sometime soon :) |
I'll try add back the vector-raster path in the meantime. |
If you do, make the path call all the way into toSVG and have it get an extract boolean to opt out of the simplification |
Are the following time results acceptable? |
@joswhite I know you were of the opinion this PR should be a package. |
This pull request has been published for external use by the way! |
@zm-cttae I would welcome a .MD file change for this pointing to your excellent package :) |
Fixes
Closes #92. Also related to #90.
Related to previous efforts #36 and #70.
Objective
Restore SVG output styling data compression using a performant algorithm:
dom-inline-style-filter
.User story
Pull request description
In the past, we have struggled to compress the output of
toSvg
indom-to-image-more
in a stable way.There is a writeup explaining our struggles in #92.
Even after an algorithm to filter out user agent styling when inlining the style, there is some ways to go with data size.
Implementation details
node
, group nodes by descending node depth.CSS inheritance is computed on the DOM tree via preorder traversal and is additive-cumulative (increases styling data).
For the filter op which is subtractive, we want to traverse the tree in the opposite direction.
The algorithm sorts elements in the
node
tree by descending node depth. (This is known as reverse level order traversal.)This gives us a 30% to 40% speed boost. This also ensures declarations are only removed when they really can be inherited.
In CSS, shorthands consistently have less hyphens than their longhand.
We want to filter out scenarios where a CSS property matches their shorthand.
E.g.
block-size
->height
orborder-color
->border
.The algorithm does a radix sort with bitmasks for standard, custom and vendored proprties, then subsorts by descending hyphen count.
In tests this filtered another 50% of inline styling.
We also get a 20-40% speed boost because we're not setting as many properties back.
Testing
The underlying algorithm was determined to be a multi-pass, high-pass deterministic compression in two modes:
This data is collected from manual testing on the output of
toSvg
API method.Results for large filesizes
0.1337
Results for small filesizes
0.1269