Skip to content

feat(addon): vite pwa #84

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions packages/cta-engine/src/create-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,7 @@ async function createPackageJSON(
templateDir: string,
routerDir: string,
targetDir: string,
addOns: Array<{
dependencies?: Record<string, string>
devDependencies?: Record<string, string>
scripts?: Record<string, string>
}>,
addOns: Array<AddOn['packageAdditions']>,
) {
let packageJSON = JSON.parse(
await environment.readFile(resolve(templateDir, 'package.json'), 'utf8'),
Expand Down Expand Up @@ -237,20 +233,28 @@ async function createPackageJSON(
}

for (const addOn of addOns) {
const { dependencies, devDependencies, scripts, pnpm, ...rest } = addOn
packageJSON = {
...packageJSON,
dependencies: {
...packageJSON.dependencies,
...addOn.dependencies,
...dependencies,
},
devDependencies: {
...packageJSON.devDependencies,
...addOn.devDependencies,
...devDependencies,
},
scripts: {
...packageJSON.scripts,
...addOn.scripts,
...scripts,
},
...rest,
}
if (options.packageManager === 'pnpm') {
packageJSON.pnpm = {
...(packageJSON?.pnpm ?? {}),
...pnpm,
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions packages/cta-engine/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ export type AddOn = {
dependencies?: Record<string, string>
devDependencies?: Record<string, string>
scripts?: Record<string, string>
} & {
[key: string]: Record<string, string>
}
command?: {
command: string
Expand Down
12 changes: 12 additions & 0 deletions packages/cta-engine/templates/react/add-on/pwa/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## Vite PWA

- You application is now a PWA, using Vite PWA.

### Notes

- If you are using Deno, make sure that sharp postinstall script is run after installation.
```bash
deno install --allow-scripts=npm:sharp
```


Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {
defineConfig,
minimal2023Preset as preset,
} from '@vite-pwa/assets-generator/config'

export default defineConfig({
headLinkOptions: {
preset: '2023',
},
preset,
images: ['public/logo.svg'],
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.Container {
padding: 0;
margin: 0;
width: 0;
height: 0;
}
.Toast {
position: fixed;
right: 0;
bottom: 0;
margin: 16px;
padding: 12px;
border: 1px solid #8885;
border-radius: 4px;
z-index: 1;
text-align: left;
box-shadow: 3px 4px 5px 0 #8885;
background-color: white;
}
.Message {
margin-bottom: 8px;
}
.Toast-button {
border: 1px solid #8885;
outline: none;
margin-right: 5px;
border-radius: 2px;
padding: 3px 10px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { useRegisterSW } from 'virtual:pwa-register/react'

import styles from './PWABadge.module.css'

function PWABadge() {
// check for updates every hour
const period = 60 * 60 * 1000

const {
offlineReady: [offlineReady, setOfflineReady],
needRefresh: [needRefresh, setNeedRefresh],
updateServiceWorker,
} = useRegisterSW({
onRegisteredSW(swUrl, r) {
if (period <= 0) return
if (r?.active?.state === 'activated') {
registerPeriodicSync(period, swUrl, r)
}
else if (r?.installing) {
r.installing.addEventListener('statechange', (e) => {
const sw = e.target as ServiceWorker
if (sw.state === 'activated')
registerPeriodicSync(period, swUrl, r)
})
}
},
})

function close() {
setOfflineReady(false)
setNeedRefresh(false)
}

return (
<div className={styles.Container} role="alert" aria-labelledby="toast-message">
{ (needRefresh || offlineReady) ?
(
<div className={styles.Toast}>
<div className={styles.Message}>
{offlineReady ? (
<span id="toast-message">App ready to work offline</span>
) : (
<span id="toast-message">New content available, click on reload button to update.</span>
)}
</div>
<div>
{needRefresh ? (
<button className={styles.ToastButton} onClick={() => updateServiceWorker(true)}>Reload</button>
) : null}
<button className={styles.ToastButton} onClick={() => close()}>Close</button>
</div>
</div>
): null}
</div>
)
}

export default PWABadge

/**
* This function will register a periodic sync check every hour, you can modify the interval as needed.
*/
function registerPeriodicSync(period: number, swUrl: string, r: ServiceWorkerRegistration) {
if (period <= 0) return

setInterval(async () => {
if ('onLine' in navigator && !navigator.onLine)
return

const resp = await fetch(swUrl, {
cache: 'no-store',
headers: {
'cache': 'no-store',
'cache-control': 'no-cache',
},
})

if (resp?.status === 200)
await r.update()
}, period)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import PWABadge from '@/components/PWABadge'

export default function LayoutAddition() {
return <PWABadge />
}
10 changes: 10 additions & 0 deletions packages/cta-engine/templates/react/add-on/pwa/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "Vite PWA",
"description": "Add PWA support to your application",
"phase": "add-on",
"link": "https://github.com/vite-pwa/vite-plugin-pwa",
"templates": [
"file-router",
"code-router"
]
}
17 changes: 17 additions & 0 deletions packages/cta-engine/templates/react/add-on/pwa/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"devDependencies": {
"@vite-pwa/assets-generator": "^0.2.6",
"vite-plugin-pwa": "^0.21.1",
"workbox-core": "^7.3.0",
"workbox-window": "^7.3.0"
},
"resolutions": {
"sharp": "0.32.6",
"sharp-ico": "0.1.5"
},
"pnpm": {
"onlyBuiltDependencies": [
"sharp"
]
}
}
2 changes: 1 addition & 1 deletion packages/cta-engine/templates/react/base/tsconfig.json.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"jsx": "react-jsx",
"module": "ESNext",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"types": ["vite/client"],
"types": ["vite/client"<% if (addOnEnabled['pwa']) { %>, "vite-plugin-pwa/react"<% } %>],

/* Bundler mode */
"moduleResolution": "bundler",
Expand Down
33 changes: 32 additions & 1 deletion packages/cta-engine/templates/react/base/vite.config.js.ejs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { defineConfig } from "vite";
import viteReact from "@vitejs/plugin-react";<% if (tailwind) { %>
import tailwindcss from "@tailwindcss/vite";
<% } %><% if (addOnEnabled['pwa']) { %>
import { VitePWA } from 'vite-plugin-pwa';
import pkg from './package.json';
<% } %><%if (fileRouter) { %>
import { TanStackRouterVite } from "@tanstack/router-plugin/vite";<% } %><% if (addOnEnabled['module-federation']) { %>
import { federation } from "@module-federation/vite";<% } %>
Expand All @@ -10,7 +13,35 @@ import federationConfig from "./module-federation.config.js";

// https://vitejs.dev/config/
export default defineConfig({
plugins: [<% if(fileRouter) { %>TanStackRouterVite({ autoCodeSplitting: true }), <% } %>viteReact()<% if (tailwind) { %>, tailwindcss()<% } %><% if (addOnEnabled['module-federation']) { %>, federation(federationConfig)<% } %>],
plugins: [<% if(fileRouter) { %>TanStackRouterVite({ autoCodeSplitting: true }), <% } %>viteReact()<% if (tailwind) { %>, tailwindcss()<% } %><% if (addOnEnabled['module-federation']) { %>, federation(federationConfig)<% } %><% if (addOnEnabled['pwa']) { %>, VitePWA({
registerType: 'autoUpdate',
injectRegister: false,

pwaAssets: {
disabled: false,
config: true,
},
manifestFilename: 'manifest.json',
manifest: {
name: pkg.name,
short_name: pkg.name,
description: pkg.description || pkg.name,
theme_color: '#ffffff',
},

workbox: {
globPatterns: ['**/*.{js,css,html,svg,png,ico}'],
cleanupOutdatedCaches: true,
clientsClaim: true,
},

devOptions: {
enabled: false,
navigateFallback: 'index.html',
suppressWarnings: true,
type: 'module',
},
})<% } %>],
test: {
globals: true,
environment: "jsdom",
Expand Down
12 changes: 12 additions & 0 deletions packages/cta-engine/templates/solid/add-on/pwa/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## Vite PWA

- You application is now a PWA, using Vite PWA.

### Notes

- If you are using Deno, make sure that sharp postinstall script is run after installation.
```bash
deno install --allow-scripts=npm:sharp
```


Loading