-
Notifications
You must be signed in to change notification settings - Fork 174
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(workbox): rewrite with better template support
- Loading branch information
Pooya Parsa
committed
Nov 16, 2017
1 parent
3c7aa7d
commit b0af84e
Showing
3 changed files
with
116 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,149 @@ | ||
const path = require('path') | ||
const swBuild = require('workbox-build') | ||
const { readFileSync, writeFileSync } = require('fs') | ||
const hashSum = require('hash-sum') | ||
const debug = require('debug')('nuxt:pwa:workbox') | ||
|
||
const fixUrl = url => url.replace(/\/\//g, '/').replace(':/', '://') | ||
const isUrl = url => url.indexOf('http') === 0 || url.indexOf('//') === 0 | ||
|
||
module.exports = function nuxtWorkbox (options) { | ||
// ============================================= | ||
// workboxModule | ||
// ============================================= | ||
|
||
module.exports = function nuxtWorkbox (moduleOptions) { | ||
const options = Object.assign({}, moduleOptions, this.options.workbox) | ||
const ctx = { options } | ||
|
||
if (this.options.dev) { | ||
return | ||
} | ||
|
||
// routerBase and publicPath | ||
this.nuxt.plugin('build', builder => { | ||
debug('Adding workbox') | ||
getRouterBase.call(this, ctx) | ||
workboxInject.call(this, ctx) | ||
emitAssets.call(this, ctx) | ||
addTemplates.call(this, ctx) | ||
}) | ||
} | ||
|
||
// ============================================= | ||
// getRouterBase | ||
// ============================================= | ||
|
||
function getRouterBase (ctx) { | ||
const routerBase = this.options.router.base | ||
let publicPath = fixUrl(`${routerBase}/${this.options.build.publicPath}`) | ||
if (isUrl(this.options.build.publicPath)) { // CDN | ||
publicPath = this.options.build.publicPath | ||
if (publicPath.indexOf('//') === 0) { | ||
publicPath = '/' + publicPath // escape fixUrl | ||
publicPath = '/' + publicPath // Escape fixUrl | ||
} | ||
} | ||
|
||
const swFileName = 'sw.js' | ||
ctx.routerBase = routerBase | ||
ctx.publicPath = publicPath | ||
} | ||
|
||
// ============================================= | ||
// addTemplates | ||
// ============================================= | ||
|
||
function addTemplates (ctx) { | ||
// Add sw.template.js | ||
this.addTemplate({ | ||
src: path.resolve(__dirname, 'templates/sw.template.js'), | ||
fileName: 'sw.template.js', | ||
options: { | ||
importPath: ctx.wbDst, | ||
wb: ctx.workboxOptions | ||
} | ||
}) | ||
|
||
// Add sw.plugin.js | ||
const swURL = `${ctx.routerBase}/${ctx.options.swURL || 'sw.js'}` | ||
this.addPlugin({ | ||
src: path.resolve(__dirname, 'templates/sw.plugin.js'), | ||
ssr: false, | ||
fileName: 'sw.plugin.js', | ||
options: { | ||
swURL: fixUrl(swURL), | ||
swScope: fixUrl(`${ctx.routerBase}/`) | ||
} | ||
}) | ||
} | ||
|
||
// Use swBuild to generate sw file | ||
// We set dest to static dir that is served as / to allow global sw scope | ||
// ============================================= | ||
// emitAssets | ||
// ============================================= | ||
|
||
function emitAssets (ctx) { | ||
const assets = [] | ||
const emitAsset = (path, name, ext = 'js') => { | ||
const source = readFileSync(path) | ||
const hash = hashSum(source) | ||
const dst = `${name}.${hash}.${ext}` | ||
assets.push({source, dst}) | ||
return dst | ||
} | ||
|
||
// Write assets after build | ||
this.nuxt.plugin('build', builder => { | ||
builder.plugin('built', () => { | ||
assets.forEach(({source, dst}) => { | ||
writeFileSync(path.resolve(this.options.buildDir, 'dist', dst), source, 'utf-8') | ||
}) | ||
}) | ||
}) | ||
|
||
// workbox.js | ||
let wbPath = require.resolve('workbox-sw') | ||
if (ctx.options.dev) { | ||
wbPath = wbPath.replace(/prod/g, 'dev') | ||
} | ||
ctx.wbDst = fixUrl(ctx.publicPath + '/' + emitAsset(wbPath, 'workbox' + (ctx.options.dev ? '.dev' : ''))) | ||
} | ||
|
||
// ============================================= | ||
// workboxInject | ||
// ============================================= | ||
|
||
function workboxInject (ctx) { | ||
// https://workboxjs.org/reference-docs/latest/module-workbox-build.html#.generateSW | ||
const workboxOptions = Object.assign({ | ||
swDest: path.resolve(this.options.srcDir, 'static', swFileName), | ||
ctx.workboxOptions = Object.assign({ | ||
swSrc: path.resolve(this.options.buildDir, 'sw.template.js'), | ||
swDest: path.resolve(this.options.srcDir, 'static', 'sw.js'), | ||
directoryIndex: '/', | ||
cacheId: process.env.npm_package_name + '_' + process.env.npm_package_version, | ||
clientsClaim: true, | ||
globPatterns: ['**/*.{js,css}'], | ||
globDirectory: path.resolve(this.options.buildDir, 'dist'), | ||
modifyUrlPrefix: { | ||
'': fixUrl(publicPath) | ||
'': fixUrl(ctx.publicPath) | ||
}, | ||
runtimeCaching: [ | ||
// Cache routes if offline | ||
{ | ||
urlPattern: fixUrl(routerBase + '/**'), | ||
urlPattern: fixUrl(ctx.routerBase + '/**'), | ||
handler: 'networkFirst' | ||
}, | ||
// Cache other _nuxt resources runtime | ||
// They are hashed by webpack so are safe to loaded by cacheFirst handler | ||
{ | ||
urlPattern: fixUrl(publicPath + '/**'), | ||
urlPattern: fixUrl(ctx.publicPath + '/**'), | ||
handler: 'cacheFirst' | ||
} | ||
] | ||
}, options) | ||
}, ctx.options) | ||
|
||
// Use nuxt plugins to prevent race conditions with webpack plugin | ||
// (https://github.com/nuxt-community/modules/issues/110) | ||
this.nuxt.plugin('build', builder => { | ||
builder.plugin('built', () => { | ||
if (workboxOptions.swSrc) { | ||
return swBuild.injectManifest(workboxOptions) | ||
} else { | ||
return swBuild.generateSW(workboxOptions) | ||
} | ||
const opts = Object.assign({}, ctx.workboxOptions) | ||
delete opts.runtimeCaching | ||
return swBuild.injectManifest(opts) | ||
}) | ||
}) | ||
|
||
// Register runtime plugin | ||
const swURL = `${routerBase}/${options.swURL || swFileName}` | ||
this.addPlugin({ | ||
src: path.resolve(__dirname, 'plugin.js'), | ||
ssr: false, | ||
options: { | ||
swURL: fixUrl(swURL), | ||
swScope: fixUrl(`${routerBase}/`) | ||
} | ||
}) | ||
} | ||
|
||
module.exports.meta = require('./package.json') |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
importScripts('<%= options.importPath %>') | ||
|
||
const workboxSW = new self.WorkboxSW({ | ||
cacheId: '<%= options.wb.cacheId %>', | ||
clientsClaim: <%= options.wb.clientsClaim %>, | ||
directoryIndex: '<%= options.wb.directoryIndex %>' | ||
}) | ||
|
||
workboxSW.precache([]) | ||
|
||
<% options.wb.runtimeCaching.forEach(r => { %> | ||
workboxSW.router.registerRoute('<%= r.urlPattern %>', workboxSW.strategies.<%= r.handler %>({}), 'GET') | ||
<% }) %> |