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

相关推荐
你的人类朋友11 分钟前
❤️‍🔥BFF架构版的hello world
前端·后端·架构
德育处主任12 分钟前
p5.js 三角形triangle的用法
前端·数据可视化·canvas
有事没事实验室25 分钟前
node.js中的path模块
前端·css·node.js·html·html5
十盒半价36 分钟前
TypeScript + React:大型项目开发的黄金搭档
前端·typescript·trae
楚轩努力变强1 小时前
前端工程化常见问题总结
开发语言·前端·javascript·vue.js·visual studio code
鱼樱前端1 小时前
rust基础二(闭包)
前端·rust
菜鸟学Python2 小时前
Python web框架王者 Django 5.0发布:20周年了!
前端·数据库·python·django·sqlite
前端开发爱好者2 小时前
只有 7 KB!前端圈疯传的 Vue3 转场动效神库!效果炸裂!
前端·javascript·vue.js
pe7er2 小时前
RESTful API 的规范性和接口安全性如何取舍
前端·后端
Fly-ping2 小时前
【前端】JavaScript文件压缩指南
开发语言·前端·javascript