PWA 开发中有哪些常用的工具和框架?如何使用它们?
PWA 的开发需要使用一系列工具和框架来提高开发效率和代码质量。以下是常用的 PWA 开发工具和框架:核心开发工具1. WorkboxWorkbox 是 Google 提供的 PWA 开发工具集,简化了 Service Worker 的开发。安装npm install workbox-cli --globalnpm install workbox-webpack-plugin --save-dev使用 Workbox CLI# 生成 Service Workerworkbox generateSW workbox-config.js# 预缓存文件workbox wizardWorkbox 配置// workbox-config.jsmodule.exports = { globDirectory: 'dist/', globPatterns: [ '**/*.{html,js,css,png,jpg,jpeg,svg,woff,woff2}' ], swDest: 'dist/sw.js', runtimeCaching: [ { urlPattern: /^https:\/\/api\.example\.com\/.*/, handler: 'NetworkFirst', options: { cacheName: 'api-cache', expiration: { maxEntries: 100, maxAgeSeconds: 30 * 24 * 60 * 60 // 30 days } } }, { urlPattern: /\.(?:png|jpg|jpeg|svg|gif)$/, handler: 'CacheFirst', options: { cacheName: 'image-cache', expiration: { maxEntries: 60, maxAgeSeconds: 60 * 24 * 60 * 60 // 60 days } } } ]};在 Webpack 中使用 Workbox// webpack.config.jsconst { GenerateSW } = require('workbox-webpack-plugin');module.exports = { plugins: [ new GenerateSW({ clientsClaim: true, skipWaiting: true, runtimeCaching: [ { urlPattern: /\.(?:png|jpg|jpeg|svg)$/, handler: 'CacheFirst', options: { cacheName: 'images', expiration: { maxEntries: 60 } } } ] }) ]};2. PWA BuilderPWA Builder 是 Microsoft 提供的工具,可以将 PWA 打包为原生应用。# 安装 PWA Builder CLInpm install -g pwabuilder# 打包应用pwabuilder package3. LighthouseLighthouse 是 Google 提供的网站性能和质量审计工具。# 安装 Lighthousenpm install -g lighthouse# 运行审计lighthouse https://your-pwa.com --view使用 Lighthouse CI# 安装 Lighthouse CInpm install -g @lhci/cli# 初始化配置lhci autorun# 运行 CIlhci autorun --collect.url=https://your-pwa.com框架和库1. React PWACreate React App# 创建 PWA 项目npx create-react-app my-pwa --template cra-template-pwa使用 React PWA// src/serviceWorkerRegistration.jsexport function register(config) { if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); if (publicUrl.origin !== window.location.origin) return; window.addEventListener('load', () => { const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; registerValidSW(swUrl, config); }); }}2. Vue PWAVue CLI PWA 插件# 创建 PWA 项目vue create my-pwa# 选择 PWA 插件配置 vue.config.js// vue.config.jsmodule.exports = { pwa: { name: 'My PWA', themeColor: '#4DBA87', msTileColor: '#000000', appleMobileWebAppCapable: 'yes', appleMobileWebAppStatusBarStyle: 'black', workboxPluginMode: 'GenerateSW', workboxOptions: { runtimeCaching: [ { urlPattern: /\.(?:png|jpg|jpeg|svg)$/, handler: 'CacheFirst', options: { cacheName: 'images', expiration: { maxEntries: 60 } } } ] } }};3. Angular PWA# 添加 PWA 支持ng add @angular/pwa配置 ngsw-config.json{ "$schema": "./node_modules/@angular/service-worker/config/schema.json", "index": "/index.html", "assetGroups": [ { "name": "app", "installMode": "prefetch", "resources": { "files": [ "/favicon.ico", "/index.html", "/manifest.webmanifest", "/*.css", "/*.js" ] } }, { "name": "assets", "installMode": "lazy", "updateMode": "prefetch", "resources": { "files": [ "/assets/**", "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)" ] } } ], "dataGroups": [ { "name": "api-freshness", "urls": [ "/api/**" ], "cacheConfig": { "maxSize": 100, "maxAge": "3d", "timeout": "10s", "strategy": "freshness" } } ]}开发工具1. Chrome DevToolsService Worker 调试// 在 DevTools Console 中// 查看所有 Service Workernavigator.serviceWorker.getRegistrations().then(registrations => { registrations.forEach(registration => { console.log('SW:', registration); });});// 取消注册 Service Workernavigator.serviceWorker.getRegistrations().then(registrations => { registrations.forEach(registration => { registration.unregister(); });});Application 面板Service Workers:查看和管理 Service WorkerCache Storage:查看和管理缓存Manifest:查看和验证 Manifest 文件Background Services:查看后台服务状态2. React DevTools# 安装 React DevToolsnpm install --save-dev react-devtools3. Vue DevTools# 安装 Vue DevToolsnpm install --save-dev @vue/devtools测试工具1. Jest// sw.test.jsdescribe('Service Worker', () => { beforeEach(() => { return navigator.serviceWorker.register('/sw.js'); }); test('should cache static assets', async () => { const cache = await caches.open('static-cache'); const response = await cache.match('/styles/main.css'); expect(response).toBeDefined(); });});2. Cypress// cypress/integration/pwa.spec.jsdescribe('PWA', () => { it('should work offline', () => { cy.visit('/'); // 模拟离线 cy.window().then((win) => { win.navigator.serviceWorker.controller.postMessage({ type: 'OFFLINE' }); }); // 验证离线功能 cy.contains('Offline').should('be.visible'); });});3. Puppeteer// test-pwa.jsconst puppeteer = require('puppeteer');(async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); // 检查 Service Worker await page.goto('https://your-pwa.com'); const sw = await page.evaluate(() => { return navigator.serviceWorker.getRegistration(); }); console.log('Service Worker:', sw); await browser.close();})();构建工具1. Webpack// webpack.config.jsconst { InjectManifest } = require('workbox-webpack-plugin');const CopyWebpackPlugin = require('copy-webpack-plugin');const WebpackPwaManifest = require('webpack-pwa-manifest');module.exports = { plugins: [ new CopyWebpackPlugin({ patterns: [ { from: 'public/manifest.json', to: 'manifest.json' } ] }), new WebpackPwaManifest({ name: 'My PWA', short_name: 'MyPWA', description: 'My Progressive Web App', background_color: '#ffffff', theme_color: '#4DBA87', icons: [ { src: 'src/assets/icon.png', sizes: [96, 128, 192, 256, 384, 512], destination: 'icons' } ] }), new InjectManifest({ swSrc: './src/sw.js', swDest: 'sw.js' }) ]};2. Vite// vite.config.jsimport { VitePWA } from 'vite-plugin-pwa';export default { plugins: [ VitePWA({ registerType: 'autoUpdate', includeAssets: ['favicon.ico', 'apple-touch-icon.png'], manifest: { name: 'My PWA', short_name: 'MyPWA', description: 'My Progressive Web App', theme_color: '#ffffff', icons: [ { src: 'pwa-192x192.png', sizes: '192x192', type: 'image/png' }, { src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png' } ] }, workbox: { runtimeCaching: [ { urlPattern: /^https:\/\/api\.example\.com\/.*/, handler: 'NetworkFirst', options: { cacheName: 'api-cache', expiration: { maxEntries: 100, maxAgeSeconds: 30 * 24 * 60 * 60 } } } ] } }) ]};部署工具1. Netlify# netlify.toml[[headers]] for = "/*" [headers.values] X-Frame-Options = "DENY" X-XSS-Protection = "1; mode=block" Content-Security-Policy = "default-src 'self'"[[redirects]] from = "/*" to = "/index.html" status = 2002. Vercel// vercel.json{ "headers": [ { "source": "/(.*)", "headers": [ { "key": "X-Frame-Options", "value": "DENY" }, { "key": "X-XSS-Protection", "value": "1; mode=block" } ] } ], "rewrites": [ { "source": "/(.*)", "destination": "/index.html" } ]}3. Firebase Hosting// firebase.json{ "hosting": { "public": "dist", "headers": [ { "source": "**/*.@(eot|otf|ttf|ttc|woff|font.css)", "headers": [ { "key": "Cache-Control", "value": "public, max-age=31536000" } ] } ], "rewrites": [ { "source": "**", "destination": "/index.html" } ] }}监控和分析1. Google Analytics// 在 Service Worker 中跟踪self.addEventListener('fetch', event => { if (navigator.sendBeacon) { navigator.sendBeacon('/analytics', JSON.stringify({ url: event.request.url, timestamp: Date.now() })); }});2. Sentry// 在 Service Worker 中捕获错误self.addEventListener('error', event => { Sentry.captureException(event.error);});self.addEventListener('unhandledrejection', event => { Sentry.captureException(event.reason);});最佳实践使用 Workbox:简化 Service Worker 开发自动化测试:使用 Jest、Cypress 等工具性能监控:使用 Lighthouse 定期审计错误追踪:使用 Sentry 等工具CI/CD 集成:自动化构建和部署代码分割:使用 Webpack、Vite 等工具缓存策略:根据资源类型选择合适的策略渐进增强:确保在不支持 PWA 的浏览器中正常工作