You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Vite中如何打包带import的Service Worker?

Laravel Vite 结合 Workbox 配置 Service Worker 解决方案

核心问题梳理

  1. import 语法报错:Service Worker 默认以经典脚本模式运行,直接用 import 会触发语法错误
  2. 打包后文件名带 Hash:Laravel Vite 默认将资源打包到 assets 目录并添加 Hash,不符合 Service Worker 固定文件名的要求
  3. 开发环境 404 错误:ES Module 模式下注册 Service Worker 时,无法正确找到脚本文件

关键前提确认

你关于「Service Worker 文件名应固定」的想法完全正确:浏览器通过文件名识别已注册的 Service Worker,仅当文件内容变更时才会触发更新流程。使用 Hash 文件名会导致每次打包都生成新文件,打乱浏览器的 Service Worker 更新逻辑。

分步解决方案

1. 调整 Vite 配置,固定 SW 输出文件名

修改 vite.config.js,单独配置 SW 文件的打包规则,输出到 public 根目录且不带 Hash:

import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'

export default defineConfig({
    plugins: [
        laravel({
            input: [
                'resources/css/app.css',
                'resources/js/app.js',
            ],
            refresh: true,
        }),
    ],
    build: {
        rollupOptions: {
            input: {
                sw: 'resources/js/sw.js',
            },
            output: {
                entryFileNames: (chunkInfo) => {
                    // 仅给 SW 文件固定文件名,其他资源保留 Hash
                    return chunkInfo.name === 'sw' ? 'sw.js' : 'assets/[name]-[hash].js';
                },
                dir: 'public',
            },
        },
    },
})

2. 修改 SW 文件,兼容开发/生产环境

将 Workbox 的导入改为动态导入,开发环境用 CDN ES 模块,生产环境依赖 Vite 打包:

// sw.js
let warmStrategyCache, offlineFallback;
let CacheFirst, StaleWhileRevalidate;
let registerRoute;
let CacheableResponsePlugin;
let ExpirationPlugin;

if (import.meta.env.DEV) {
    // 开发环境加载 Workbox ES 模块 CDN
    const recipes = await import('https://esm.sh/workbox-recipes');
    const strategies = await import('https://esm.sh/workbox-strategies');
    const routing = await import('https://esm.sh/workbox-routing');
    const cacheableResponse = await import('https://esm.sh/workbox-cacheable-response');
    const expiration = await import('https://esm.sh/workbox-expiration');
    
    ({ warmStrategyCache, offlineFallback } = recipes);
    ({ CacheFirst, StaleWhileRevalidate } = strategies);
    ({ registerRoute } = routing);
    ({ CacheableResponsePlugin } = cacheableResponse);
    ({ ExpirationPlugin } = expiration);
} else {
    // 生产环境使用打包后的 Workbox 依赖
    ({ warmStrategyCache, offlineFallback } = await import('workbox-recipes'));
    ({ CacheFirst, StaleWhileRevalidate } = await import('workbox-strategies'));
    ({ registerRoute } = await import('workbox-routing'));
    ({ CacheableResponsePlugin } = await import('workbox-cacheable-response'));
    ({ ExpirationPlugin } = await import('workbox-expiration'));
}

// 缓存逻辑保持不变
const pageCache = new CacheFirst({
    cacheName: 'page-cache',
    plugins: [
        new CacheableResponsePlugin({
            statuses: [0, 200],
        }),
        new ExpirationPlugin({
            maxAgeSeconds: 30 * 24 * 60 * 60,
        }),
    ],
})

warmStrategyCache({
    urls: ['/index.html', '/'],
    strategy: pageCache,
})

registerRoute(({ request }) => request.mode === 'navigate', pageCache)

registerRoute(
    ({ request }) => ['style', 'script', 'worker'].includes(request.destination),
    new StaleWhileRevalidate({
        cacheName: 'asset-cache',
        plugins: [
            new CacheableResponsePlugin({
                statuses: [0, 200],
            }),
        ],
    }),
)

offlineFallback({
    pageFallback: '/offline.html',
})

3. 修正 Service Worker 注册逻辑

修改 app.js,根据环境切换注册路径和脚本类型:

// app.js
if ('serviceWorker' in navigator) {
    window.addEventListener('load', async () => {
        try {
            const swUrl = import.meta.env.DEV ? '/resources/js/sw.js' : '/sw.js';
            const reg = await navigator.serviceWorker.register(swUrl, {
                type: import.meta.env.DEV ? 'module' : 'classic',
            });

            console.log('Service worker registered! 😎', reg);
        } catch (err) {
            console.log('😥 Service worker registration failed: ', err);
        }
    });
}

工作原理说明

  • 生产环境:Vite 会将 SW 文件打包为无 Hash 的 public/sw.js,并将 Workbox 依赖内联,最终以经典脚本模式运行
  • 开发环境:直接加载 resources/js/sw.js,以 ES Module 模式运行,通过 CDN 获取 Workbox 模块,避免打包开销

内容的提问来源于stack exchange,提问作者Arjen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 23:32:18