Skip to content

Commit

Permalink
feat(workbox): workbox 3 + offlinePage (#60)
Browse files Browse the repository at this point in the history
Co-authored-by: manniL <hello@lichter.io>
Co-authored-by: galvez <jonasgalvez@gmail.com>"
  • Loading branch information
2 people authored and pi0 committed Aug 24, 2018
1 parent 6d241ec commit 0fef874
Show file tree
Hide file tree
Showing 7 changed files with 2,359 additions and 1,392 deletions.
6 changes: 6 additions & 0 deletions docs/modules/workbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ workbox: {

**importScripts** (Array) - Additional scripts to be imported in service worker script. (Relative to `/`. Can be placed in `assets/` directory)

**offlinePage** (String) - Enables routing all offline requests to the specified path. (Example: `/offline`)

**cachingExtensions** (String) - Loads and inserts the contents of the specified file path into the service worker script, below autogenerated calls to `workbox.precaching.*`. You may add as many extra calls as you want to this file.

**routingExtensions** (String) - Loads and inserts the contents of the specified file path into the service worker script, below autogenerated calls to `workbox.routing.*`. You may add as many extra calls as you want to this file.

For list of all available options see [here](https://developers.google.com/web/tools/workbox/modules/workbox-build)

### Adding custom runtimeCaching items (For CDN)
Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,18 @@
"axios": "^0.18.0",
"babel-eslint": "^8.1.2",
"codecov": "^3.0.0",
"eslint": "^4.14.0",
"eslint": "^4.19.1",
"eslint-config-standard": "^11.0.0",
"eslint-plugin-html": "^4.0.1",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-jest": "^21.5.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-jest": "^21.21.0",
"eslint-plugin-node": "^6.0.1",
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-standard": "^3.0.1",
"eslint-plugin-promise": "^3.8.0",
"eslint-plugin-standard": "^3.1.0",
"jest": "^22.0.4",
"jsdom": "^11.5.1",
"lerna": "^3.0.0-alpha.1",
"nuxt": "^1.3.0",
"standard-version": "^4.2.0"
"standard-version": "^4.4.0"
}
}
2 changes: 1 addition & 1 deletion packages/meta/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ function generateMeta (_options) {
}

// Title
if (options.name && !this.options.head.title && typeof (this.options.head.titleTemplate) !== 'function') {
if (options.name && !this.options.head.title && typeof this.options.head.titleTemplate !== 'function') {
this.options.head.title = options.name
}

Expand Down
49 changes: 38 additions & 11 deletions packages/workbox/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const path = require('path')
const swBuild = require('workbox-build')
const { readFileSync, writeFileSync } = require('fs')
const { readFileSync, writeFileSync, existsSync } = require('fs')
const hashSum = require('hash-sum')
const debug = require('debug')('nuxt:pwa')
const { defaultsDeep } = require('lodash')
const { defaultsDeep, pick } = require('lodash')

const fixUrl = url => url.replace(/\/\//g, '/').replace(':/', '://')
const isUrl = url => url.indexOf('http') === 0 || url.indexOf('//') === 0
Expand Down Expand Up @@ -33,6 +33,16 @@ module.exports = function nuxtWorkbox (moduleOptions) {
// getRouterBase
// =============================================

function loadScriptExtension (scriptExtension) {
if (scriptExtension) {
const extPath = this.nuxt.resolveAlias(scriptExtension)
if (existsSync(extPath)) {
return readFileSync(extPath, 'utf8')
}
return null
}
}

function getOptions (moduleOptions) {
// Router Base
const routerBase = this.options.router.base
Expand All @@ -51,6 +61,8 @@ function getOptions (moduleOptions) {
swSrc: path.resolve(this.options.buildDir, 'sw.template.js'),
swDest: path.resolve(this.options.srcDir, this.options.dir.static || 'static', 'sw.js'),
directoryIndex: '/',
cachingExtensions: null,
routingExtensions: null,
cacheId: process.env.npm_package_name || 'nuxt',
clientsClaim: true,
globPatterns: ['**/*.{js,css}'],
Expand All @@ -59,6 +71,7 @@ function getOptions (moduleOptions) {
'': fixUrl(publicPath)
},
offline: true,
offlinePage: null,
_runtimeCaching: [
// Cache all _nuxt resources at runtime
// They are hashed by webpack so are safe to loaded by cacheFirst handler
Expand All @@ -73,13 +86,21 @@ function getOptions (moduleOptions) {
const options = defaultsDeep({}, this.options.workbox, moduleOptions, defaults)

// Optionally cache other routes for offline
if (options.offline) {
defaults._runtimeCaching.push({
urlPattern: fixUrl(routerBase + '/.*'),
if (options.offline && !options.offlinePage) {
options._runtimeCaching.push({
urlPattern: fixUrl(`${routerBase}/.*`),
handler: 'networkFirst'
})
}

if (options.cachingExtensions) {
options.cachingExtensions = loadScriptExtension.call(this, options.cachingExtensions)
}

if (options.routingExtensions) {
options.routingExtensions = loadScriptExtension.call(this, options.routingExtensions)
}

return options
}

Expand All @@ -93,16 +114,20 @@ function addTemplates (options) {
src: path.resolve(__dirname, 'templates/sw.template.js'),
fileName: 'sw.template.js',
options: {
offlinePage: options.offlinePage,
cachingExtensions: options.cachingExtensions,
routingExtensions: options.routingExtensions,
importScripts: [options.wbDst].concat(options.importScripts || []),
runtimeCaching: [].concat(options._runtimeCaching, options.runtimeCaching).map(i => (Object.assign({}, i, {
urlPattern: i.urlPattern,
handler: i.handler || 'networkFirst',
method: i.method || 'GET'
}))),
clientsClaim: options.clientsClaim,
wbOptions: {
cacheId: options.cacheId,
clientsClaim: options.clientsClaim,
directoryIndex: options.directoryIndex
directoryIndex: options.directoryIndex,
cleanUrls: false
}
}
})
Expand Down Expand Up @@ -132,13 +157,13 @@ function emitAssets (options) {
const source = readFileSync(path)
const hash = hashSum(source)
const dst = `${name}.${hash}.${ext}`
assets.push({source, dst})
assets.push({ source, dst })
return dst
}

// Write assets after build
const hook = builder => {
assets.forEach(({source, dst}) => {
assets.forEach(({ source, dst }) => {
writeFileSync(path.resolve(this.options.buildDir, 'dist', dst), source, 'utf-8')
})
}
Expand All @@ -165,8 +190,10 @@ function emitAssets (options) {

function workboxInject (options) {
const hook = () => {
const opts = Object.assign({}, options)
delete opts.runtimeCaching
const opts = pick(options, [
'swDest', 'swSrc', 'globDirectory', 'globFollow', 'globIgnores', 'globPatterns', 'dontCacheBustUrlsMatching',
'globStrict', 'templatedUrls', 'maximumFileSizeToCacheInBytes', 'modifyUrlPrefix', 'manifestTransforms'
])
return swBuild.injectManifest(opts)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/workbox/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
"access": "public"
},
"dependencies": {
"workbox-build": "^2.1.2"
"workbox-build": "^3.4.1"
}
}
25 changes: 19 additions & 6 deletions packages/workbox/templates/sw.template.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
importScripts(<%= options.importScripts.map(i => `'${i}'`).join(', ') %>)
importScripts(<%= options.importScripts.map((i) => `'${i}'`).join(', ') %>)

const workboxSW = new self.WorkboxSW(<%= JSON.stringify(options.wbOptions, null, 2) %>)
workbox.precaching.precacheAndRoute([], <%= JSON.stringify(options.wbOptions, null, 2) %>)

workboxSW.precache([])
<% if (options.offlinePage) { %>workbox.precaching.precacheAndRoute(['<%= options.offlinePage %>'])<% } %>
<% if (options.cachingExtensions) { %><%= options.cachingExtensions %><% } %>
<% if (options.clientsClaim) { %>workbox.clientsClaim()<% } %>

<% options.runtimeCaching.forEach(r => {
<%
options.runtimeCaching.forEach(r => {
const strategy = JSON.stringify(r.strategyOptions || {})
%>
workboxSW.router.registerRoute(new RegExp('<%= r.urlPattern %>'), workboxSW.strategies.<%= r.handler %>(<%= strategy %>), '<%= r.method %>')
%>
workbox.routing.registerRoute(new RegExp('<%= r.urlPattern %>'), workbox.strategies.<%= r.handler %>(<%= strategy %>), '<%= r.method %>')
<% }) %>

<% if (options.offlinePage) { %>
// offlinePage support
const strategy = workbox.strategies.staleWhileRevalidate()
workbox.routing.registerRoute(new RegExp('/.*'), ({event}) => {
return strategy.handle({event})
.catch(() => caches.match('<%= options.offlinePage %>')
})<% } %>

<% if (options.routingExtensions) { %><%= options.routingExtensions %><% } %>

0 comments on commit 0fef874

Please sign in to comment.