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/",
|
||||
"lint": "eslint . --fix",
|
||||
"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": {
|
||||
"@eslint/js": "^9.19.0",
|
||||
"@laravel/vite-plugin-wayfinder": "^0.1.3",
|
||||
"@stylistic/eslint-plugin": "^5.10.0",
|
||||
"@types/node": "^22.13.5",
|
||||
"@vite-pwa/assets-generator": "^1.0.2",
|
||||
"@vue/eslint-config-typescript": "^14.3.0",
|
||||
"eslint": "^9.17.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
@ -27,6 +29,7 @@
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript-eslint": "^8.23.0",
|
||||
"vite-plugin-pwa": "^1.3.0",
|
||||
"vue-tsc": "^2.2.4"
|
||||
},
|
||||
"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_negotiation.c>
|
||||
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 { registerSW } from 'virtual:pwa-register';
|
||||
import { createApp, h } from 'vue';
|
||||
import 'vue-sonner/style.css';
|
||||
import { Toaster } from '@/components/ui/sonner';
|
||||
import { useFlashToast } from '@/composables/useFlashToast';
|
||||
|
||||
registerSW({ immediate: true });
|
||||
|
||||
const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
|
||||
|
||||
createInertiaApp({
|
||||
|
||||
@ -3,10 +3,13 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<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.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
|
||||
|
||||
|
||||
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';
|
||||
130
vite.config.ts
@ -4,31 +4,111 @@ import tailwindcss from '@tailwindcss/vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import laravel from 'laravel-vite-plugin';
|
||||
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({
|
||||
plugins: [
|
||||
laravel({
|
||||
input: ['resources/css/app.css', 'resources/js/app.ts'],
|
||||
refresh: true,
|
||||
fonts: [
|
||||
bunny('Instrument Sans', {
|
||||
weights: [400, 500, 600],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
inertia(),
|
||||
tailwindcss(),
|
||||
vue({
|
||||
template: {
|
||||
transformAssetUrls: {
|
||||
base: null,
|
||||
includeAbsolute: false,
|
||||
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: [
|
||||
laravel({
|
||||
input: ['resources/css/app.css', 'resources/js/app.ts'],
|
||||
refresh: true,
|
||||
fonts: [
|
||||
bunny('Instrument Sans', {
|
||||
weights: [400, 500, 600],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
inertia(),
|
||||
tailwindcss(),
|
||||
vue({
|
||||
template: {
|
||||
transformAssetUrls: {
|
||||
base: null,
|
||||
includeAbsolute: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
wayfinder({
|
||||
formVariants: true,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
wayfinder({
|
||||
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],
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||