11

I use this in production.rb :

config.public_file_server.headers = {
  'Cache-Control' => 'public, s-maxage=31536000, maxage=31536000',
  'Expires'       => "#{1.year.from_now.to_formatted_s(:rfc822)}"
}

I use public files through a cdn.mydomain.com, which is reading from www.mydomain.com and it copies the cache-control from www.mydomain.com, that I set with public_file_server.headers.

The issue is that I want some files from /public to not have those cache-control, for example for my service-worker.js

Is there a way to set those cache control only for one folder in /public for example?

The other solution would be to remove this public_file_server.headers configuration, and setting the cache control on the cdn level (I use cdn.mydomain.com/publicfile), and keeping www.mydomain.com/serviceworker without cache control, for the service worker.

But maybe there is a chance to config this at the Rails level?

1 Answer 1

13

I had exactly the same problem: PWA built with Rails using CDN (Cloudfront). For the assets I want to use cache headers with far future expires, but the ServiceWorker needs Cache-control: No-cache.

Because CloudFront doesn't allow to add or change headers by itself, I need a solution on the app level. After some research I found a solution in a blogpost. The idea is to set headers via public_file_server.headers and add a middleware to change this for the ServiceWorker file.

Also, you wrote maxage=, it should be max-age=.

Here is the code I use:

production.rb:

config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
config.public_file_server.headers = {
  'Cache-Control' => 'public, s-maxage=31536000, max-age=15552000',
  'Expires' => 1.year.from_now.to_formatted_s(:rfc822)
}

if ENV['RAILS_SERVE_STATIC_FILES'].present?
  config.middleware.insert_before ActionDispatch::Static, ServiceWorkerManager, ['sw.js']
end

app/middleware/service_worker_manager.rb:

# Taken from https://codeburst.io/service-workers-rails-middleware-841d0194144d
#
class ServiceWorkerManager
  # We’ll pass 'service_workers' when we register this middleware.
  def initialize(app, service_workers)
    @app = app
    @service_workers = service_workers
  end

  def call(env)
    # Let the next middleware classes & app do their thing first…
    status, headers, response = @app.call(env)
    dont_cache = @service_workers.any? { |worker_name| env['REQUEST_PATH'].include?(worker_name) }

    # …and modify the response if a service worker was fetched.
    if dont_cache
      headers['Cache-Control'] = 'no-cache'
      headers.except!('Expires')
    end

    [status, headers, response]
  end
end
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.