Skip to content
This repository has been archived by the owner on May 2, 2024. It is now read-only.

Commit

Permalink
feat: usePWAIcon composable (#43)
Browse files Browse the repository at this point in the history
* chore: wip

* fix: convert `pwa.d.ts` into declaration (#42)

* chore: use edge

* feat: implement composable

Co-authored-by: Daniel Roe <[email protected]>
  • Loading branch information
kevinmarrec and danielroe authored Oct 1, 2022
1 parent 431c0c9 commit adfac55
Show file tree
Hide file tree
Showing 13 changed files with 164 additions and 46 deletions.
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,20 @@ export default defineNuxtConfig({

> To customize it, you can check the default of this module [here](https://github.com/kevinmarrec/nuxt-pwa-module/blob/main/templates/workbox/sw.js), as well as [Nuxt 2 default](https://github.com/nuxt-community/pwa-module/blob/main/templates/workbox/sw.js) and [Workbox Documentation](https://developer.chrome.com/docs/workbox).
## ⚠️ Missing features ⚠️
## Composables

Compared to Nuxt 2 PWA, this module is - as for now - missing the following features:
- Workbox extra options (`enabled`, `workboxUrl`, `workboxVersion` only supported)
- OneSignal support
### usePWAIcon (size, options)

You can use `usePWAIcon` to get icons urls of your PWA, and use it in your app.

```ts
const icon = usePWAIcon(512) // /assets/icons/512x512.png
const icon = usePWAIcon(512, { maskable: true }) // /assets/icons/512x512.maskable.png
```

Alternatively, you can benefit of available sizes with Typescript using a `string` instead of `number` size parameter :

![image](https://user-images.githubusercontent.com/25272043/193407772-2326170d-86cc-4246-ae8c-cb711b4d8aa9.png)

## Development

Expand Down
14 changes: 14 additions & 0 deletions example/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<template>
<main class="container h-screen mx-auto flex justify-center items-center">
<div class="justify-center items-center">
<img :src="usePWAIcon(192)">
<span class="text-lg">This page should work offline.</span>
</div>
</main>
</template>

<style lang="postcss">
html {
@apply bg-cool-gray-900 text-white
}
</style>
5 changes: 1 addition & 4 deletions example/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export default defineNuxtConfig({
app: {
buildAssetsDir: '/assets/'
},
css: ['@unocss/reset/antfu.css'],
modules: [
'@unocss/nuxt',
'../src/module'
Expand All @@ -14,9 +15,5 @@ export default defineNuxtConfig({
workbox: {
enabled: true
}
},
unocss: {
preflight: true,
icons: true
}
})
13 changes: 0 additions & 13 deletions example/pages/index.vue

This file was deleted.

14 changes: 14 additions & 0 deletions example/uno.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {
defineConfig,
presetUno,
transformerDirectives
} from 'unocss'

export default defineConfig({
presets: [
presetUno()
],
transformers: [
transformerDirectives()
]
})
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"@unocss/nuxt": "^0.45.26",
"@vitest/coverage-c8": "^0.23.4",
"eslint": "^8.24.0",
"nuxt": "^3.0.0-rc.11",
"nuxt": "npm:nuxt3@3.0.0-rc.12-27736489.2e080c2",
"standard-version": "^9.5.0",
"typescript": "^4.8.4",
"vitest": "^0.23.4"
Expand Down
75 changes: 59 additions & 16 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion src/module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { join } from 'pathe'
import { createResolver, defineNuxtModule } from '@nuxt/kit'
import { addImportsDir, createResolver, defineNuxtModule } from '@nuxt/kit'
import parts from './parts'
import type { PWAOptions, PWAContext } from './types'

Expand Down Expand Up @@ -70,6 +70,8 @@ export default defineNuxtModule<PWAOptions>({
_resolver: createResolver(import.meta.url)
}

addImportsDir(ctx._resolver.resolve('./runtime/composables'))

for (const part of parts) {
await part(ctx)
}
Expand Down
14 changes: 12 additions & 2 deletions src/parts/icon/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { existsSync } from 'node:fs'
import { fork } from 'node:child_process'
import consola from 'consola'
import { join, resolve } from 'pathe'
import { join, resolve, relative } from 'pathe'
import { provider } from 'std-env'
import { joinURL } from 'ufo'
import { useNuxt } from '@nuxt/kit'
import { addTemplate, useNuxt } from '@nuxt/kit'
import type { PWAContext } from '../../types'
import { defaultDevices, metaFromDevice } from './splash'
import { getFileHash, makeManifestIcon } from './utils'
Expand Down Expand Up @@ -107,4 +107,14 @@ export default async (pwa: PWAContext) => {
nuxt.hook('nitro:build:before', async () => {
await generate
})

// Generate types
const typesPath = addTemplate({
filename: 'types/pwa.d.ts',
getContents: () => `export type IconSize = number | ${options.sizes.map(size => `'${size}'`).join(' | ')}`
}).dst.replace(/\.d\.ts$/, '')

nuxt.hook('prepare:types', ({ tsConfig }) => {
tsConfig.compilerOptions.paths['#pwa'] = [relative(nuxt.options.srcDir, typesPath)]
})
}
2 changes: 1 addition & 1 deletion src/parts/manifest/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default (pwa: PWAContext) => {

const nuxt = useNuxt()

nuxt.options.runtimeConfig.pwaManifest = pwa.manifest
nuxt.options.runtimeConfig.public.pwaManifest = pwa.manifest

if (nuxt.options.ssr) {
addServerHandler({
Expand Down
9 changes: 9 additions & 0 deletions src/runtime/composables/usePWAIcon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { ManifestIcon } from '../../parts/manifest/types'
import type { IconSize } from '#pwa'
import { useRuntimeConfig } from '#imports'

export function usePWAIcon (size: IconSize, { maskable } = { maskable: false }) {
return (useRuntimeConfig().public.pwaManifest.icons as ManifestIcon[])
.find(i => i.sizes === `${+size}x${+size}` && i.purpose === (maskable ? 'maskable' : 'any'))
?.src || ''
}
5 changes: 1 addition & 4 deletions src/runtime/server/manifest.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import { defineEventHandler } from 'h3'
import { useRuntimeConfig } from '#imports'

export default defineEventHandler(() => {
const { pwaManifest } = useRuntimeConfig()
return pwaManifest
})
export default defineEventHandler(() => useRuntimeConfig().public.pwaManifest)
36 changes: 36 additions & 0 deletions test/composables.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { setup } from '@nuxt/test-utils'
import { describe, it, expect, vi } from 'vitest'
import { usePWAIcon } from '../src/runtime/composables/usePWAIcon'

import './setup'

vi.mock('#imports', () => ({
useRuntimeConfig: () => ({
public: {
pwaManifest: {
icons: [
{ sizes: '64x64', purpose: 'any', src: '/assets/icons/64x64.png' },
{ sizes: '64x64', purpose: 'maskable', src: '/assets/icons/64x64.maskable.png' }
]
}
}
})
}))

describe('composables', async () => {
await setup({})

describe('usePWAIcon', () => {
it('returns icon url', () => {
expect(usePWAIcon(64)).toBe('/assets/icons/64x64.png')
})

it('returns maskable icon url when maskable option is true', () => {
expect(usePWAIcon(64, { maskable: true })).toBe('/assets/icons/64x64.maskable.png')
})

it('returns empty string when icon not found', () => {
expect(usePWAIcon(0)).toBe('')
})
})
})

0 comments on commit adfac55

Please sign in to comment.