Make service worker opt-in in development

pull/1022/head
Jasper van Merle 6 years ago
parent 0cd1527143
commit 576f32dae1

@ -1,6 +1,7 @@
FROM ruby:2.6.0 FROM ruby:2.6.0
ENV LANG=C.UTF-8 ENV LANG=C.UTF-8
ENV ENABLE_SERVICE_WORKER=true
WORKDIR /devdocs WORKDIR /devdocs

@ -1,6 +1,7 @@
FROM ruby:2.6.0-alpine FROM ruby:2.6.0-alpine
ENV LANG=C.UTF-8 ENV LANG=C.UTF-8
ENV ENABLE_SERVICE_WORKER=true
WORKDIR /devdocs WORKDIR /devdocs

@ -14,3 +14,4 @@ app.config =
release: <%= Time.now.utc.httpdate.to_json %> release: <%= Time.now.utc.httpdate.to_json %>
mathml_stylesheet: '<%= App.cdn_origin %>/mathml.css' mathml_stylesheet: '<%= App.cdn_origin %>/mathml.css'
service_worker_path: '/service-worker.js' service_worker_path: '/service-worker.js'
service_worker_enabled: <%= App.environment == 'production' || !ENV["ENABLE_SERVICE_WORKER"].nil? %>

@ -2,7 +2,7 @@ class app.ServiceWorker
$.extend @prototype, Events $.extend @prototype, Events
@isEnabled: -> @isEnabled: ->
!!navigator.serviceWorker !!navigator.serviceWorker and app.config.service_worker_enabled
constructor: -> constructor: ->
@registration = null @registration = null

@ -5,7 +5,6 @@ class app.Settings
'manualUpdate' 'manualUpdate'
'fastScroll' 'fastScroll'
'arrowScroll' 'arrowScroll'
'bypassCache'
'docs' 'docs'
'dark' 'dark'
'layout' 'layout'
@ -92,11 +91,6 @@ class app.Settings
@set 'size', value @set 'size', value
return return
setBypassCache: (value) ->
@set 'bypassCache', value
app.serviceWorker?.updateInBackground()
return
dump: -> dump: ->
@store.dump() @store.dump()

@ -44,7 +44,12 @@ canICloseTheTab = ->
if app.ServiceWorker.isEnabled() if app.ServiceWorker.isEnabled()
""" 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). """ """ 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). """
else else
""" 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> 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 <a href="//devdocs.io">devdocs.io</a> offline won't work.<br>
The current tab will continue to function even when you go offline (provided you installed all the documentations beforehand). """ The current tab will continue to function even when you go offline (provided you installed all the documentations beforehand). """
app.templates.offlineDoc = (doc, status) -> app.templates.offlineDoc = (doc, status) ->

@ -8,7 +8,7 @@ app.templates.intro = """
<p>Thanks for downloading DevDocs. Here are a few things you should know: <p>Thanks for downloading DevDocs. Here are a few things you should know:
<ol class="_intro-list"> <ol class="_intro-list">
<li>Your local version of DevDocs won't self-update. Unless you're modifying the code, <li>Your local version of DevDocs won't self-update. Unless you're modifying the code,
I&nbsp;recommend using the hosted version at <a href="https://devdocs.io">devdocs.io</a>. we&nbsp;recommend using the hosted version at <a href="https://devdocs.io">devdocs.io</a>.
<li>Run <code>thor docs:list</code> to see all available documentations. <li>Run <code>thor docs:list</code> to see all available documentations.
<li>Run <code>thor docs:download &lt;name&gt;</code> to download documentations. <li>Run <code>thor docs:download &lt;name&gt;</code> to download documentations.
<li>Run <code>thor docs:download --installed</code> to update all downloaded documentations. <li>Run <code>thor docs:download --installed</code> to update all downloaded documentations.

@ -15,10 +15,6 @@ app.templates.settingsPage = (settings) -> """
<input type="checkbox" form="settings" name="layout" value="_sidebar-hidden"#{if settings['_sidebar-hidden'] then ' checked' else ''}>Automatically hide and show the sidebar <input type="checkbox" form="settings" name="layout" value="_sidebar-hidden"#{if settings['_sidebar-hidden'] then ' checked' else ''}>Automatically hide and show the sidebar
<small>Tip: drag the edge of the sidebar to resize it.</small> <small>Tip: drag the edge of the sidebar to resize it.</small>
</label> </label>
<label class="_settings-label">
<input type="checkbox" form="settings" name="bypassCache" value="1"#{if settings.bypassCache then ' checked' else ''}>Bypass Service Worker cache
<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>
</label>
</div> </div>
</div> </div>

@ -14,7 +14,6 @@ class app.views.SettingsPage extends app.View
settings.dark = app.settings.get('dark') settings.dark = app.settings.get('dark')
settings.smoothScroll = !app.settings.get('fastScroll') settings.smoothScroll = !app.settings.get('fastScroll')
settings.arrowScroll = app.settings.get('arrowScroll') 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[layout] = app.settings.hasLayout(layout) for layout in app.settings.LAYOUTS
settings settings
@ -33,10 +32,6 @@ class app.views.SettingsPage extends app.View
app.settings.set('fastScroll', !enable) app.settings.set('fastScroll', !enable)
return return
toggleBypassCache: (enable) ->
app.settings.setBypassCache(!!enable)
return
toggle: (name, enable) -> toggle: (name, enable) ->
app.settings.set(name, enable) app.settings.set(name, enable)
return return
@ -80,8 +75,6 @@ class app.views.SettingsPage extends app.View
@toggleSmoothScroll input.checked @toggleSmoothScroll input.checked
when 'import' when 'import'
@import input.files[0], input @import input.files[0], input
when 'bypassCache'
@toggleBypassCache input.checked
else else
@toggle input.name, input.checked @toggle input.name, input.checked
return return

@ -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:** 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`) 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). 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`. 3. Check that the scraper is listed in `thor docs:list`.

@ -205,8 +205,28 @@ class App < Sinatra::Application
].compact ].compact
end end
def bypass_cache? def service_worker_cache_name
!memoized_cookies['bypassCache'].nil? # 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 end
def redirect_via_js(path) def redirect_via_js(path)

@ -1,6 +1,6 @@
<%# Use the hash of the application.js file as cache name or 'app' if not running in production %> <%# The name of the cache to store responses in %>
<%# This ensures that the cache is always updated if the hash of the application.js file changes %> <%# If the cache name changes DevDocs is assumed to be updated %>
const cacheName = '<%= javascript_path('application', asset_host: false).scan(/application-([^\.]+)\.js/).last&.first || 'app' %>'; const cacheName = '<%= service_worker_cache_name %>';
<%# Url's to cache when the service worker is installed %> <%# Url's to cache when the service worker is installed %>
const urlsToCache = [ const urlsToCache = [
@ -32,9 +32,6 @@ self.addEventListener('activate', event => {
<%# Handle HTTP requests %> <%# Handle HTTP requests %>
self.addEventListener('fetch', event => { self.addEventListener('fetch', event => {
event.respondWith((async () => { event.respondWith((async () => {
<% if bypass_cache? %>
return fetch(event.request);
<% else %>
const cachedResponse = await caches.match(event.request); const cachedResponse = await caches.match(event.request);
if (cachedResponse) return cachedResponse; if (cachedResponse) return cachedResponse;
@ -53,6 +50,5 @@ self.addEventListener('fetch', event => {
throw err; throw err;
} }
<% end %>
})()); })());
}); });

Loading…
Cancel
Save