diff --git a/docs/content/en/setup.md b/docs/content/en/setup.md
index cda2aeae..1388b53f 100644
--- a/docs/content/en/setup.md
+++ b/docs/content/en/setup.md
@@ -15,14 +15,14 @@ Add `@nuxtjs/pwa` dependency to your project:
```bash
- yarn add @nuxtjs/pwa
+ yarn add --dev @nuxtjs/pwa
```
```bash
- npm i @nuxtjs/pwa
+ npm i --dev @nuxtjs/pwa
```
@@ -32,12 +32,14 @@ Edit your `nuxt.config.js` file to add pwa module::
```js{}[nuxt.config.js]
{
- modules: [
+ buildModules: [
'@nuxtjs/pwa',
]
}
```
+**NOTE:** If using `ssr: false` with production mode without `nuxt generate`, you have to use `modules` instead of `buildModules`
+
### Add Icon
Ensure `static` dir exists and optionally create `static/icon.png`. (Recommended to be square png and >= `512x512px`)
diff --git a/lib/icon/module.js b/lib/icon/module.js
index 0570596a..9e2a0817 100755
--- a/lib/icon/module.js
+++ b/lib/icon/module.js
@@ -7,14 +7,10 @@ const { joinUrl, getRouteParams, sizeName } = require('../utils')
const { version } = require('../../package.json')
module.exports = function (pwa) {
- this.nuxt.hook('build:before', () => run.call(this, pwa, true))
-
- if (this.options.mode === 'spa' && !this.options.dev) {
- return run.call(this, pwa, false) // Fill meta
- }
+ this.nuxt.hook('build:before', () => run.call(this, pwa))
}
-async function run (pwa, _emitAssets) {
+async function run (pwa) {
const { publicPath } = getRouteParams(this.options)
// Defaults
@@ -92,9 +88,7 @@ async function run (pwa, _emitAssets) {
}
// Emit assets in background
- if (_emitAssets) {
- emitAssets.call(this, options)
- }
+ emitAssets.call(this, options)
}
async function findIcon (options) {
@@ -120,7 +114,7 @@ function addPlugin (options) {
if (options.plugin) {
this.addPlugin({
src: path.resolve(__dirname, './plugin.js'),
- fileName: 'nuxt-icons.js',
+ fileName: 'pwa/icons.js',
options: {
pluginName: options.pluginName,
icons
diff --git a/lib/manifest/module.js b/lib/manifest/module.js
index e073f35b..e6ba3611 100755
--- a/lib/manifest/module.js
+++ b/lib/manifest/module.js
@@ -1,17 +1,9 @@
const hash = require('hasha')
-const { joinUrl, getRouteParams, find } = require('../utils')
+const { joinUrl, getRouteParams } = require('../utils')
module.exports = function nuxtManifest (pwa) {
- const hook = () => {
- addManifest.call(this, pwa)
- }
-
- if (this.options.mode === 'spa') {
- return hook()
- }
-
- this.nuxt.hook('build:before', hook)
+ this.nuxt.hook('build:before', () => addManifest.call(this, pwa))
}
function addManifest (pwa) {
@@ -67,11 +59,9 @@ function addManifest (pwa) {
})
// Add manifest meta
- if (!find(this.options.head.link, 'rel', 'manifest')) {
- const baseAttribute = { rel: 'manifest', href: joinUrl(options.publicPath, manifestFileName) }
- const attribute = manifest.crossorigin ? Object.assign({}, baseAttribute, { crossorigin: manifest.crossorigin }) : baseAttribute
- this.options.head.link.push(attribute)
- } else {
- console.warn('Manifest meta already provided!') // eslint-disable-line no-console
+ const manifestMeta = { rel: 'manifest', href: joinUrl(options.publicPath, manifestFileName), hid: 'manifest' }
+ if (manifest.crossorigin) {
+ manifestMeta.crossorigin = manifest.crossorigin
}
+ pwa._manifestMeta = manifestMeta
}
diff --git a/lib/meta/meta.json b/lib/meta/meta.json
new file mode 100644
index 00000000..a55b0521
--- /dev/null
+++ b/lib/meta/meta.json
@@ -0,0 +1 @@
+<%= JSON.stringify(options.head, null, 2) %>
diff --git a/lib/meta/meta.merge.js b/lib/meta/meta.merge.js
new file mode 100644
index 00000000..c00d381f
--- /dev/null
+++ b/lib/meta/meta.merge.js
@@ -0,0 +1,36 @@
+exports.mergeMeta = function mergeMeta (to, from) {
+ if (typeof to === 'function') {
+ // eslint-disable-next-line no-console
+ console.warn('Cannot merge meta. Avoid using head as a function!')
+ return
+ }
+
+ for (const key in from) {
+ const value = from[key]
+ if (Array.isArray(value)) {
+ to[key] = to[key] || []
+ for (const item of value) {
+ // Avoid duplicates
+ if (
+ (item.hid && hasMeta(to[key], 'hid', item.hid)) ||
+ (item.name && hasMeta(to[key], 'name', item.name))
+ ) {
+ continue
+ }
+ // Add meta
+ to[key].push(item)
+ }
+ } else if (typeof value === 'object') {
+ to[key] = to[key] || {}
+ for (const attr in value) {
+ to[key][attr] = value[attr]
+ }
+ } else if (to[key] === undefined) {
+ to[key] = value
+ }
+ }
+}
+
+function hasMeta (arr, key, val) {
+ return arr.find(obj => val ? obj[key] === val : obj[key])
+}
diff --git a/lib/meta/module.js b/lib/meta/module.js
index 7f94b326..8646123f 100755
--- a/lib/meta/module.js
+++ b/lib/meta/module.js
@@ -1,20 +1,24 @@
-const { join } = require('path')
+const { join, resolve } = require('path')
const { existsSync } = require('fs')
-const { find, isUrl } = require('../utils')
+const { isUrl } = require('../utils')
+const { mergeMeta } = require('./meta.merge')
module.exports = function nuxtMeta (pwa) {
- const hook = () => {
- generateMeta.call(this, pwa)
- }
+ const { nuxt } = this
- if (this.options.mode === 'spa') {
- return hook()
- }
+ nuxt.hook('build:before', () => generateMeta.call(this, pwa))
- this.nuxt.hook('build:before', hook)
+ // SPA Support
+ if (nuxt.options.target === 'static') {
+ nuxt.hook('generate:extendRoutes', () => SPASupport.call(this, pwa))
+ } else if (!nuxt.options._build) {
+ SPASupport.call(this, pwa)
+ }
}
function generateMeta (pwa) {
+ const { nuxt } = this
+
// Defaults
const defaults = {
name: process.env.npm_package_name,
@@ -46,7 +50,9 @@ function generateMeta (pwa) {
// Default value for viewport
if (options.viewport === undefined) {
- options.viewport = options.nativeUI ? 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0, minimal-ui' : 'width=device-width, initial-scale=1'
+ options.viewport = options.nativeUI
+ ? 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0, minimal-ui'
+ : 'width=device-width, initial-scale=1'
}
// Default value for mobileAppIOS
@@ -54,29 +60,40 @@ function generateMeta (pwa) {
options.mobileAppIOS = !!options.nativeUI
}
+ const head = {
+ title: '',
+ meta: [],
+ link: [],
+ htmlAttrs: {}
+ }
+
// Charset
- if (options.charset && !find(this.options.head.meta, 'charset')) {
- this.options.head.meta.push({ hid: 'charset', charset: options.charset })
+ if (options.charset) {
+ head.meta.push({ hid: 'charset', charset: options.charset })
}
// Viewport
- if (options.viewport && !find(this.options.head.meta, 'name', 'viewport')) {
- this.options.head.meta.push({ hid: 'viewport', name: 'viewport', content: options.viewport })
+ if (options.viewport) {
+ head.meta.push({ hid: 'viewport', name: 'viewport', content: options.viewport })
}
// mobileApp
- if (options.mobileApp && !find(this.options.head.meta, 'name', 'mobile-web-app-capable')) {
- this.options.head.meta.push({ hid: 'mobile-web-app-capable', name: 'mobile-web-app-capable', content: 'yes' })
+ if (options.mobileApp) {
+ head.meta.push({ hid: 'mobile-web-app-capable', name: 'mobile-web-app-capable', content: 'yes' })
}
// mobileApp (IOS)
- if (options.mobileAppIOS && !find(this.options.head.meta, 'name', 'apple-mobile-web-app-capable')) {
- this.options.head.meta.push({ hid: 'apple-mobile-web-app-capable', name: 'apple-mobile-web-app-capable', content: 'yes' })
+ if (options.mobileAppIOS) {
+ head.meta.push({ hid: 'apple-mobile-web-app-capable', name: 'apple-mobile-web-app-capable', content: 'yes' })
}
// statusBarStyle (IOS)
- if (options.mobileAppIOS && options.appleStatusBarStyle && !find(this.options.head.meta, 'name', 'apple-mobile-web-app-status-bar-style')) {
- this.options.head.meta.push({ hid: 'apple-mobile-web-app-status-bar-style', name: 'apple-mobile-web-app-status-bar-style', content: options.appleStatusBarStyle })
+ if (options.mobileAppIOS && options.appleStatusBarStyle) {
+ head.meta.push({
+ hid: 'apple-mobile-web-app-status-bar-style',
+ name: 'apple-mobile-web-app-status-bar-style',
+ content: options.appleStatusBarStyle
+ })
}
// Icons
@@ -84,105 +101,106 @@ function generateMeta (pwa) {
const iconSmall = options.icons[0]
const iconBig = options.icons[options.icons.length - 1]
- if (!find(this.options.head.link, 'rel', 'shortcut icon')) {
- this.options.head.link.push({ rel: 'shortcut icon', href: iconSmall.src })
- }
-
- if (!find(this.options.head.link, 'rel', 'apple-touch-icon')) {
- this.options.head.link.push({ rel: 'apple-touch-icon', href: iconBig.src, sizes: iconBig.sizes })
- }
+ // Shortcut icon
+ head.link.push({ rel: 'shortcut icon', href: iconSmall.src })
+ head.link.push({ rel: 'apple-touch-icon', href: iconBig.src, sizes: iconBig.sizes })
// Launch Screen Image (IOS)
- if (options.mobileAppIOS && pwa._iosSplash && !find(this.options.head.link, 'rel', 'apple-touch-startup-image')) {
- this.options.head.link.push({ href: pwa._iosSplash.iphonese, media: '(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)', rel: 'apple-touch-startup-image' })
- this.options.head.link.push({ href: pwa._iosSplash.iphone6, media: '(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)', rel: 'apple-touch-startup-image' })
- this.options.head.link.push({ href: pwa._iosSplash.iphoneplus, media: '(device-width: 621px) and (device-height: 1104px) and (-webkit-device-pixel-ratio: 3)', rel: 'apple-touch-startup-image' })
- this.options.head.link.push({ href: pwa._iosSplash.iphonex, media: '(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3)', rel: 'apple-touch-startup-image' })
- this.options.head.link.push({ href: pwa._iosSplash.iphonexr, media: '(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2)', rel: 'apple-touch-startup-image' })
- this.options.head.link.push({ href: pwa._iosSplash.iphonexsmax, media: '(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3)', rel: 'apple-touch-startup-image' })
- this.options.head.link.push({ href: pwa._iosSplash.ipad, media: '(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2)', rel: 'apple-touch-startup-image' })
- this.options.head.link.push({ href: pwa._iosSplash.ipadpro1, media: '(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2)', rel: 'apple-touch-startup-image' })
- this.options.head.link.push({ href: pwa._iosSplash.ipadpro2, media: '(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2)', rel: 'apple-touch-startup-image' })
- this.options.head.link.push({ href: pwa._iosSplash.ipadpro3, media: '(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2)', rel: 'apple-touch-startup-image' })
+ if (options.mobileAppIOS && pwa._iosSplash) {
+ const splashes = [
+ ['iphonese', '(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)'],
+ ['iphone6', '(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)'],
+ ['iphoneplus', '(device-width: 621px) and (device-height: 1104px) and (-webkit-device-pixel-ratio: 3)'],
+ ['iphonex', '(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3)'],
+ ['iphonexr', '(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2)'],
+ ['iphonexsmax', '(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3)'],
+ ['ipad', '(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2)'],
+ ['ipadpro1', '(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2)'],
+ ['ipadpro2', '(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2)'],
+ ['ipadpro3', '(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2)']
+ ]
+
+ for (const [type, media] of splashes) {
+ head.link.push({
+ href: pwa._iosSplash[type],
+ media,
+ rel: 'apple-touch-startup-image',
+ hid: 'apple-touch-startup-image-' + type
+ })
+ }
}
}
- const favicon = join(this.options.srcDir, this.options.dir.static, 'favicon.ico')
- if (options.favicon && !find(this.options.head.link, 'rel', 'shortcut icon') && existsSync(favicon)) {
+ // Favicon.ico as fallback
+ const favicon = join(nuxt.options.srcDir, nuxt.options.dir.static, 'favicon.ico')
+ if (options.favicon && existsSync(favicon)) {
// eslint-disable-next-line no-console
- console.warn('You are using a low quality icon, use icon png. See https://pwa.nuxtjs.org/icon/')
-
- this.options.head.link.push({ rel: 'shortcut icon', href: this.options.router.base + 'favicon.ico' })
+ console.warn('You are using a low quality icon, use icon png. See https://pwa.nuxtjs.org/icon')
+ head.link.push({ rel: 'shortcut icon', href: nuxt.options.router.base + 'favicon.ico' })
}
// Title
- if (options.name && !this.options.head.title && typeof this.options.head.titleTemplate !== 'function') {
- this.options.head.title = options.name
- }
-
- // IOS launch icon title
- const title = options.name || this.options.head.title || false
- if (title && !find(this.options.head.meta, 'name', 'apple-mobile-web-app-title')) {
- this.options.head.meta.push({ hid: 'apple-mobile-web-app-title', name: 'apple-mobile-web-app-title', content: title })
+ const title = options.name || options.title
+ if (title) {
+ head.title = options.name
+ // IOS launch icon title
+ head.meta.push({ hid: 'apple-mobile-web-app-title', name: 'apple-mobile-web-app-title', content: title })
}
// Author
- if (options.author && !find(this.options.head.meta, 'name', 'author')) {
- this.options.head.meta.push({ hid: 'author', name: 'author', content: options.author })
+ if (options.author) {
+ head.meta.push({ hid: 'author', name: 'author', content: options.author })
}
// description meta
- if (options.description && !find(this.options.head.meta, 'name', 'description')) {
- this.options.head.meta.push({ hid: 'description', name: 'description', content: options.description })
+ if (options.description) {
+ head.meta.push({ hid: 'description', name: 'description', content: options.description })
}
// theme-color meta
- if (options.theme_color && !find(this.options.head.meta, 'name', 'theme-color')) {
- this.options.head.meta.push({ hid: 'theme-color', name: 'theme-color', content: options.theme_color })
+ if (options.theme_color) {
+ head.meta.push({ hid: 'theme-color', name: 'theme-color', content: options.theme_color })
}
// Add lang to html tag
- if (options.lang && !(this.options.head.htmlAttrs && this.options.head.htmlAttrs.lang)) {
- if (!this.options.head.htmlAttrs) {
- this.options.head.htmlAttrs = {}
- }
- this.options.head.htmlAttrs.lang = options.lang
+ if (options.lang) {
+ head.htmlAttrs.lang = options.lang
}
// og:type
- if (options.ogType && !find(this.options.head.meta, 'property', 'og:type') && !find(this.options.head.meta, 'name', 'og:type')) {
- this.options.head.meta.push({ hid: 'og:type', name: 'og:type', property: 'og:type', content: options.ogType })
+ if (options.ogType) {
+ head.meta.push({ hid: 'og:type', name: 'og:type', property: 'og:type', content: options.ogType })
}
// og:title
if (options.ogTitle === true) {
options.ogTitle = options.name
}
- if (options.ogTitle && !find(this.options.head.meta, 'property', 'og:title') && !find(this.options.head.meta, 'name', 'og:title')) {
- this.options.head.meta.push({ hid: 'og:title', name: 'og:title', property: 'og:title', content: options.ogTitle })
+ if (options.ogTitle) {
+ head.meta.push({ hid: 'og:title', name: 'og:title', property: 'og:title', content: options.ogTitle })
}
// og:site_name
if (options.ogSiteName === true) {
options.ogSiteName = options.name
}
- if (options.ogSiteName && !find(this.options.head.meta, 'property', 'og:site_name') && !find(this.options.head.meta, 'name', 'og:site_name')) {
- this.options.head.meta.push({ hid: 'og:site_name', name: 'og:site_name', property: 'og:site_name', content: options.ogSiteName })
+ if (options.ogSiteName) {
+ head.meta.push({ hid: 'og:site_name', name: 'og:site_name', property: 'og:site_name', content: options.ogSiteName })
}
// og:description
if (options.ogDescription === true) {
options.ogDescription = options.description
}
- if (options.ogDescription && !find(this.options.head.meta, 'property', 'og:description') && !find(this.options.head.meta, 'name', 'og:description')) {
- this.options.head.meta.push({ hid: 'og:description', name: 'og:description', property: 'og:description', content: options.ogDescription })
+ if (options.ogDescription) {
+ head.meta.push({ hid: 'og:description', name: 'og:description', property: 'og:description', content: options.ogDescription })
}
// og:url
if (options.ogHost && options.ogUrl === true) {
options.ogUrl = options.ogHost
}
- if (options.ogUrl && options.ogUrl !== true && !find(this.options.head.meta, 'property', 'og:url') && !find(this.options.head.meta, 'name', 'og:url')) {
- this.options.head.meta.push({ hid: 'og:url', name: 'og:url', property: 'og:url', content: options.ogUrl })
+ if (options.ogUrl && options.ogUrl !== true) {
+ head.meta.push({ hid: 'og:url', name: 'og:url', property: 'og:url', content: options.ogUrl })
}
// og:image
@@ -197,22 +215,22 @@ function generateMeta (pwa) {
} else if (typeof options.ogImage === 'string') {
options.ogImage = { path: options.ogImage }
}
- if (options.ogImage && !find(this.options.head.meta, 'property', 'og:image') && !find(this.options.head.meta, 'name', 'og:image')) {
+ if (options.ogImage) {
if (options.ogHost || isUrl(options.ogImage.path)) {
- this.options.head.meta.push({
+ head.meta.push({
hid: 'og:image',
name: 'og:image',
property: 'og:image',
content: isUrl(options.ogImage.path) ? options.ogImage.path : options.ogHost + options.ogImage.path
})
if (options.ogImage.width && options.ogImage.height) {
- this.options.head.meta.push({
+ head.meta.push({
hid: 'og:image:width',
name: 'og:image:width',
property: 'og:image:width',
content: options.ogImage.width
})
- this.options.head.meta.push({
+ head.meta.push({
hid: 'og:image:height',
name: 'og:image:height',
property: 'og:image:height',
@@ -220,7 +238,7 @@ function generateMeta (pwa) {
})
}
if (options.ogImage.type) {
- this.options.head.meta.push({
+ head.meta.push({
hid: 'og:image:type',
name: 'og:image:type',
property: 'og:image:type',
@@ -231,17 +249,53 @@ function generateMeta (pwa) {
}
// twitter:card
- if (options.twitterCard && !find(this.options.head.meta, 'property', 'twitter:card') && !find(this.options.head.meta, 'name', 'twitter:card')) {
- this.options.head.meta.push({ hid: 'twitter:card', name: 'twitter:card', property: 'twitter:card', content: options.twitterCard })
+ if (options.twitterCard) {
+ head.meta.push({ hid: 'twitter:card', name: 'twitter:card', property: 'twitter:card', content: options.twitterCard })
}
// twitter:site
- if (options.twitterSite && !find(this.options.head.meta, 'property', 'twitter:site') && !find(this.options.head.meta, 'name', 'twitter:site')) {
- this.options.head.meta.push({ hid: 'twitter:site', name: 'twitter:site', property: 'twitter:site', content: options.twitterSite })
+ if (options.twitterSite) {
+ head.meta.push({ hid: 'twitter:site', name: 'twitter:site', property: 'twitter:site', content: options.twitterSite })
}
// twitter:creator
- if (options.twitterCreator && !find(this.options.head.meta, 'property', 'twitter:creator') && !find(this.options.head.meta, 'name', 'twitter:creator')) {
- this.options.head.meta.push({ hid: 'twitter:creator', name: 'twitter:creator', property: 'twitter:creator', content: options.twitterCreator })
+ if (options.twitterCreator) {
+ head.meta.push({ hid: 'twitter:creator', name: 'twitter:creator', property: 'twitter:creator', content: options.twitterCreator })
+ }
+
+ // manifest meta
+ if (pwa._manifestMeta) {
+ head.link.push(pwa._manifestMeta)
+ }
+
+ this.addPlugin({
+ src: resolve(__dirname, './plugin.js'),
+ fileName: 'pwa/meta.js',
+ options: {}
+ })
+
+ this.addTemplate({
+ src: resolve(__dirname, 'meta.json'),
+ fileName: 'pwa/meta.json',
+ options: { head }
+ })
+
+ this.addTemplate({
+ src: resolve(__dirname, 'meta.merge.js'),
+ fileName: 'pwa/meta.merge.js',
+ options: { head }
+ })
+}
+
+function SPASupport (_pwa) {
+ const { nuxt } = this
+ const metaJSON = resolve(nuxt.options.buildDir, 'pwa/meta.json')
+ if (existsSync(metaJSON)) {
+ // eslint-disable-next-line no-console
+ console.log('[PWA] Loading meta from ' + metaJSON)
+ mergeMeta(nuxt.options.head, require(metaJSON))
+ } else {
+ // eslint-disable-next-line no-console
+ console.warn('[PWA] Cannot load meta from ' + metaJSON)
}
}
diff --git a/lib/meta/plugin.js b/lib/meta/plugin.js
new file mode 100644
index 00000000..1d97fe3b
--- /dev/null
+++ b/lib/meta/plugin.js
@@ -0,0 +1,6 @@
+import meta from './meta.json'
+import { mergeMeta } from './meta.merge'
+
+export default function ({ app }) {
+ mergeMeta(app.head, meta)
+}
diff --git a/lib/utils/index.js b/lib/utils/index.js
index 093a0969..a169a8e0 100755
--- a/lib/utils/index.js
+++ b/lib/utils/index.js
@@ -1,9 +1,5 @@
const path = require('path').posix
-function find (arr, key, val) {
- return arr.find(obj => val ? obj[key] === val : obj[key])
-}
-
function isUrl (url) {
return url.indexOf('http') === 0 || url.indexOf('//') === 0
}
@@ -53,7 +49,6 @@ function startCase (str) {
}
module.exports = {
- find,
isUrl,
joinUrl,
getRouteParams,
diff --git a/test/__snapshots__/pwa.test.js.snap b/test/__snapshots__/pwa.test.js.snap
index 805781fb..c249c9f4 100644
--- a/test/__snapshots__/pwa.test.js.snap
+++ b/test/__snapshots__/pwa.test.js.snap
@@ -35,6 +35,7 @@ Array [
"fixture/.nuxt/dist/server/pages",
"fixture/.nuxt/loading.html",
"fixture/.nuxt/mixins",
+ "fixture/.nuxt/pwa",
"fixture/.nuxt/views",
"fixture/.nuxt/views/app.template.html",
"fixture/.nuxt/views/error.html",
diff --git a/test/fixture/nuxt.config.js b/test/fixture/nuxt.config.js
index e59657ed..6ba8d51b 100644
--- a/test/fixture/nuxt.config.js
+++ b/test/fixture/nuxt.config.js
@@ -2,7 +2,7 @@ module.exports = {
dev: false,
rootDir: __dirname,
- modules: [
+ buildModules: [
{ handler: require('../../') }
],