• Dadman with a boy
  • Posts: 16,078
CSS caching
« on May 10th, 2011, 06:43 PM »Last edited on September 11th, 2011, 06:57 PM by Nao
Feature: CSS caching
Developer: Nao
Target: everyone
Status: 100% (believed to be complete.)

This is pretty much the same as for JavaScript caching, except that there's only one code path for CSS, since there aren't 50 ways to minify stylesheets.

Now, I'd just like to point out that thanks to the preparser, Wedge's cached CSS files will also embed all of the icon data, saving you yet another number of additional hits that servers and browsers usually don't like too much. IE6 and IE7 don't support data embedding, so they'll simply keep using external links. Who uses these stupid browsers anyway?

Re: CSS caching
« Reply #1, on May 1st, 2013, 05:56 PM »
I'm having a pretty annoying problem with regards to caching...

So, up until now, I've been naively doing things and just storing these variables in the CSS filename: browser ID and version, OS ID and version, whether you're a member or not, whether you're an admin, or in RTL mode, and whether you're in a certain board or category. If any of these was not used in the suffix list of all CSS files concatenated into one, then the keyword wouldn't be stored. E.g., if you don't have an index.rtl.css file in the file list to be concatenated, *or* your language isn't in RTL mode, you wouldn't see the rtl keyword in the cached filename.

Okay, right...
It all works, until you come to an addition I made to Wess a few months ago: @if keywords... These are used INSIDE the CSS file, and apply to the same things as the file suffixes, i.e. browser, OS, membership details, board ID, etc.
I didn't really use the feature for anything else than is_member and browser testing, and it makes sense.
Then it struck me yesterday, that these really didn't get cached at all... So, I rewrote the cache to take the file contents into account, and add its @if successful tests to the suffix list in the cached filename. Right.

And then all hell broke lose...

@if b1
   color: red

This doesn't work.
This doesn't work.
This doesn't work.

It only works if you're generating the file when INSIDE board #1. Then it gets properly added to a new file, with 'b1' in its filename.

But if you first generate a file from within another page, it caches the suffix list of successes, and b1 isn't a success, because we're not there... So, if visiting b1 after that, it simply retrieves the default filename, which doesn't have b1 in it.

Possible solutions:

- Never cache files, always rebuild them. Preposterous...

- Do not allow the use of some keywords inside files: b1, c1, m1, things like that... Only allow them inside suffixes of satellite CSS files (index.b1,b2.css). I did my rewrite precisely because I wanted more flexibility for file suffixes, but this update would instead give less flexibility to integrated @if tests...

- Never cache suffix tests (except maybe for 'm' followed by member ID, because we don't want one file per member..?!), always build a different file for each situation; i.e., if I'm the admin and running board 1 in RTL mode, create a new file called member-admin-rtl-b1-12345.css.gz, even if there are no admin or RTL tests within the CSS files themselves...

- Cache the *entire* list of integrated @if tests that FAILED, and then when loading a CSS file, check whether one of these failed tests are actually valid in our current situation; if yes, then re-cache our file with the new situation. Otherwise, just use the currently cached version. This makes handling much more complex than it already is; and is potentially slower, as these tests would all be done on every page load, even if a file is already cached...... :-/

Maybe there's another solution, but I can't think of it...?
I'm quite upset. I should have thought about that yesterday, or something... :-/
Re: CSS caching
« Reply #2, on May 1st, 2013, 11:40 PM »
tl:dr; if someone's interested in Wess and caching and everything, please just err... read this post, and give your opinions... I can't really force anyone to get into something this complicated, so I'll guess it'll stay that way, but hopefully I'll sleep over it..? :-/

So... I've sold part of the problem, by removing support for b1/c1 entirely.
I've replaced it with b1/c1 classes that are added next to the dynamic ID that already gives the ability to style the current action... (e.g. <div class="content"><div class="frame b3 c1" id="topic"> means you're in the main content div of a topic page located in board #3, which is part of category #1.)
I don't know yet if it's worth showing the category ID, though...
All in all, I don't even know if everything's really useful, because if your goal is to offer a different layout for a specific board, you can just as well create a new sub-skin, and then assign it to your board, and that's it, you're done... Of course, users are then free to change it... (Are they? I don't remember if we have an option to force a skin no matter what...?)

Still, I need to fix the rest... It's really much, much more complicated than I first expected.

For instance, let's say I'm member #1 and I'm running a skin that has an index.m1.css override. It'll see that keyword, add it to the list of special suffixes, and subsequently to my CSS filename. "member-m1-12345.css.gz" it is. Good.
Now, if by chance I've also added an "@if m1" test within the main index.css file, everything will work just the same. Good.
And that's when you decide to remove the index.m1.css file and move everything to the index.css file itself, ah...
So, Wess will first gather a list of existing file suffixes. Not a single 'm1' among them, so it doesn't test against 'm1' either, and thus doesn't add m1 to the suffix list. So, we're getting a filename that just says, "member". Now, we're accessing the cache that we stored relative to this 'member' key, which will return the complete filename *after* all internal @if tests were done and all positive keywords were added to the filename in the first place... So, that cache entry will return, for instance, 'member', same as the original, because no extra tests were triggered in index.css... Except that yes, we should have returned 'member-m1' instead, because there's a test for m1 in it, right..? Wrong. The cache key 'member' was generated during a page load for member #3854, and member #3854 failed the m1 test, and thus the returned cache key didn't have 'm1' in it... Very obviously.

It can get worse... For instance, if you're changing your language to a RTL one, how exactly do we tell Wess that you are now requiring it to return a positive on all "@if rtl" tests..?

I guess we'd need to either store a list of all tests per skin, and then do quick tests on these on each page load, or instead store the 'final filename' for each user, in their member data. But that DOES mean going through the caching process every time they do something, like a skin/language/sex/mod-status change. NOT FUN.

Another possibility, as mentioned before, would be to store all keywords that would return TRUE in your situation, i.e. at worst every one of your CSS files would start with the filename "member-m1-admin-webkit526.1-win6.1"... Uh. Then again, if ALL files use that filename, the HTML should compress well, but you're also generating a frigging single file per OS/browser/member-status combination. (And that's not even taking m1 into account; unless I use some extra caching, I'll have to get rid of m1 testing as well... Which I'd rather not do, since I've found good use for it even on this site..???)

Anyway... It just means I'm stumped. I can't figure out what the cleanest solution is. Every time I think of something, it feels like a regression to me. "Oh, okay, let's just get rid of board and categories... Oh, and member IDs too... And let's generate 3 times more files than I used to..."


:edit: Yay, this topic triggered the 'new'-indicator-on-quick-edit bug for me... And as always, it's always on the first one and not subsequent ones.
Posted: May 1st, 2013, 11:24 PM

Perhaps I should also ask this simple one:

Which keywords are most likely to be used by a themer, or plugin author, or admin, in crafting their CSS...?

browser (ie6, firefox[17-], whatver...)
os (android, ios[-5], whatever...)
member ID (m1, m2...)
board ID (b1...)
category ID (c1...)

Anything else..?

Re: CSS caching
« Reply #4, on May 2nd, 2013, 01:44 AM »
That's a lot to process after a long day troubleshooting crap code, I'll read it again tomorrow when I'm more awake.

Re: CSS caching
« Reply #5, on May 2nd, 2013, 07:22 AM »
Meanwhile... everyone's been very busy discussing SMF licensing changes and other things that were already discussed last month... and the month before... etc. I don't get why everyone is wasting their time repeating themselves continually. I get it that people don't give a damn about Wess, I'd just appreciate if they posted to say it here, because that would help me prioritize my own share of work on it...

Re: CSS caching
« Reply #6, on May 2nd, 2013, 12:49 PM »
everyone's been very busy discussing SMF licensing changes and other things that were already discussed last month... and the month before... etc. I don't get why everyone is wasting their time repeating themselves continually
Because of the ineptitude of the team that still hasn't managed to actually get this shit sorted out.

It's not that I don't care about Wess, it's that I have no idea what's truly best.

My gut instinct says these are important:
browser (ie6, firefox[17-], whatver...)
os (android, ios[-5], whatever...)
for modders and themers

and these are not:
member ID (m1, m2...)
board ID (b1...)
category ID (c1...)
For the simple reason that the first lot are pretty generic, the second lot are site specific. There are alternatives like creating different skins for different boards which negate the board and category id items to a degree. As for member specific... other than your own uses for it (for testing out styles before deployment, I doubt anyone would really use it)

Re: CSS caching
« Reply #7, on May 2nd, 2013, 01:02 PM »
Honestly I don't see the purpose of board, category and member modifiers, that shouldn't be stylesheets concern. Similarly the admin, guest member and mod modifiers. Semantically, there should be different classes for cases and not a single class fluctuating on condition.

Re: CSS caching
« Reply #8, on May 2nd, 2013, 01:04 PM »
It's not really about classes changing on condition, it's more about inclusion for things like the admin/guest/member/mod modifiers, so you define it once in the master stylesheet but only show that to the user if they're actually in that group.

Saves bandwidth for everyone else if you hide admin-only stuff away, that sort of thing.

Re: CSS caching
« Reply #9, on May 2nd, 2013, 01:10 PM »
Isn't that changing on condition? I'm still not clear here.

Re: CSS caching
« Reply #10, on May 2nd, 2013, 01:13 PM »
Sure it is, but it's a preprocessor directive, nothing more.

The whole point of the exercise is that you have one source file with multiple outputs depending on the current user.

The reason it is done the way it is done is to minimise bandwidth: if the current user is a guest, don't include stuff that is only for members, so that the resultant CSS file for guests is smaller.

For example, the stuff about warnings will not be visible to guests. So there's no need to include it in the CSS file that guests get. It's still declared in the main Wess file.

Re: CSS caching
« Reply #11, on May 2nd, 2013, 01:20 PM »
Ah, that makes more sense. I guess they can stay then. But I'll keep my opinion on the specific modifiers.

Re: CSS caching
« Reply #12, on May 2nd, 2013, 07:54 PM »
Hmm, so... Sooooo..... Okay....

I finally pulled my finger out, and wrote some code to automatically store all tests in CSS files... The main index files have something like 20 tests, and executing them on every single page load is a total disaster. Indeed, I'm just pulling something else this time (your leg), and it all executes in less than a millisecond...
Considering that a millisecond is precisely my 'psychological barrier' when it comes to execution times of features I'm not excited to add, I'd say it's all good then! ;)

Now I just need to fix another 27 bugs, and I'll be done with it.......
Re: CSS caching
« Reply #13, on May 2nd, 2013, 08:28 PM »
And... All working :)

Not only that, but it seems that up until now, the b1 keyword never worked to target a board, because the keyword wasn't generated in the first place, ah ah... Needed to be done in loadBoard(), which is executed AFTER the 'we' object is created. (Well, AFAIK..?)

So, I did that 'final' test: added an "@if b1" test to my test CSS, then went to the homepage, filename was member-chrome26-ID.css.gz, then clicked on board #1, filename was member-chrome26-b1-ID.css.gz

Epic! :D

Of course, the final code is something like a kilobyte larger than it used to be... Next time I plan to rewrite something to 'simplify it' and 'remove some of the fat', I should get stuffed myself or something... :lol:
Re: CSS caching
« Reply #14, on May 3rd, 2013, 12:05 AM »
My semi-final code, as surprising as it is to me, IS actually less complex than the original one...!

Class-CSS: 10 more bytes... Not much!
Class-System: 10 more bytes, too...!
Subs-Cache: 600+ bytes LESS!
Load: 2000+ bytes LESS!

Yay... :) Just need to rewrite the plugin-related code though, I'll probably have to 'forbid' use of file suffixes for them, and only allow for @if tests, which I'm assuming to be just fine! All right..?

Plus, I'm finished with Fringe. Nice final episodes! Was a pretty good show, in the end...

Re: CSS caching
« Reply #15, on May 3rd, 2013, 12:35 AM »
Sounds good to me, just I hope I won't have any changes to fix up in my code, I shouldn't have anything that will conflict though.