在 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)以避免缓存问题。

相关推荐
apcipot_rain4 分钟前
【应用密码学】实验五 公钥密码2——ECC
前端·数据库·python
ShallowLin9 分钟前
vue3学习——组合式 API:生命周期钩子
前端·javascript·vue.js
Nejosi_念旧30 分钟前
Vue API 、element-plus自动导入插件
前端·javascript·vue.js
互联网搬砖老肖31 分钟前
Web 架构之攻击应急方案
前端·架构
pixle01 小时前
Vue3 Echarts 3D饼图(3D环形图)实现讲解附带源码
前端·3d·echarts
麻芝汤圆2 小时前
MapReduce 入门实战:WordCount 程序
大数据·前端·javascript·ajax·spark·mapreduce
juruiyuan1113 小时前
FFmpeg3.4 libavcodec协议框架增加新的decode协议
前端
Peter 谭4 小时前
React Hooks 实现原理深度解析:从基础到源码级理解
前端·javascript·react.js·前端框架·ecmascript
LuckyLay5 小时前
React百日学习计划——Deepseek版
前端·学习·react.js
gxn_mmf5 小时前
典籍知识问答重新生成和消息修改Bug修改
前端·bug