Skip to content

Commit

Permalink
feat(service-worker): inject registration script to all pages (#299)
Browse files Browse the repository at this point in the history
  • Loading branch information
farnabaz authored Jun 29, 2022
1 parent 134f89f commit 486f236
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 30 deletions.
12 changes: 9 additions & 3 deletions src/prerender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { parseURL, withBase } from 'ufo'
import chalk from 'chalk'
import { createNitro } from './nitro'
import { build } from './build'
import type { Nitro, PrerenderRoute } from './types'
import type { Nitro, PrerenderGenerateRoute, PrerenderRoute } from './types'
import { writeFile } from './utils'

const allowedExtensions = new Set(['', '.json'])
Expand Down Expand Up @@ -43,13 +43,13 @@ export async function prerender (nitro: Nitro) {
const generateRoute = async (route: string) => {
const start = Date.now()

// Check if we should render routee
// Check if we should render route
if (!canPrerender(route)) { return }
generatedRoutes.add(route)
routes.delete(route)

// Create result object
const _route: PrerenderRoute = { route }
const _route: PrerenderGenerateRoute = { route }

// Fetch the route
const res = await (localFetch(withBase(route, nitro.options.baseURL), { headers: { 'X-Nitro-Prerender': route } }) as ReturnType<typeof fetch>)
Expand All @@ -64,6 +64,12 @@ export async function prerender (nitro: Nitro) {
const isImplicitHTML = !route.endsWith('.html') && (res.headers.get('content-type') || '').includes('html')
const routeWithIndex = route.endsWith('/') ? route + 'index' : route
_route.fileName = isImplicitHTML ? route + '/index.html' : routeWithIndex

await nitro.hooks.callHook('prerender:generate', _route, nitro)

// Check if route skipped by hook
if (_route.skip) { return }

const filePath = join(nitro.options.output.publicDir, _route.fileName)
await writeFile(filePath, _route.contents)

Expand Down
52 changes: 25 additions & 27 deletions src/presets/service-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,35 @@ import { joinURL } from 'ufo'
import { defineNitroPreset } from '../preset'
import type { Nitro } from '../types'

// TODO
// const scriptTemplate = (baseURL = '/') => `
// <script>
// if ('serviceWorker' in navigator) {
// window.addEventListener('load', function () {
// navigator.serviceWorker.register('${joinURL(baseURL, 'sw.js')}');
// });
// }
// </script>
// `
const scriptTemplate = (baseURL = '/') => `
<script>
async function register () {
const registration = await navigator.serviceWorker.register('${joinURL(baseURL, 'sw.js')}')
await navigator.serviceWorker.ready
registration.active.addEventListener('statechange', (event) => {
if (event.target.state === 'activated') {
window.location.reload()
}
})
}
if ('serviceWorker' in navigator) {
if (location.hostname !== 'localhost' && location.protocol === 'http:') {
location.replace(location.href.replace('http://', 'https://'))
} else {
register()
}
}
</script>
`

const htmlTemplate = (baseURL = '/') => `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="prefetch" href="${joinURL(baseURL, 'sw.js')}">
<link rel="prefetch" href="${joinURL(baseURL, 'server/index.mjs')}">
<script>
async function register () {
const registration = await navigator.serviceWorker.register('${joinURL(baseURL, 'sw.js')}')
await navigator.serviceWorker.ready
registration.active.addEventListener('statechange', (event) => {
if (event.target.state === 'activated') {
window.location.reload()
}
})
}
if (location.hostname !== 'localhost' && location.protocol === 'http:') {
location.replace(location.href.replace('http://', 'https://'))
} else {
register()
}
</script>
${scriptTemplate(baseURL)}
</head>
<body>
Initializing nitro service worker...
</body>
Expand All @@ -55,6 +49,10 @@ export const serviceWorker = defineNitroPreset(() => {
preview: 'npx serve ./public'
},
hooks: {
'prerender:generate' (route, nitro) {
const script = scriptTemplate(nitro.options.baseURL)
route.contents = route.contents.replace('</head>', `${script}\n</head>`)
},
async 'compiled' (nitro: Nitro) {
// Write sw.js file
await fsp.writeFile(resolve(nitro.options.output.publicDir, 'sw.js'), `self.importScripts('${joinURL(nitro.options.baseURL, 'server/index.mjs')}');`, 'utf8')
Expand Down
5 changes: 5 additions & 0 deletions src/types/nitro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,18 @@ export interface PrerenderRoute {
generateTimeMS?: number
}

export interface PrerenderGenerateRoute extends PrerenderRoute {
skip?: boolean
}

type HookResult = void | Promise<void>
export interface NitroHooks {
'rollup:before': (nitro: Nitro) => HookResult
'compiled': (nitro: Nitro) => HookResult
'dev:reload': () => HookResult
'close': () => HookResult
'prerender:route': (route: PrerenderRoute) => HookResult
'prerender:generate': (route: PrerenderGenerateRoute, nitro: Nitro) => HookResult
}

type CustomDriverName = string & { _custom?: any }
Expand Down

0 comments on commit 486f236

Please sign in to comment.