在 Laravel 项目中使用 vite-plugin-pwa 的正确方法是什么?

Ade*_*owe 6 laravel progressive-web-apps laravel-mix workbox vite

我有一个 laravel (inertia/vue) 应用程序(直到最近才使用 laravel-mix),其中包含我使用 pwa 构建器和工作箱构建的 pwa 功能。

随着laravel框架从laravel-mix改为vite,我迁移到vite,它的功能按预期工作,js和css被注入到应用程序入口页面的head元素中,vue页面按预期工作,在开发过程中,不会编译任何内容并将其注入到公共文件夹中,就像 laravel-mix/webpack 的情况一样。

我现在无法像以前一样让 PWA 功能正常工作。由于我不再使用 webpack/laravel-mix,我用这个插件替换了我正在使用的 webpack-workbox 插件:vite-plugin-pwa

当我使用 laravel-mix 和 webpack-workbox 插件时,我只需指向 webpack 配置文件中的源 Service Worker 文件,并使用我想要的 Workbox 策略来构建最终的 Service Worker 文件,然后将其编译并放置在我的公共目录中文件夹以及其他已编译的 css 和 js 文件。

使用此 vite 插件,我的最终服务工作人员不会被编译并放置在公共目录中,因此应用程序无法发现服务工作人员。我收到 404 错误,并显示以下消息:“无法为范围注册服务工作线程...”,因为没有可用的服务工作线程文件。

我怀疑我没有以正确的方式配置或使用此插件,并且希望获得有关如何执行此操作或以其他方式解决此问题的帮助。

这是我的 vite.config.js 文件:

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
import { VitePWA } from 'vite-plugin-pwa'

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.js',
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
                compilerOptions: {
                    isCustomElement: tag => tag.startsWith('pwa-')
                    || tag.startsWith('font-')
                },
            },
        }),
        VitePWA({
            strategies: 'injectManifest',
            swSrc: './public/sw.js',
            swDest: './public/pwabuilder-sw.js',
            devOptions: {
                enabled: true,
                type: 'module'
            }
        }),
    ],
});

Run Code Online (Sandbox Code Playgroud)

这是我的公共文件夹中的源 Service Worker 文件:

// This is the "Offline copy of assets" service worker
import {BackgroundSyncPlugin} from 'workbox-background-sync'
import {registerRoute} from 'workbox-routing'
import {StaleWhileRevalidate} from 'workbox-strategies'
import {ExpirationPlugin} from 'workbox-expiration'

const CACHE = "pwabuilder-offline"
const QUEUE_NAME = "bgSyncQueue"

self.__WB_DISABLE_DEV_LOGS = true

self.addEventListener("message", (event) => {
  if (event.data && event.data.type === "SKIP_WAITING") {
    self.skipWaiting()
  }
})

const bgSyncPlugin = new BackgroundSyncPlugin(QUEUE_NAME, {
  maxRetentionTime: 24 * 60 // Retry for max of 24 Hours (specified in minutes)
})

const expPlugin = new ExpirationPlugin({
  maxEntries: 5,
  maxAgeSeconds: 1 * 24 * 60 * 60,
  purgeOnQuotaError: true,
  matchOptions: {
    ignoreVary: true,
  }
})

registerRoute(
  new RegExp('/*'),
  new StaleWhileRevalidate({
    cacheName: CACHE,
    plugins: [
      bgSyncPlugin,
      expPlugin
    ]
  })
)

self.addEventListener('push', function (e) {
  if (!(self.Notification && self.Notification.permission === 'granted')) {
      return;
  }

  if (e.data) {
    const msg = e.data.json()
    clients.matchAll().then(function(c) {
        e.waitUntil(self.registration.showNotification('SmartWealth Push Notification', {
          body: msg.notification.body,
          icon: msg.notification.icon,
          actions: msg.notification.actions,
          deep_link: msg.notification.deep_link
        }))

    })
  }
})
Run Code Online (Sandbox Code Playgroud)

更新这是我当前使用 workbox CDN 的软件:

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
import { VitePWA } from 'vite-plugin-pwa'

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.js',
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
                compilerOptions: {
                    isCustomElement: tag => tag.startsWith('pwa-')
                    || tag.startsWith('font-')
                },
            },
        }),
        VitePWA({
            strategies: 'injectManifest',
            swSrc: './public/sw.js',
            swDest: './public/pwabuilder-sw.js',
            devOptions: {
                enabled: true,
                type: 'module'
            }
        }),
    ],
});

Run Code Online (Sandbox Code Playgroud)

我不再需要 vite 来注入我的 SW。

sif*_*day 0

在 Laravel 项目中使用 vite-plugin-pwa 的正确方法因许多问题而变得复杂,例如:

  • Laravel 有自己的公共目录
  • 因此,vite 然后构建到 public/build/assets,这与通常的前端布局不同
  • PWA 没有立即明显的静态 HTML 入口点
  • Laravel 会将其他您不希望离线的东西(例如 Telescope)放在公共目录中

为了使其正常工作,您需要配置 vite-plugin-pwa 来解决以下问题:

  • 在 vite.config.ts 中配置 buildBase 和 outDir 作为您首选的目录结构
  • 创建一个 Blade 文件作为 HTML 入口点并将其配置添加到 vite.config.ts
  • 向 Web 服务器添加Service-Worker-Allowed标头以解决构建目录施加的限制
  • 在 vite.config.ts 中配置缓存以解决公共目录中的其他资产

这里有一个详细的 GitHub 问题探讨这个问题:

https://github.com/vite-pwa/vite-plugin-pwa/issues/431

我通过这个线程让我自己的 Laravel、Vite、Vue3 和 TypeScript 应用程序作为 PWA 工作,并提供离线支持和应用程序安装提示。最初的问题是从演示存储库询问的,所以我根据我的经验进行了设置,以防它可以帮助其他人。你可以在这里找到它:

https://github.com/sfreytag/laravel-vite-pwa