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 @@
1FROM ruby:2.6.01FROM ruby:2.6.0
2 2
3ENV LANG=C.UTF-83ENV LANG=C.UTF-8
4ENV ENABLE_SERVICE_WORKER=true
4 5
5WORKDIR /devdocs6WORKDIR /devdocs
6 7
Dockerfile-alpine+1−0
@@ -1,6 +1,7 @@
1FROM ruby:2.6.0-alpine1FROM ruby:2.6.0-alpine
2 2
3ENV LANG=C.UTF-83ENV LANG=C.UTF-8
4ENV ENABLE_SERVICE_WORKER=true
4 5
5WORKDIR /devdocs6WORKDIR /devdocs
6 7
assets/javascripts/app/config.coffee.erb+1−0
@@ -14,3 +14,4 @@ app.config = · 13 unmodified lines
14 release: <%= Time.now.utc.httpdate.to_json %>14 release: <%= Time.now.utc.httpdate.to_json %>
15 mathml_stylesheet: '<%= App.cdn_origin %>/mathml.css'15 mathml_stylesheet: '<%= App.cdn_origin %>/mathml.css'
16 service_worker_path: '/service-worker.js'16 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
2 $.extend @prototype, Events2 $.extend @prototype, Events
3 3
4 @isEnabled: ->4 @isEnabled: ->
5 !!navigator.serviceWorker5 !!navigator.serviceWorker and app.config.service_worker_enabled
6 6
7 constructor: ->7 constructor: ->
8 @registration = null8 @registration = null
assets/javascripts/app/settings.coffee+0−6
@@ -5,7 +5,6 @@ class app.Settings · 4 unmodified lines
5 'manualUpdate'5 'manualUpdate'
6 'fastScroll'6 'fastScroll'
7 'arrowScroll'7 'arrowScroll'
8 'bypassCache'
9 'docs'8 'docs'
10 'dark'9 'dark'
11 'layout'10 'layout'
@@ -92,11 +91,6 @@ class app.Settings · 80 unmodified lines
92 @set 'size', value91 @set 'size', value
93 return92 return
94 93
95 setBypassCache: (value) ->
96 @set 'bypassCache', value
97 app.serviceWorker?.updateInBackground()
98 return
99
100 dump: ->94 dump: ->
101 @store.dump()95 @store.dump()
102 96
assets/javascripts/templates/pages/offline_tmpl.coffee+6−1
@@ -44,7 +44,12 @@ canICloseTheTab = -> · 43 unmodified lines
44 if app.ServiceWorker.isEnabled()44 if app.ServiceWorker.isEnabled()
45 """ 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). """45 """ 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). """
46 else46 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>
48 The current tab will continue to function even when you go offline (provided you installed all the documentations beforehand). """53 The current tab will continue to function even when you go offline (provided you installed all the documentations beforehand). """
49 54
50app.templates.offlineDoc = (doc, status) ->55app.templates.offlineDoc = (doc, status) ->
assets/javascripts/templates/pages/root_tmpl.coffee.erb+1−1
@@ -8,7 +8,7 @@ app.templates.intro = """ · 7 unmodified lines
8 <p>Thanks for downloading DevDocs. Here are a few things you should know:8 <p>Thanks for downloading DevDocs. Here are a few things you should know:
9 <ol class="_intro-list">9 <ol class="_intro-list">
10 <li>Your local version of DevDocs won't self-update. Unless you're modifying the code,10 <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>.
12 <li>Run <code>thor docs:list</code> to see all available documentations.12 <li>Run <code>thor docs:list</code> to see all available documentations.
13 <li>Run <code>thor docs:download &lt;name&gt;</code> to download documentations.13 <li>Run <code>thor docs:download &lt;name&gt;</code> to download documentations.
14 <li>Run <code>thor docs:download --installed</code> to update all downloaded documentations.14 <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
15 <input type="checkbox" form="settings" name="layout" value="_sidebar-hidden"#{if settings['_sidebar-hidden'] then ' checked' else ''}>Automatically hide and show the sidebar15 <input type="checkbox" form="settings" name="layout" value="_sidebar-hidden"#{if settings['_sidebar-hidden'] then ' checked' else ''}>Automatically hide and show the sidebar
16 <small>Tip: drag the edge of the sidebar to resize it.</small>16 <small>Tip: drag the edge of the sidebar to resize it.</small>
17 </label>17 </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>
22 </div>18 </div>
23 </div>19 </div>
24 20
assets/javascripts/views/content/settings_page.coffee+0−7
@@ -14,7 +14,6 @@ class app.views.SettingsPage extends app.View · 13 unmodified lines
14 settings.dark = app.settings.get('dark')14 settings.dark = app.settings.get('dark')
15 settings.smoothScroll = !app.settings.get('fastScroll')15 settings.smoothScroll = !app.settings.get('fastScroll')
16 settings.arrowScroll = app.settings.get('arrowScroll')16 settings.arrowScroll = app.settings.get('arrowScroll')
17 settings.bypassCache = app.settings.get('bypassCache')
18 settings[layout] = app.settings.hasLayout(layout) for layout in app.settings.LAYOUTS17 settings[layout] = app.settings.hasLayout(layout) for layout in app.settings.LAYOUTS
19 settings18 settings
20 19
@@ -33,10 +32,6 @@ class app.views.SettingsPage extends app.View · 12 unmodified lines
33 app.settings.set('fastScroll', !enable)32 app.settings.set('fastScroll', !enable)
34 return33 return
35 34
36 toggleBypassCache: (enable) ->
37 app.settings.setBypassCache(!!enable)
38 return
39
40 toggle: (name, enable) ->35 toggle: (name, enable) ->
41 app.settings.set(name, enable)36 app.settings.set(name, enable)
42 return37 return
@@ -80,8 +75,6 @@ class app.views.SettingsPage extends app.View · 37 unmodified lines
80 @toggleSmoothScroll input.checked75 @toggleSmoothScroll input.checked
81 when 'import'76 when 'import'
82 @import input.files[0], input77 @import input.files[0], input
83 when 'bypassCache'
84 @toggleBypassCache input.checked
85 else78 else
86 @toggle input.name, input.checked79 @toggle input.name, input.checked
87 return80 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
2 2
3**Note:** please read the [contributing guidelines](../.github/CONTRIBUTING.md) before submitting a new documentation.3**Note:** please read the [contributing guidelines](../.github/CONTRIBUTING.md) before submitting a new documentation.
4 4
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
71. 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`)51. 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`)
82. Add the appropriate class attributes and filter options (see the [Scraper Reference](./scraper-reference.md) page).62. Add the appropriate class attributes and filter options (see the [Scraper Reference](./scraper-reference.md) page).
93. Check that the scraper is listed in `thor docs:list`.73. 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
205 ].compact205 ].compact
206 end206 end
207 207
208 def bypass_cache?208 def service_worker_cache_name
209 !memoized_cookies['bypassCache'].nil?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
210 end230 end
211 231
212 def redirect_via_js(path)232 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 %>1<%# The name of the cache to store responses in %>
2<%# This ensures that the cache is always updated if the hash of the application.js file changes %>2<%# If the cache name changes DevDocs is assumed to be updated %>
3const cacheName = '<%= javascript_path('application', asset_host: false).scan(/application-([^\.]+)\.js/).last&.first || 'app' %>';3const cacheName = '<%= service_worker_cache_name %>';
4 4
5<%# Url's to cache when the service worker is installed %>5<%# Url's to cache when the service worker is installed %>
6const urlsToCache = [6const urlsToCache = [
@@ -32,9 +32,6 @@ self.addEventListener('activate', event => { · 25 unmodified lines
32<%# Handle HTTP requests %>32<%# Handle HTTP requests %>
33self.addEventListener('fetch', event => {33self.addEventListener('fetch', event => {
34 event.respondWith((async () => {34 event.respondWith((async () => {
35 <% if bypass_cache? %>
36 return fetch(event.request);
37 <% else %>
38 const cachedResponse = await caches.match(event.request);35 const cachedResponse = await caches.match(event.request);
39 if (cachedResponse) return cachedResponse;36 if (cachedResponse) return cachedResponse;
40 37
@@ -53,6 +50,5 @@ self.addEventListener('fetch', event => { · 12 unmodified lines
53 50
54 throw err;51 throw err;
55 }52 }
56 <% end %>
57 })());53 })());
58});54});