Skip to content
This repository was archived by the owner on Jan 11, 2023. It is now read-only.

Feature request: custom cache-control headers #567

Closed
nolanlawson opened this issue Feb 16, 2019 · 15 comments · Fixed by #1173
Closed

Feature request: custom cache-control headers #567

nolanlawson opened this issue Feb 16, 2019 · 15 comments · Fixed by #1173
Labels

Comments

@nolanlawson
Copy link
Contributor

nolanlawson commented Feb 16, 2019

I think I mentioned this in a previous issue, but it would be nice to be able to override Sapper's built-in cache-control headers. Sometimes you want to add public, or sometimes you want to increase or decrease the max-age, etc.

Currently I can work around this, but it's extremely hacky:

function overrideSetHeader (req, res, next) {
  const origSetHeader = res.setHeader
  res.setHeader = function (key, value) {
    if (key === 'Cache-Control') {
      if (value === 'max-age=31536000, immutable') { // webpack assets
        return origSetHeader.apply(this, ['Cache-Control', 'public,max-age=31536000,immutable'])
      }
      if (value === 'max-age=600') { // HTML files
        return origSetHeader.apply(this, ['Cache-Control', 'public,max-age=3600'])
      }
    }

    return origSetHeader.apply(this, arguments)
  }
  return next()
}

app.use(overrideSetHeader, sapper.middleware())

If there's some Express/Polka-standard way for middleware to do this then I'd be happy with that; else maybe it could just be an option passed in to sapper.middleware()?

@antony
Copy link
Member

antony commented Apr 26, 2019

This has become mission critical for me I think. The problem is that whenever I deploy, cloudflare/browsers cache the old pages with old asset references for 10 minutes, which appears to mean that the site runs, but in some weird half-broken state for all my users, who become immensely irritated since buttons stop clicking, dropdowns stop loading etc.

I would assess therefore that this feature is very high priority, since it makes reliable continuous delivery of a sapper application nearly impossible right now.

The workaround looks good - I will implement this on my application asap, since right now I've just had to turn the CDN off which is far from ideal.

@kylecordes
Copy link

This "serving a mix of old and new" is already well solved for the JavaScript served by Sapper: hashed URLs.

Maybe a good solution is to enhance Sapper, or the default configuration thereof, to also hash asset URLs? Many popular websites are served this way (with hashed asset URLs for images etc, not only JS) to prevent this kind of problem.

(As part of such a solution (I don’t know if there is a good Sapper answer for this part yet, even for JavaScript URLs) is that when deploying a new version, old asset URLs must also continue to serve their old contents for a while, to support pages already running in browsers, overly enthusiastic caching layers, etc.)

@alexdilley
Copy link

alexdilley commented Oct 16, 2019

The hard-set cache header stumped me when implementing the not-too-uncommon OAuth flow, à la:

Visit / (Cache-Control: max-age=600);
Log-in with social provider;
Be returned to OAuth /callback endpoint;
Respond with 302: Set-Cookie: '...', Location '/';
Get cached copy of / (instead of making a request and letting Sapper render the user with an authenticated view) 😠

(Oddly, this isn't an issue in Chrome: it seems it ignores any cache when following redirects.)

My hack-around (ooh, it's bad!)...

...a rollup-plugin-replace mapping:

'max-age=600': 'no-cache'

💥 🤠

Q: Why set a Cache-Control header at all for page requests – aren't they largely dynamic by nature (I'd be using sapper export for static pages, right)?

@gka
Copy link
Contributor

gka commented Apr 28, 2020

a fixed maxage is simply not practical for many applications, and for our upcoming release we're going to ship the sort of ugly setHeader overwrite workaround. It would be really good to get this resolved in a less hacky way.

@benmccann
Copy link
Member

benmccann commented May 13, 2020

I think a good default would be to set the cache age to 0 for all dynamic content and used a long-lived expires header for static content with a hash in the filename. The default for dynamic content right now doesn't make sense. Sapper handles the static content it serves under /client well by hashing it for a year:

cache_control: dev ? 'no-cache' : 'max-age=31536000, immutable'

@jthegedus
Copy link
Contributor

@benmccann

Sapper doesn't serve static content...

I just wanted to say that Sapper pages without preload are essentially static pages. While I agree Sapper shouldn't enforce the cache_control it is useful for many pages on people's existing sites.

Supporting users customising the cache_control is obviously the best path forward and removing the cache_control in the meantime is also preferred.

@antony
Copy link
Member

antony commented May 17, 2020

@jthegedus I'm not 100% I agree with your conclusion. A static page would be defined as one whose content doesn't change between renders. If you were to have logic in your script tag which affected renders then this would not be the case.

I'm very much in favour of having a globally configurable default here, with a future view to having it configurable on a per-route basis.

@jthegedus
Copy link
Contributor

@antony with regards to cache_control though we only really care about whether the page changes during SSR, not client-side. If the SSR output doesn't change then it can be considered static, no?

@pngwn
Copy link
Member

pngwn commented May 17, 2020

But logic in the script can also modify the SSR output as well.

@antony
Copy link
Member

antony commented May 17, 2020

@jthegedus to clarify - <script context="module"> only modifies SSR content, <script> can modify both SSR and CSR content.

@pngwn
Copy link
Member

pngwn commented May 17, 2020

Huh? They both run client and server.

@jthegedus
Copy link
Contributor

jthegedus commented May 17, 2020

This particular discussion is probably best had in #1046 The confusion here makes me think the API could be more strict to better enable (support) future features and optimisations.

@antony
Copy link
Member

antony commented May 18, 2020

@pngwn yeah sorry, my bad. Should have been sleeping not typing. @jthegedus I think the API on this is very clear (despite my confusing it further!). In fact Svelte/Sapper's SSR/CSR separation is the clearest of any of the similar frameworks.

I think we should fix this issue and close this by making the header modifiable, and then further optimisation belongs in the ticket you linked.

@benmccann
Copy link
Member

I raised an issue in the template to add hashes to the static filenames and provided the code to do so there. If I don't hear any objections I'll send it as a PR.

@benmccann
Copy link
Member

We've removed the Cache-Control header from dynamic pages by default, which solves most of the issues mentioned here. Cache-Control will still be used for the files under /client. If you'd like to customize, you can use a middleware to set it based on the path. I've filed a new issue to track the feature request of providing a friendlier way to make headers more configurable: #1354

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants