History

Make service worker opt-in in development

Jasper van Merle committed 7 years ago

Commit 576f32d1 parent 0cd152712 files · +36 −31Browse files

Unified · Split

12 files
  1. Dockerfile +1 −0
  2. Dockerfile-alpine +1 −0
  3. assets/javascripts/app/config.coffee.erb +1 −0
  4. assets/javascripts/app/serviceworker.coffee +1 −1
  5. assets/javascripts/app/settings.coffee +0 −6
  6. assets/javascripts/templates/pages/offline_tmpl.coffee +6 −1
  7. assets/javascripts/templates/pages/root_tmpl.coffee.erb +1 −1
  8. assets/javascripts/templates/pages/settings_tmpl.coffee +0 −4
  9. assets/javascripts/views/content/settings_page.coffee +0 −7
  10. docs/adding-docs.md +0 −2
  11. lib/app.rb +22 −2
  12. views/service-worker.js.erb +3 −7
Dockerfile+1−0
@@ -1,6 +1,7 @@
11 FROM ruby:2.6.0
22
33 ENV LANG=C.UTF-8
4+ENV ENABLE_SERVICE_WORKER=true
45
56 WORKDIR /devdocs
67
Dockerfile-alpine+1−0
@@ -1,6 +1,7 @@
11 FROM ruby:2.6.0-alpine
22
33 ENV LANG=C.UTF-8
4+ENV ENABLE_SERVICE_WORKER=true
45
56 WORKDIR /devdocs
67
assets/javascripts/app/config.coffee.erb+1−0
@@ -14,3 +14,4 @@ app.config = · 13 unmodified lines
1414 release: <%= Time.now.utc.httpdate.to_json %>
1515 mathml_stylesheet: '<%= App.cdn_origin %>/mathml.css'
1616 service_worker_path: '/service-worker.js'
17+ service_worker_enabled: <%= App.environment == 'production' || !ENV["ENABLE_SERVICE_WORKER"].nil? %>
assets/javascripts/app/serviceworker.coffee+1−1
@@ -2,7 +2,7 @@ class app.ServiceWorker · 1 unmodified line
22 $.extend @prototype, Events
33
44 @isEnabled: ->
5− !!navigator.serviceWorker
5+ !!navigator.serviceWorker and app.config.service_worker_enabled
66
77 constructor: ->
88 @registration = null
assets/javascripts/app/settings.coffee+0−6
@@ -5,7 +5,6 @@ class app.Settings · 4 unmodified lines
55 'manualUpdate'
66 'fastScroll'
77 'arrowScroll'
8− 'bypassCache'
98 'docs'
109 'dark'
1110 'layout'
@@ -92,11 +91,6 @@ class app.Settings · 80 unmodified lines
9291 @set 'size', value
9392 return
9493
95− setBypassCache: (value) ->
96− @set 'bypassCache', value
97− app.serviceWorker?.updateInBackground()
98− return
99−
10094 dump: ->
10195 @store.dump()
10296
assets/javascripts/templates/pages/offline_tmpl.coffee+6−1
@@ -44,7 +44,12 @@ canICloseTheTab = -> · 43 unmodified lines
4444 if app.ServiceWorker.isEnabled()
4545 """ Yes! Even offline, you can open a new tab, go to <a href="//devdocs.io">devdocs.io</a>, and everything will work as if you were online (provided you installed all the documentations you want to use beforehand). """
4646 else
47− """ No. Service Workers aren't available in your browser (or are disabled), so loading <a href="//devdocs.io">devdocs.io</a> offline won't work.<br>
47+ reason = "aren't available in your browser (or are disabled)"
48+
49+ if app.config.env != 'production'
50+ reason = "are disabled in your development instance of DevDocs (enable them by setting the ENABLE_SERVICE_WORKERS environment variable)"
51+
52+ """ No. Service Workers #{reason}, so loading <a href="//devdocs.io">devdocs.io</a> offline won't work.<br>
4853 The current tab will continue to function even when you go offline (provided you installed all the documentations beforehand). """
4954
5055 app.templates.offlineDoc = (doc, status) ->
assets/javascripts/templates/pages/root_tmpl.coffee.erb+1−1
@@ -8,7 +8,7 @@ app.templates.intro = """ · 7 unmodified lines
88 <p>Thanks for downloading DevDocs. Here are a few things you should know:
99 <ol class="_intro-list">
1010 <li>Your local version of DevDocs won't self-update. Unless you're modifying the code,
11− I&nbsp;recommend using the hosted version at <a href="https://devdocs.io">devdocs.io</a>.
11+ we&nbsp;recommend using the hosted version at <a href="https://devdocs.io">devdocs.io</a>.
1212 <li>Run <code>thor docs:list</code> to see all available documentations.
1313 <li>Run <code>thor docs:download &lt;name&gt;</code> to download documentations.
1414 <li>Run <code>thor docs:download --installed</code> to update all downloaded documentations.
assets/javascripts/templates/pages/settings_tmpl.coffee+0−4
@@ -15,10 +15,6 @@ app.templates.settingsPage = (settings) -> """ · 14 unmodified lines
1515 <input type="checkbox" form="settings" name="layout" value="_sidebar-hidden"#{if settings['_sidebar-hidden'] then ' checked' else ''}>Automatically hide and show the sidebar
1616 <small>Tip: drag the edge of the sidebar to resize it.</small>
1717 </label>
18− <label class="_settings-label">
19− <input type="checkbox" form="settings" name="bypassCache" value="1"#{if settings.bypassCache then ' checked' else ''}>Bypass Service Worker cache
20− <small>When this is checked, the Service Worker will always fetch the latest version of requested files. Useful when making changes to the DevDocs source code.</small>
21− </label>
2218 </div>
2319 </div>
2420
assets/javascripts/views/content/settings_page.coffee+0−7
@@ -14,7 +14,6 @@ class app.views.SettingsPage extends app.View · 13 unmodified lines
1414 settings.dark = app.settings.get('dark')
1515 settings.smoothScroll = !app.settings.get('fastScroll')
1616 settings.arrowScroll = app.settings.get('arrowScroll')
17− settings.bypassCache = app.settings.get('bypassCache')
1817 settings[layout] = app.settings.hasLayout(layout) for layout in app.settings.LAYOUTS
1918 settings
2019
@@ -33,10 +32,6 @@ class app.views.SettingsPage extends app.View · 12 unmodified lines
3332 app.settings.set('fastScroll', !enable)
3433 return
3534
36− toggleBypassCache: (enable) ->
37− app.settings.setBypassCache(!!enable)
38− return
39−
4035 toggle: (name, enable) ->
4136 app.settings.set(name, enable)
4237 return
@@ -80,8 +75,6 @@ class app.views.SettingsPage extends app.View · 37 unmodified lines
8075 @toggleSmoothScroll input.checked
8176 when 'import'
8277 @import input.files[0], input
83− when 'bypassCache'
84− @toggleBypassCache input.checked
8578 else
8679 @toggle input.name, input.checked
8780 return
docs/adding-docs.md+0−2
@@ -2,8 +2,6 @@ Adding a documentation may look like a daunting task but once you get the hang o · 1 unmodified line
22
33 **Note:** please read the [contributing guidelines](../.github/CONTRIBUTING.md) before submitting a new documentation.
44
5−**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.
6−
75 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`)
86 2. Add the appropriate class attributes and filter options (see the [Scraper Reference](./scraper-reference.md) page).
97 3. Check that the scraper is listed in `thor docs:list`.
lib/app.rb+22−2
@@ -205,8 +205,28 @@ class App < Sinatra::Application · 204 unmodified lines
205205 ].compact
206206 end
207207
208− def bypass_cache?
209− !memoized_cookies['bypassCache'].nil?
208+ def service_worker_cache_name
209+ # Returns the digest of the last modified asset
210+ # When a manifest exist, this digest is only calculated once based on the asset manifest because it never changes without a server restart
211+ # 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
212+ if File.exist?(App.assets_manifest_path)
213+ return @@service_worker_cache_name ||=
214+ Sprockets::Manifest
215+ .new(nil, App.assets_manifest_path)
216+ .files
217+ .values
218+ .sort_by {|file| file["mtime"]}
219+ .reverse
220+ .first["digest"]
221+ else
222+ last_modified_file = App.sprockets
223+ .each_file
224+ .to_a
225+ .reject {|file| file.start_with?(App.docs_path)}
226+ .max_by {|file| File.mtime(file)}
227+
228+ return App.sprockets.pack_base64digest(App.sprockets.file_digest(last_modified_file))
229+ end
210230 end
211231
212232 def redirect_via_js(path)
views/service-worker.js.erb+3−7
@@ -1,6 +1,6 @@
1−<%# Use the hash of the application.js file as cache name or 'app' if not running in production %>
2−<%# This ensures that the cache is always updated if the hash of the application.js file changes %>
3−const cacheName = '<%= javascript_path('application', asset_host: false).scan(/application-([^\.]+)\.js/).last&.first || 'app' %>';
1+<%# The name of the cache to store responses in %>
2+<%# If the cache name changes DevDocs is assumed to be updated %>
3+const cacheName = '<%= service_worker_cache_name %>';
44
55 <%# Url's to cache when the service worker is installed %>
66 const urlsToCache = [
@@ -32,9 +32,6 @@ self.addEventListener('activate', event => { · 25 unmodified lines
3232 <%# Handle HTTP requests %>
3333 self.addEventListener('fetch', event => {
3434 event.respondWith((async () => {
35− <% if bypass_cache? %>
36− return fetch(event.request);
37− <% else %>
3835 const cachedResponse = await caches.match(event.request);
3936 if (cachedResponse) return cachedResponse;
4037
@@ -53,6 +50,5 @@ self.addEventListener('fetch', event => { · 12 unmodified lines
5350
5451 throw err;
5552 }
56− <% end %>
5753 })());
5854 });