From 576f32dae1ef2d987eb4c3f1d810a249729ff20e Mon Sep 17 00:00:00 2001 From: Jasper van Merle Date: Wed, 10 Jul 2019 19:48:36 +0200 Subject: [PATCH] Make service worker opt-in in development --- Dockerfile | 1 + Dockerfile-alpine | 1 + assets/javascripts/app/config.coffee.erb | 1 + assets/javascripts/app/serviceworker.coffee | 2 +- assets/javascripts/app/settings.coffee | 6 ----- .../templates/pages/offline_tmpl.coffee | 7 +++++- .../templates/pages/root_tmpl.coffee.erb | 2 +- .../templates/pages/settings_tmpl.coffee | 4 ---- .../views/content/settings_page.coffee | 7 ------ docs/adding-docs.md | 2 -- lib/app.rb | 24 +++++++++++++++++-- views/service-worker.js.erb | 10 +++----- 12 files changed, 36 insertions(+), 31 deletions(-) diff --git a/Dockerfile b/Dockerfile index 77443edd..420bd195 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM ruby:2.6.0 ENV LANG=C.UTF-8 +ENV ENABLE_SERVICE_WORKER=true WORKDIR /devdocs diff --git a/Dockerfile-alpine b/Dockerfile-alpine index 5bd25afe..a5d993f7 100644 --- a/Dockerfile-alpine +++ b/Dockerfile-alpine @@ -1,6 +1,7 @@ FROM ruby:2.6.0-alpine ENV LANG=C.UTF-8 +ENV ENABLE_SERVICE_WORKER=true WORKDIR /devdocs diff --git a/assets/javascripts/app/config.coffee.erb b/assets/javascripts/app/config.coffee.erb index 765da0b5..9b28b5a5 100644 --- a/assets/javascripts/app/config.coffee.erb +++ b/assets/javascripts/app/config.coffee.erb @@ -14,3 +14,4 @@ app.config = release: <%= Time.now.utc.httpdate.to_json %> mathml_stylesheet: '<%= App.cdn_origin %>/mathml.css' service_worker_path: '/service-worker.js' + service_worker_enabled: <%= App.environment == 'production' || !ENV["ENABLE_SERVICE_WORKER"].nil? %> diff --git a/assets/javascripts/app/serviceworker.coffee b/assets/javascripts/app/serviceworker.coffee index 7a58f304..188a7e42 100644 --- a/assets/javascripts/app/serviceworker.coffee +++ b/assets/javascripts/app/serviceworker.coffee @@ -2,7 +2,7 @@ class app.ServiceWorker $.extend @prototype, Events @isEnabled: -> - !!navigator.serviceWorker + !!navigator.serviceWorker and app.config.service_worker_enabled constructor: -> @registration = null diff --git a/assets/javascripts/app/settings.coffee b/assets/javascripts/app/settings.coffee index 58875f42..0540bfb7 100644 --- a/assets/javascripts/app/settings.coffee +++ b/assets/javascripts/app/settings.coffee @@ -5,7 +5,6 @@ class app.Settings 'manualUpdate' 'fastScroll' 'arrowScroll' - 'bypassCache' 'docs' 'dark' 'layout' @@ -92,11 +91,6 @@ class app.Settings @set 'size', value return - setBypassCache: (value) -> - @set 'bypassCache', value - app.serviceWorker?.updateInBackground() - return - dump: -> @store.dump() diff --git a/assets/javascripts/templates/pages/offline_tmpl.coffee b/assets/javascripts/templates/pages/offline_tmpl.coffee index 52705605..52f64839 100644 --- a/assets/javascripts/templates/pages/offline_tmpl.coffee +++ b/assets/javascripts/templates/pages/offline_tmpl.coffee @@ -44,7 +44,12 @@ canICloseTheTab = -> if app.ServiceWorker.isEnabled() """ Yes! Even offline, you can open a new tab, go to devdocs.io, and everything will work as if you were online (provided you installed all the documentations you want to use beforehand). """ else - """ No. Service Workers aren't available in your browser (or are disabled), so loading devdocs.io offline won't work.
+ reason = "aren't available in your browser (or are disabled)" + + if app.config.env != 'production' + reason = "are disabled in your development instance of DevDocs (enable them by setting the ENABLE_SERVICE_WORKERS environment variable)" + + """ No. Service Workers #{reason}, so loading devdocs.io offline won't work.
The current tab will continue to function even when you go offline (provided you installed all the documentations beforehand). """ app.templates.offlineDoc = (doc, status) -> diff --git a/assets/javascripts/templates/pages/root_tmpl.coffee.erb b/assets/javascripts/templates/pages/root_tmpl.coffee.erb index 7adce7fd..a94a99a0 100644 --- a/assets/javascripts/templates/pages/root_tmpl.coffee.erb +++ b/assets/javascripts/templates/pages/root_tmpl.coffee.erb @@ -8,7 +8,7 @@ app.templates.intro = """

Thanks for downloading DevDocs. Here are a few things you should know:

  1. Your local version of DevDocs won't self-update. Unless you're modifying the code, - I recommend using the hosted version at devdocs.io. + we recommend using the hosted version at devdocs.io.
  2. Run thor docs:list to see all available documentations.
  3. Run thor docs:download <name> to download documentations.
  4. Run thor docs:download --installed to update all downloaded documentations. diff --git a/assets/javascripts/templates/pages/settings_tmpl.coffee b/assets/javascripts/templates/pages/settings_tmpl.coffee index 4a2066f1..1d439edb 100644 --- a/assets/javascripts/templates/pages/settings_tmpl.coffee +++ b/assets/javascripts/templates/pages/settings_tmpl.coffee @@ -15,10 +15,6 @@ app.templates.settingsPage = (settings) -> """ Automatically hide and show the sidebar Tip: drag the edge of the sidebar to resize it. - diff --git a/assets/javascripts/views/content/settings_page.coffee b/assets/javascripts/views/content/settings_page.coffee index 96904a13..af2e9a9d 100644 --- a/assets/javascripts/views/content/settings_page.coffee +++ b/assets/javascripts/views/content/settings_page.coffee @@ -14,7 +14,6 @@ class app.views.SettingsPage extends app.View settings.dark = app.settings.get('dark') settings.smoothScroll = !app.settings.get('fastScroll') settings.arrowScroll = app.settings.get('arrowScroll') - settings.bypassCache = app.settings.get('bypassCache') settings[layout] = app.settings.hasLayout(layout) for layout in app.settings.LAYOUTS settings @@ -33,10 +32,6 @@ class app.views.SettingsPage extends app.View app.settings.set('fastScroll', !enable) return - toggleBypassCache: (enable) -> - app.settings.setBypassCache(!!enable) - return - toggle: (name, enable) -> app.settings.set(name, enable) return @@ -80,8 +75,6 @@ class app.views.SettingsPage extends app.View @toggleSmoothScroll input.checked when 'import' @import input.files[0], input - when 'bypassCache' - @toggleBypassCache input.checked else @toggle input.name, input.checked return diff --git a/docs/adding-docs.md b/docs/adding-docs.md index 4b34b045..dfc96cb1 100644 --- a/docs/adding-docs.md +++ b/docs/adding-docs.md @@ -2,8 +2,6 @@ Adding a documentation may look like a daunting task but once you get the hang o **Note:** please read the [contributing guidelines](../.github/CONTRIBUTING.md) before submitting a new documentation. -**Note:** when editing any of the files in the `assets` directory or the `public` directory, you'll have to bypass the service worker cache. To do this, go to the Preferences page on your local instance of DevDocs, check "Bypass Service Worker cache" and refresh the page. - 1. Create a subclass of `Docs::UrlScraper` or `Docs::FileScraper` in the `lib/docs/scrapers/` directory. Its name should be the [PascalCase](http://api.rubyonrails.org/classes/String.html#method-i-camelize) equivalent of the filename (e.g. `my_doc` → `MyDoc`) 2. Add the appropriate class attributes and filter options (see the [Scraper Reference](./scraper-reference.md) page). 3. Check that the scraper is listed in `thor docs:list`. diff --git a/lib/app.rb b/lib/app.rb index 83e646e4..a0063e49 100644 --- a/lib/app.rb +++ b/lib/app.rb @@ -205,8 +205,28 @@ class App < Sinatra::Application ].compact end - def bypass_cache? - !memoized_cookies['bypassCache'].nil? + def service_worker_cache_name + # Returns the digest of the last modified asset + # When a manifest exist, this digest is only calculated once based on the asset manifest because it never changes without a server restart + # If a manifest does not exist, it is calculated every time this method is called because the assets can change while the server is running + if File.exist?(App.assets_manifest_path) + return @@service_worker_cache_name ||= + Sprockets::Manifest + .new(nil, App.assets_manifest_path) + .files + .values + .sort_by {|file| file["mtime"]} + .reverse + .first["digest"] + else + last_modified_file = App.sprockets + .each_file + .to_a + .reject {|file| file.start_with?(App.docs_path)} + .max_by {|file| File.mtime(file)} + + return App.sprockets.pack_base64digest(App.sprockets.file_digest(last_modified_file)) + end end def redirect_via_js(path) diff --git a/views/service-worker.js.erb b/views/service-worker.js.erb index 20de7bbe..d9eb4a6c 100644 --- a/views/service-worker.js.erb +++ b/views/service-worker.js.erb @@ -1,6 +1,6 @@ -<%# Use the hash of the application.js file as cache name or 'app' if not running in production %> -<%# This ensures that the cache is always updated if the hash of the application.js file changes %> -const cacheName = '<%= javascript_path('application', asset_host: false).scan(/application-([^\.]+)\.js/).last&.first || 'app' %>'; +<%# The name of the cache to store responses in %> +<%# If the cache name changes DevDocs is assumed to be updated %> +const cacheName = '<%= service_worker_cache_name %>'; <%# Url's to cache when the service worker is installed %> const urlsToCache = [ @@ -32,9 +32,6 @@ self.addEventListener('activate', event => { <%# Handle HTTP requests %> self.addEventListener('fetch', event => { event.respondWith((async () => { - <% if bypass_cache? %> - return fetch(event.request); - <% else %> const cachedResponse = await caches.match(event.request); if (cachedResponse) return cachedResponse; @@ -53,6 +50,5 @@ self.addEventListener('fetch', event => { throw err; } - <% end %> })()); });