mathdown
mathdown copied to clipboard
Caching headers
GH Pages sends Cache-Control:max-age=600
header (and corresponding Expires
in 10minutes).
http://www.webpagetest.org/performance_optimization.php?test=150216_4T_H0J&run=1&cached=0
Also it was served via Fastly CDN.
Heroku and RHcloud [http://www.webpagetest.org/result/150216_TV_HNP/, http://www.webpagetest.org/result/150216_CH_HP2/] also set 10 minutes.
So at least I'm not worse off...
Background reading: http://tomayko.com/writings/things-caches-do I see 3 approaches:
- Longer fixed max-age. Not good when rolling out new version; in fact 10min can also cause breakage.
- ETag with hash of content. Still requires request but probably cheap with HTTP pipelining?
- Change URL when content changes (e.g. include git commit), so max-age can be set to infinity. This is hard to do with dev/prod parity — if index.html from checkout works, then dynamic server must rewrite links? Also, unless every single file changes (which requires more extensive rewriting) this may end up caching less than stable URL + ETag.
Oh, should also read up cache manifests (or is that only for browser extensions?).
http://security.stackexchange.com/a/7008/31246 - set Cache-control: public
to allow caching on HTTPS
Turns out there is some caching:
Load Time | First Byte | Start Render | Speed Index | DOM Elements | Time | Requests | Bytes In | Time | Requests | Bytes In | |
---|---|---|---|---|---|---|---|---|---|---|---|
Document Complete | Fully Loaded | ||||||||||
First View | 7.617s | 0.373s | 4.100s | 7258 | 75 | 7.617s | 37 | 426 KB | 12.441s | 52 | 466 KB |
Repeat View | 0.995s | 1.993s | 0.995s | 2273 | 74 | 0.995s | 0 | 0 KB | 4.377s | 8 | 29 KB |
[http://www.webpagetest.org/result/150220_21_CGX/]
There are basically 2 kinds of caching:
- Expiration (
max-age
and/orexpires
) — the period when no request is needed at all — is not effective at 10min. - Then the browser falls back to validation (
etag
— sending a request but hopefully getting a short "304 Not Modified" response. This works.
Relevant headers in our response from RHcloud-hosted mathdown.net (on codemirror.js):
cache-control:public, max-age=600
etag:"64770-742663784-1418313063000"
last-modified:Thu, 11 Dec 2014 15:51:03 GMT
The last-modified time here is matches the file date (verified via ssh into rhcloud & heroku run):
- On RHcloud it's Dec 11, matching the CodeMirror git commit that last affected codemirror.js.
- On heroku it's FEb 20, mathcing time of last deploy.
- On my local filesystem (with default git settings), it's whenever I did git pull etc...
The etag is generated based on the dev, ino, and last modified date. Stat results are cached. [https://www.npmjs.com/package/st]
I actually want to get rid of max-age — for 10min after each deploy it may cause unpredictable bugs due to mixed versions.
The sane way to use max-age is to make it infinite and change URLs every time content changes. This is the most optimal approach but I don't see an easy way to make same it work with static files without rewriting relative paths in HTML and CSS.
There is one non-intrusive way of putting the whole static hierarchy under a subdir (named e.g. static-G1THA5H/
). Perhaps aided by `
During developement, changing a file still serves the old file for a short time (minute?), even with Shift+refresh.
As part of #172 I moved to Netlify, which does something sensible as a CDN, and I no longer care what exactly :eyeglasses: