Laravel10+Vue3+InertiaJs1.x项目转PWA的改造咨询
改造Laravel 10 + Inertia + Vue3项目为PWA(仅离线功能)
一、先搞定Web App Manifest(和Inertia完全不冲突)
manifest只是定义PWA的基础元数据,和Inertia的路由、数据传递逻辑完全无关,放心加就行:
- 在项目
public目录下创建manifest.json,示例内容:
{ "name": "你的项目名称", "short_name": "短名称", "start_url": "/", "display": "standalone", "background_color": "#ffffff", "theme_color": "#3b82f6", "icons": [ { "src": "/icons/icon-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/icons/icon-512x512.png", "sizes": "512x512", "type": "image/png" } ] }
- 在Laravel的主模板(比如
resources/views/app.blade.php)的<head>里添加:
<link rel="manifest" href="/manifest.json"> <meta name="theme-color" content="#3b82f6">
- 把图标文件放到
public/icons目录下,尺寸按manifest里的要求准备。
二、配置Service Worker(核心,处理离线缓存)
这部分是重点,要适配Inertia的请求逻辑,避免冲突:
1. 注册Service Worker
在Vue入口文件(resources/js/app.js)里添加注册代码,注意只在生产环境启用:
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js') .then(registration => { console.log('SW registered: ', registration); }) .catch(registrationError => { console.log('SW registration failed: ', registrationError); }); }); }
2. 编写Service Worker逻辑(public/sw.js)
因为你的项目没有独立API,都是Inertia的页面请求(带X-Inertia请求头),所以缓存策略要区分静态资源和页面请求:
const CACHE_NAME = 'your-app-cache-v1'; const STATIC_ASSETS = [ '/', '/app.js', // 注意如果用Vite,文件名可能带哈希,需要调整 '/app.css', '/manifest.json', '/icons/icon-192x192.png', '/icons/icon-512x512.png' ]; // 安装阶段:缓存核心静态资源 self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => cache.addAll(STATIC_ASSETS)) .then(() => self.skipWaiting()) ); }); // 激活阶段:清理旧缓存 self.addEventListener('activate', (event) => { event.waitUntil( caches.keys().then(cacheNames => { return Promise.all( cacheNames.filter(name => name !== CACHE_NAME) .map(name => caches.delete(name)) ); }) ); }); // Fetch事件:处理请求缓存 self.addEventListener('fetch', (event) => { const request = event.request; // 跳过非GET请求(Inertia的页面请求都是GET) if (request.method !== 'GET') return; // 处理Inertia页面请求(带X-Inertia头) if (request.headers.get('X-Inertia')) { event.respondWith( caches.match(request) .then(cachedResponse => { // 离线时用缓存,在线时更新缓存 const fetchPromise = fetch(request) .then(networkResponse => { caches.open(CACHE_NAME) .then(cache => cache.put(request, networkResponse.clone())); return networkResponse; }); return cachedResponse || fetchPromise; }) ); return; } // 处理静态资源(优先用缓存) event.respondWith( caches.match(request) .then(cachedResponse => cachedResponse || fetch(request)) ); });
三、避免Inertia和Service Worker冲突的关键细节
- 区分Inertia请求:通过
X-Inertia请求头识别页面请求,单独处理缓存,不要把Inertia的请求当成普通静态资源缓存 - 静态资源哈希:确保Vite/Mix生成的静态资源文件名带哈希(比如
app.abc123.js),这样Service Worker能正确识别资源更新,避免缓存旧资源 - 开发环境禁用:开发时可以注释掉Service Worker注册代码,或者用Chrome DevTools的Application面板手动注销,避免缓存影响开发
- 不要缓存错误页面:可以在fetch事件里判断响应状态码,比如只缓存200的响应,避免把404/500页面缓存下来
四、测试离线功能
- 打包生产环境代码(
npm run build+php artisan optimize) - 用HTTPS部署(或者用localhost,Chrome允许localhost的PWA)
- 打开Chrome DevTools → Application → Service Workers,确认SW已注册
- 勾选"Offline"选项,刷新页面,测试页面和静态资源是否能正常加载
- 导航到几个页面后离线,测试页面跳转是否正常
内容的提问来源于stack exchange,提问作者Christian
相关产品推荐
相关产品推荐

