elk/modules/pwa/index.ts

84 lines
3.1 KiB
TypeScript

import { defineNuxtModule } from '@nuxt/kit'
import type { VitePluginPWAAPI } from 'vite-plugin-pwa'
import { VitePWA } from 'vite-plugin-pwa'
import type { Plugin } from 'vite'
import type { VitePWANuxtOptions } from './types'
import { configurePWAOptions } from './config'
export * from './types'
export default defineNuxtModule<VitePWANuxtOptions>({
meta: {
name: 'pwa',
configKey: 'pwa',
},
defaults: nuxt => ({
base: nuxt.options.app.baseURL,
scope: nuxt.options.app.baseURL,
}),
async setup(options, nuxt) {
let vitePwaClientPlugin: Plugin | undefined
const resolveVitePluginPWAAPI = (): VitePluginPWAAPI | undefined => {
return vitePwaClientPlugin?.api
}
// TODO: combine with configurePWAOptions?
nuxt.hook('nitro:init', (nitro) => {
options.outDir = nitro.options.output.publicDir
options.injectManifest = options.injectManifest || {}
options.injectManifest.globDirectory = nitro.options.output.publicDir
})
nuxt.hook('vite:extend', ({ config }) => {
const plugin = config.plugins?.find(p => p && typeof p === 'object' && 'name' in p && p.name === 'vite-plugin-pwa')
if (plugin)
throw new Error('Remove vite-plugin-pwa plugin from Vite Plugins entry in Nuxt config file!')
})
nuxt.hook('vite:extendConfig', (viteInlineConfig, { isClient }) => {
viteInlineConfig.plugins = viteInlineConfig.plugins || []
const plugin = viteInlineConfig.plugins.find(p => p && typeof p === 'object' && 'name' in p && p.name === 'vite-plugin-pwa')
if (plugin)
throw new Error('Remove vite-plugin-pwa plugin from Vite Plugins entry in Nuxt config file!')
configurePWAOptions(options, nuxt)
const plugins = VitePWA(options)
viteInlineConfig.plugins.push(plugins)
if (isClient)
vitePwaClientPlugin = plugins.find(p => p.name === 'vite-plugin-pwa') as Plugin
})
if (nuxt.options.dev) {
const webManifest = `${nuxt.options.app.baseURL}${options.devOptions?.webManifestUrl ?? options.manifestFilename ?? 'manifest.webmanifest'}`
const devSw = `${nuxt.options.app.baseURL}dev-sw.js?dev-sw`
const workbox = `${nuxt.options.app.baseURL}workbox-`
// @ts-expect-error just ignore
const emptyHandle = (_req, _res, next) => {
next()
}
nuxt.hook('vite:serverCreated', (viteServer, { isServer }) => {
if (isServer)
return
viteServer.middlewares.stack.push({ route: webManifest, handle: emptyHandle })
viteServer.middlewares.stack.push({ route: devSw, handle: emptyHandle })
})
if (!options.strategies || options.strategies === 'generateSW') {
nuxt.hook('vite:serverCreated', (viteServer, { isServer }) => {
if (isServer)
return
viteServer.middlewares.stack.push({ route: workbox, handle: emptyHandle })
})
nuxt.hook('close', async () => {
// todo: cleanup dev-dist folder
})
}
}
else {
nuxt.hook('nitro:init', (nitro) => {
nitro.hooks.hook('rollup:before', async () => {
await resolveVitePluginPWAAPI()?.generateSW()
})
})
}
},
})