Add PWA support with VitePWA integration, including manifest configuration and service worker registration. Update package dependencies for PWA assets generation. Enhance application metadata for improved PWA experience.
4100
package-lock.json
generated
@ -10,13 +10,15 @@
|
|||||||
"format:check": "prettier --check resources/",
|
"format:check": "prettier --check resources/",
|
||||||
"lint": "eslint . --fix",
|
"lint": "eslint . --fix",
|
||||||
"lint:check": "eslint .",
|
"lint:check": "eslint .",
|
||||||
"types:check": "vue-tsc --noEmit"
|
"types:check": "vue-tsc --noEmit",
|
||||||
|
"pwa-icons": "pwa-assets-generator --preset minimal public/assets/logo.png"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.19.0",
|
"@eslint/js": "^9.19.0",
|
||||||
"@laravel/vite-plugin-wayfinder": "^0.1.3",
|
"@laravel/vite-plugin-wayfinder": "^0.1.3",
|
||||||
"@stylistic/eslint-plugin": "^5.10.0",
|
"@stylistic/eslint-plugin": "^5.10.0",
|
||||||
"@types/node": "^22.13.5",
|
"@types/node": "^22.13.5",
|
||||||
|
"@vite-pwa/assets-generator": "^1.0.2",
|
||||||
"@vue/eslint-config-typescript": "^14.3.0",
|
"@vue/eslint-config-typescript": "^14.3.0",
|
||||||
"eslint": "^9.17.0",
|
"eslint": "^9.17.0",
|
||||||
"eslint-config-prettier": "^10.0.1",
|
"eslint-config-prettier": "^10.0.1",
|
||||||
@ -27,6 +29,7 @@
|
|||||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||||
"tw-animate-css": "^1.4.0",
|
"tw-animate-css": "^1.4.0",
|
||||||
"typescript-eslint": "^8.23.0",
|
"typescript-eslint": "^8.23.0",
|
||||||
|
"vite-plugin-pwa": "^1.3.0",
|
||||||
"vue-tsc": "^2.2.4"
|
"vue-tsc": "^2.2.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -1,3 +1,12 @@
|
|||||||
|
<IfModule mod_mime.c>
|
||||||
|
AddType application/manifest+json .webmanifest
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule mod_headers.c>
|
||||||
|
SetEnvIf Request_URI "^/build/sw\.js$" sw_file
|
||||||
|
Header set Service-Worker-Allowed "/" env=sw_file
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
<IfModule mod_rewrite.c>
|
<IfModule mod_rewrite.c>
|
||||||
<IfModule mod_negotiation.c>
|
<IfModule mod_negotiation.c>
|
||||||
Options -MultiViews -Indexes
|
Options -MultiViews -Indexes
|
||||||
|
|||||||
BIN
public/assets/apple-touch-icon-180x180.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
public/assets/favicon.ico
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
public/assets/logo.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
public/assets/maskable-icon-512x512.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
public/assets/pwa-192x192.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
public/assets/pwa-512x512.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/assets/pwa-64x64.png
Normal file
|
After Width: | Height: | Size: 968 B |
@ -1,9 +1,14 @@
|
|||||||
|
/// <reference types="vite-plugin-pwa/client" />
|
||||||
|
|
||||||
import { createInertiaApp } from '@inertiajs/vue3';
|
import { createInertiaApp } from '@inertiajs/vue3';
|
||||||
|
import { registerSW } from 'virtual:pwa-register';
|
||||||
import { createApp, h } from 'vue';
|
import { createApp, h } from 'vue';
|
||||||
import 'vue-sonner/style.css';
|
import 'vue-sonner/style.css';
|
||||||
import { Toaster } from '@/components/ui/sonner';
|
import { Toaster } from '@/components/ui/sonner';
|
||||||
import { useFlashToast } from '@/composables/useFlashToast';
|
import { useFlashToast } from '@/composables/useFlashToast';
|
||||||
|
|
||||||
|
registerSW({ immediate: true });
|
||||||
|
|
||||||
const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
|
const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
|
||||||
|
|
||||||
createInertiaApp({
|
createInertiaApp({
|
||||||
|
|||||||
@ -3,10 +3,13 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="description" content="{{ config('app.name', 'Laravel') }} - Progressive Web App">
|
||||||
|
<meta name="theme-color" content="#171717">
|
||||||
|
|
||||||
<link rel="icon" href="/favicon.ico" sizes="any">
|
<link rel="icon" href="/favicon.ico" sizes="any">
|
||||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
||||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
|
<link rel="apple-touch-icon" href="/assets/apple-touch-icon-180x180.png" sizes="180x180">
|
||||||
|
<link rel="manifest" href="/build/manifest.webmanifest">
|
||||||
|
|
||||||
@fonts
|
@fonts
|
||||||
|
|
||||||
|
|||||||
28
server.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override Laravel's default server router for `php artisan serve`.
|
||||||
|
* Serves the service worker with the Service-Worker-Allowed header
|
||||||
|
* so it can control the entire site scope from /build/sw.js.
|
||||||
|
*
|
||||||
|
* @see https://vite-pwa-org.netlify.app/frameworks/laravel.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
$publicPath = getcwd();
|
||||||
|
|
||||||
|
$uri = urldecode(
|
||||||
|
parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) ?? ''
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($uri !== '/' && $uri !== '/build/sw.js' && file_exists($publicPath.$uri)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($uri === '/build/sw.js') {
|
||||||
|
header('Service-Worker-Allowed: /');
|
||||||
|
header('Content-Type: text/javascript');
|
||||||
|
echo file_get_contents(__DIR__.'/public/build/sw.js');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once $publicPath.'/index.php';
|
||||||
@ -4,9 +4,46 @@ import tailwindcss from '@tailwindcss/vite';
|
|||||||
import vue from '@vitejs/plugin-vue';
|
import vue from '@vitejs/plugin-vue';
|
||||||
import laravel from 'laravel-vite-plugin';
|
import laravel from 'laravel-vite-plugin';
|
||||||
import { bunny } from 'laravel-vite-plugin/fonts';
|
import { bunny } from 'laravel-vite-plugin/fonts';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig, loadEnv } from 'vite';
|
||||||
|
import { VitePWA } from 'vite-plugin-pwa';
|
||||||
|
|
||||||
export default defineConfig({
|
const manifestIcons = [
|
||||||
|
{
|
||||||
|
src: '/assets/pwa-64x64.png',
|
||||||
|
sizes: '64x64',
|
||||||
|
type: 'image/png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: '/assets/pwa-192x192.png',
|
||||||
|
sizes: '192x192',
|
||||||
|
type: 'image/png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: '/assets/pwa-512x512.png',
|
||||||
|
sizes: '512x512',
|
||||||
|
type: 'image/png',
|
||||||
|
purpose: 'any',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: '/assets/maskable-icon-512x512.png',
|
||||||
|
sizes: '512x512',
|
||||||
|
type: 'image/png',
|
||||||
|
purpose: 'maskable',
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const publicIcons = [
|
||||||
|
{ src: '/favicon.ico' },
|
||||||
|
{ src: '/favicon.svg' },
|
||||||
|
{ src: '/assets/apple-touch-icon-180x180.png' },
|
||||||
|
{ src: '/assets/logo.png' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default defineConfig(({ mode }) => {
|
||||||
|
const env = loadEnv(mode, process.cwd(), '');
|
||||||
|
const appName = env.VITE_APP_NAME || 'DST Collection';
|
||||||
|
|
||||||
|
return {
|
||||||
plugins: [
|
plugins: [
|
||||||
laravel({
|
laravel({
|
||||||
input: ['resources/css/app.css', 'resources/js/app.ts'],
|
input: ['resources/css/app.css', 'resources/js/app.ts'],
|
||||||
@ -30,5 +67,48 @@ export default defineConfig({
|
|||||||
wayfinder({
|
wayfinder({
|
||||||
formVariants: true,
|
formVariants: true,
|
||||||
}),
|
}),
|
||||||
|
VitePWA({
|
||||||
|
buildBase: '/build/',
|
||||||
|
scope: '/',
|
||||||
|
base: '/',
|
||||||
|
registerType: 'autoUpdate',
|
||||||
|
devOptions: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
includeAssets: [],
|
||||||
|
workbox: {
|
||||||
|
globPatterns: [
|
||||||
|
'**/*.{js,css,html,ico,jpg,png,svg,woff,woff2,ttf,eot}',
|
||||||
],
|
],
|
||||||
|
navigateFallback: '/',
|
||||||
|
navigateFallbackDenylist: [/^\/telescope/],
|
||||||
|
additionalManifestEntries: [
|
||||||
|
{ url: '/', revision: `${Date.now()}` },
|
||||||
|
...manifestIcons.map((icon) => ({
|
||||||
|
url: icon.src,
|
||||||
|
revision: `${Date.now()}`,
|
||||||
|
})),
|
||||||
|
...publicIcons.map((icon) => ({
|
||||||
|
url: icon.src,
|
||||||
|
revision: `${Date.now()}`,
|
||||||
|
})),
|
||||||
|
],
|
||||||
|
maximumFileSizeToCacheInBytes: 3_000_000,
|
||||||
|
},
|
||||||
|
manifest: {
|
||||||
|
name: appName,
|
||||||
|
short_name: appName,
|
||||||
|
description: `${appName} - Progressive Web App`,
|
||||||
|
theme_color: '#171717',
|
||||||
|
background_color: '#ffffff',
|
||||||
|
display: 'standalone',
|
||||||
|
orientation: 'portrait',
|
||||||
|
scope: '/',
|
||||||
|
start_url: '/',
|
||||||
|
id: '/',
|
||||||
|
icons: [...manifestIcons],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|||||||