In Dev Console I sometimes got a warning, that page reflow took so much ms. And because I'm curious, I looked up what it means.
Reflow is basically recalculation of dimensions and positions for some or all layout elements on the page. Just from this description you may understand it's pretty expensive (performance-wise) task.
Reflow can be triggered by manipulating DOM, changing visuals (computed styles and classes), resizing browser's window and more. Different browser engines have slightly different triggers and time required for the particular reflow type, but the general idea remains.
You can speed up the reflow process by reducing DOM depth, CSS rules and complex selectors; or moving complex rendering (e.g. animations) out of the flow using absolute or fixed position for the element.
If I find reengineering favorable, I usually go for it. Therefore major versions with breaking changes appear fairly quickly in the beginning of a new software product, allowing me to stabilize the API as soon as possible.
On the other hand, most changes are in QedyJS, so unfortunately almost none of the current improvements will go open source.
Scopes. Multiple modules at once, scope is passed with the component, which is no problem in most cases. But it's a little annoying, since I decided to have no cirucular references, which means a component can't contain scope object and therefore I have to pass component and scope separately in two parameters. And for the rest you must specify the scope, which is also annoying, but also necessary.
Speaking of scopes, I reimagined JavaScript scopes as well. Now module methods have direct access to the scope via this
and because I decided to “trust” converters, they have now direct access to components and therefore are able to modify them. It makes a lot of things much easier and more streamlined.
I waited with a release many months, to have full functionality right from the start. Nothing was postponed (like datastores in Mk. II), because that's what bit me in the butt in the past the most.
Found even more great articles and talks about JS performance and did tremendous amount of micro optimizations in the code, especially in loops, where it makes sense the most. Some (if not most) of them are probably unnecessary, but I'm a performance freak, so it feels good to have 'em all :-)
Got rid of domLinks, now links are bundled with the component. The same applies for items and data-realted logic (e.g. sorting and filtering) were moved from components to datastores.
Some of original designs are great and in fact some of them even goes back to Mk. I. And don't let me start with the whole concept of QetriX, I must admin it makes me proud the core basics I established over a decade ago still works perfectly.
I continue to abuse this blog as my guinea pig for performance related features, like prefetching and caching. PageSpeed Insights gave it a score of 100 for both mobile and desktop, which frankly I've never seen before.
My previous guinea pig has “only” 91/99, mostly because it uses Google AdSense and Analytics (which is also problematic for CSP, just sayin'). It's weird, that Google created metrics, which his own services, targeting as much websites as possible, don't comply with.
Anyway, speaking of caching, I created a HTML cache, published from localhost, removing any dynamic server side parts and making this blog less “powered by QetriX” and more like “powered by .htaccess” :-)
For path /blog/2020/01
I have a static HTML file /data/2020-01.html
and the .htaccess rule for it is:
That actually explains the PageSpeed score, it's basically a static website. And while on localhost it still takes time to load the page, the live version on webhosting loads pages instantaneously. Impressive! Another site with such speed I found is DEV.to, which uses InstantClick, and there are also some smaller sites, that use Web Workers to achieve the same.
Another trick to speed things up is to use “mousedown” event, instead of “click”. Click usually adds a around 300 ms of delay, waiting for the button to go up again, so that's what makes mousedown faster.
Drawbacks are ev.preventDefault()
doesn't work as expected in mousedown, so you'll need the click event handler alongside, but it's OK, because mousedown event is not fired when using keyboard anyway.
Also with mousedown it's not possible to easily select the element, e.g. for copy/paste. This could be a pain in clickable tables, where users can't select cell contents. And you may need to detect which mouse button triggered the event, to at least allow context menu for the element, and launch the action only for the primary button (left one, in most cases).
Moving on. Another feature I did in the past, but never actually finished it, until now, is enabling pasting images from clipboard to contentEditable element, with conversion and upload to the server, where the picture is resized, compressed and optimized (if necessary and possible).
With modern APIs in the browser it's actually a piece of cake and I was surprised I can even re-use almost all the code to enable drag'n'drop image uploading (good job, whoever designed this), so I added that as well. For all the events I have only a single method:
And finally, I made some fixes. I fixed disappearing tags on article edits, because I went the easy way and updated the whole JSON, but edits didn't send tags, so they got wiped out. After the fix, missing parts are filled from the original JSON using PHP's array_merge
, so nothing is lost in the process, and now I can send only the actual changes.
Lastly, I had a bug in history management, where in some cases the same entry was added twice. I fixed this fairly quickly and I was even able to remove a few unnecessary lines of code. ''Yay!''