在 React 项目中使用 TypeScript 编写 Service Worker 的完整方案

在 React 项目中使用 TypeScript 编写 Service Worker 的完整方案如下:


📝 实现步骤

1. 项目初始化

确保你的 React 项目已支持 TypeScript(通过 create-react-app 或自定义配置)

bash 复制代码
npx create-react-app my-app --template typescript
cd my-app
npm install @types/service_worker_api --save-dev

2. 创建 Service Worker 文件

新建 src/sw.ts

typescript 复制代码
// src/sw.ts
interface DomainUpdateEvent extends ExtendableEvent {
  detail: {
    domains: string[];
  };
}

const ALLOWED_DOMAINS: string[] = ['api.example.com'];

self.addEventListener('fetch', (event) => {
  const requestURL = new URL(event.request.url);
  const requestedDomain = requestURL.hostname;

  if (ALLOWED_DOMAINS.includes(requestedDomain)) {
    console.log(`[SW] 允许请求: ${event.request.url}`);
    
    // 示例:添加请求头
    const modifiedHeaders = new Headers(event.request.headers);
    modifiedHeaders.append('X-SW-Optimized', 'true');
    
    event.respondWith(
      fetch(event.request, {
        headers: modifiedHeaders
      })
    );
  }
});

// 动态更新白名单
self.addEventListener('message', (e: DomainUpdateEvent) => {
  if (e.detail?.domains) {
    ALLOWED_DOMAINS.push(...e.detail.domains);
    console.log('[SW] 更新白名单:', ALLOWED_DOMAINS);
  }
});

3. 配置编译输出

修改 tsconfig.json

json 复制代码
{
  "compilerOptions": {
    "outDir": "build/sw",
    "rootDir": "src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/sw.ts"]
}

4. 注册 Service Worker

src/App.tsx 中注册:

typescript 复制代码
// src/App.tsx
import { useEffect } from 'react';

function App() {
  useEffect(() => {
    if ('serviceWorker' in navigator) {
      const registerSW = async () => {
        try {
          const registration = await navigator.serviceWorker.register(
            process.env.PUBLIC_URL + '/sw.js'
          );
          console.log('SW 注册成功:', registration);
        } catch (err) {
          console.error('SW 注册失败:', err);
        }
      };

      // 开发环境热更新
      if (process.env.NODE_ENV === 'development') {
        const updateSW = () => {
          navigator.serviceWorker.getRegistrations().then(registrations => {
            registrations.forEach(registration => registration.update());
          });
        };
        setInterval(updateSW, 60000); // 每分钟检查更新
      }

      registerSW();
    }
  }, []);

  return <div>App Content</div>;
}

export default App;

5. 配置构建脚本

package.json 中添加构建命令:

json 复制代码
{
  "scripts": {
    "build:sw": "tsc --project tsconfig.json",
    "build": "npm run build:sw && react-scripts build",
    "start": "react-scripts start && npm run build:sw -- --watch"
  }
}

🛠️ 高级技巧

  1. 缓存策略集成

    添加 Workbox 支持:

    bash 复制代码
    npm install workbox-build

    创建 workbox-config.js

    javascript 复制代码
    module.exports = {
      globDirectory: 'build/',
      globPatterns: ['**/*.{js,css,html,png}'],
      swDest: 'build/sw.js',
      clientsClaim: true,
      skipWaiting: true
    };

    修改构建脚本:

    json 复制代码
    {
      "scripts": {
        "build": "react-scripts build && workbox injectManifest workbox-config.js"
      }
    }
  2. 动态配置更新

    通过网页发送消息更新配置:

    typescript 复制代码
    // 在组件中
    const updateSWConfig = () => {
      if ('serviceWorker' in navigator) {
        navigator.serviceWorker.controller?.postMessage({
          type: 'UPDATE_DOMAINS',
          domains: ['new-domain.com']
        });
      }
    };
  3. 调试支持

    src/sw.ts 中添加调试开关:

    typescript 复制代码
    const DEBUG_MODE = process.env.NODE_ENV === 'development';
    if (DEBUG_MODE) {
      self.addEventListener('activate', (event) => {
        console.log('[SW] 激活事件:', event);
      });
    }

⚠️ 注意事项

  1. 作用域限制

    确保 Service Worker 文件位于网站根目录或子目录,且作用域能覆盖目标请求路径。

  2. HTTPS 要求

    生产环境必须使用 HTTPS(本地开发可通过 localhost 使用)。

  3. 更新机制

    修改 Service Worker 后需重新编译并刷新页面,或调用 registration.update()

  4. 文件哈希

    建议为编译后的 Service Worker 文件添加哈希值(如 sw.[hash].js)以避免缓存问题。

相关推荐
又又呢1 小时前
前端面试题总结——webpack篇
前端·webpack·node.js
dog shit2 小时前
web第十次课后作业--Mybatis的增删改查
android·前端·mybatis
我有一只臭臭2 小时前
el-tabs 切换时数据不更新的问题
前端·vue.js
七灵微2 小时前
【前端】工具链一本通
前端
Nueuis3 小时前
微信小程序前端面经
前端·微信小程序·小程序
_r0bin_5 小时前
前端面试准备-7
开发语言·前端·javascript·fetch·跨域·class
IT瘾君5 小时前
JavaWeb:前端工程化-Vue
前端·javascript·vue.js
potender5 小时前
前端框架Vue
前端·vue.js·前端框架
站在风口的猪11086 小时前
《前端面试题:CSS预处理器(Sass、Less等)》
前端·css·html·less·css3·sass·html5
程序员的世界你不懂6 小时前
(9)-Fiddler抓包-Fiddler如何设置捕获Https会话
前端·https·fiddler