propshaft icon indicating copy to clipboard operation
propshaft copied to clipboard

ability to specify cache-control header in config

Open equivalent opened this issue 2 years ago • 6 comments

Ability to tell what cache-control header we want the assets loaded with

This will solve the issue https://github.com/rails/propshaft/issues/90

Solution proposed by @dhh in issue 94 :

Screenshot 2022-12-29 at 21 07 56

two things here:

1. no-cache header

no-cache works but maybe no-store is more what we want (source) Screenshot 2022-12-29 at 21 09 50

... I don't mind either

2. this could be simpler?

I'm not sure if I didn't overkill this. Maybe something simpler would be enough eg:

# lib/propshaft/server.rb
       {
          #...
          "cache-control"   => Rails.development? ? 'no-store' : "public, max-age=31536000, immutable"
       }

...let me know I can simplify it

equivalent avatar Dec 29 '22 20:12 equivalent

🤔 wait a minute, now I'm re-reading @brenogazzola comment

Screenshot 2022-12-29 at 21 27 37

...hmm I'm not sure about the prod but this solved the dev isuue 🤔

screen recording 📹 👇 https://user-images.githubusercontent.com/721990/210008614-65a9d72f-f621-4145-b065-22848c9bee3d.mov

equivalent avatar Dec 29 '22 20:12 equivalent

Video looks a bit strange to me. The digest of application.css did not change, which means the @include "my-custom.css" should still be pointing to 8ffbe1. So how did the browser know it had to fetch f4b376 after refresh?

brenogazzola avatar Dec 30 '22 14:12 brenogazzola

@brenogazzola

Ok took me a while to realise what's happening:

  • yes application-xxxxxxxx.css digest don't change
  • yes I agree theoretically it should (as digest is calculated from content and @import url('/my-custom.css'); is translated to @import url('/my-custom-mmmmmmm.css'); = application.css content changed so it should be application-yyyyyy.css ... but it's not!)

To see what I mean please watch https://youtu.be/cqQHyJj7few

video showing digest dont change

So because browser don't cache application-xxxxxxxx.css it will load it from server every time and the next time loaded it poins to different @import url('/my-custom-nnnnnnnn.css'); => no issue like #90

how come the digest of application-xxxxxxxx.css didn't change ? 🤷‍♂️ my guess is that the digest of application.css is calculated on a file content before content gets digested (before my-custom.css turns to my-custom-nnnnnn.css

equivalent avatar Jan 14 '23 21:01 equivalent

one more thing - during testing the above I've stumbled upon an edegecase:

My PR proposes the no-store header by default for Development env(therefor no such issue as #90) 👍.

If a developer switch the non-cache header to any form of cache header and then switch back to no-store again, his/her browser will be stuck at old cache.

To see this in action pls watch https://youtu.be/3nmCubctHuk

video showing how browser needs cache clear when switch from cahce header to no-store

Given on cache header browser will cache the old application-xxxxx.css When I switch to no-store header browser still cache the old application-xxxxx.css Therefore it will not pick up the fact the my-custom.css has a new digest

conclusion:

  • My PR works 👍
  • My PR solves #90 issue in development (tat means first time users will not have that issue as Development env fixed by default) 👍
  • If someone tries to test if cache works, they need to clear the browser cache or do a change in application.css (so new digest appears for application-yyyy.css) 😕

equivalent avatar Jan 14 '23 21:01 equivalent

:muscle: I can confirm this fixes the problem. And yes, I had to wipe the cache locally first to get this change effective.

simi avatar Feb 22 '23 01:02 simi

how come the digest of application-xxxxxxxx.css didn't change ? 🤷‍♂️ my guess is that the digest of application.css is calculated on a file content before content gets digested (before my-custom.css turns to my-custom-nnnnnn.css

I'm a bit worried about this part. Yes, you are right, parent digest is calculated on the original content, not the one that was changed with the digest of the children imports.

This means this solution will give you a false impression that everything is working because in the development you are seeing the changes. But when you push to production, anyone who had already fetched the parent file (eg: your CDN which is sending the files to your users) will not fetch again it again, since its digest did not change and they think it's the same file.

This means that if you are using new classes that were added to the children files, your site is now broken (at least visually).

The only feasible solution I see is one that ensures that parent digest changes when children digest change

brenogazzola avatar May 07 '23 20:05 brenogazzola

We need to fix this at the root. The no-cache setup isn't going to work for production either. Need to invalidate files when their dependencies have changed. There are several open approaches for that, so exploring those.

dhh avatar May 15 '24 23:05 dhh