如何在Next.js中打包Service Worker并解决import语法错误?
问题描述
我正在按照Firebase官方指南配置Service Worker,用来拦截并修改fetch()请求,但现在出现了错误:
Uncaught SyntaxError: Cannot use import statement outside a module (at service-worker.js:1:1)
我怀疑这和指南里的提示有关:
Make sure that the service worker is bundled so that it will still work after the browser has been closed.
我对这个主题不太熟悉,用的是Next.js,只在Next.js文档里找到相关的打包内容。
我的Service Worker代码:
// public/service-worker.js import { auth } from "@/firebase/firebase" import { getIdToken, onAuthStateChanged } from "firebase/auth" // Firebase docs use "activate" not "install" self.addEventListener("install", (event) => { console.log("Installing...") }) ...
注册Service Worker的代码:
// src/app/signup/SignUpForm.js "use client" export function SignUpForm() { useEffect(() => { if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/service-worker.js', { scope: '/' }) } }, []) ... }
请问该如何解决这个错误?
解决方案
错误根源
Service Worker运行在独立的浏览器全局环境中,默认不支持ES模块的import语法;而且Next.js的public目录下的文件会被直接静态托管,不会经过模块打包流程,导致Firebase的导入语句无法被解析。
方案1:改用Firebase CDN脚本引入(快速解决)
直接在Service Worker中通过importScripts加载Firebase的兼容版SDK,避免使用ES模块导入:
// public/service-worker.js // 加载Firebase兼容版SDK importScripts('https://www.gstatic.com/firebasejs/9.23.0/firebase-app-compat.js'); importScripts('https://www.gstatic.com/firebasejs/9.23.0/firebase-auth-compat.js'); // 初始化Firebase(和你项目中的配置完全一致) const firebaseConfig = { apiKey: "你的API_KEY", authDomain: "你的AUTH_DOMAIN", projectId: "你的PROJECT_ID", storageBucket: "你的STORAGE_BUCKET", messagingSenderId: "你的MESSAGING_SENDER_ID", appId: "你的APP_ID" }; firebase.initializeApp(firebaseConfig); const auth = firebase.auth(); // 后续正常使用Firebase Auth API self.addEventListener("install", (event) => { console.log("Installing...") }); // 其他拦截逻辑...
方案2:使用Next.js专用PWA插件(推荐,适配Next.js生态)
借助@ducanh2912/next-pwa插件自动打包Service Worker,支持ES模块导入:
- 安装依赖:
npm install @ducanh2912/next-pwa - 修改
next.config.js配置:const withPWA = require('@ducanh2912/next-pwa').default({ dest: 'public', register: true, // 自动注册Service Worker skipWaiting: true, customWorkerDir: 'src/service-worker', // 自定义Service Worker源码目录 }); module.exports = withPWA({ // 你的Next.js原有配置 }); - 将Service Worker源码移到
src/service-worker/index.js,现在可以正常使用ES模块导入:// src/service-worker/index.js import { auth } from "@/firebase/firebase"; import { getIdToken, onAuthStateChanged } from "firebase/auth"; self.addEventListener("install", (event) => { console.log("Installing...") }); // 其他逻辑... - 移除组件中手动注册Service Worker的代码(插件会自动处理注册)。
方案3:手动打包Service Worker(自定义流程)
用esbuild或webpack单独打包Service Worker源码,将ES模块转换为浏览器兼容格式:
- 安装esbuild:
npm install esbuild --save-dev - 创建打包脚本
build-sw.js:require('esbuild').build({ entryPoints: ['src/service-worker.js'], bundle: true, outfile: 'public/service-worker.js', format: 'iife', // 输出自执行函数,适配Service Worker环境 platform: 'browser', }).catch(() => process.exit(1)); - 在
package.json中添加打包命令:"scripts": { "build:sw": "node build-sw.js", "build": "npm run build:sw && next build" } - 将Service Worker源码移到
src/service-worker.js,正常使用ES模块导入,每次构建时会自动打包到public目录。
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

