如何在 Angular 应用程序(Angular 7)中添加 Service Worker
引言
Service workers 是一种很实用的技术,能够帮助我们创建离线可访问的 Web 应用程序。Service workers 允许您的 Web 应用程序发送推送通知、在后台运行脚本以及管理事务。在这篇文章中,我们将全面了解如何在 Angular 7 应用程序中添加 Service Worker。
- 简介
Service workers 是一个网页环境的小型的 JavaScript 程序,可以在后台执行一些任务,比如消息推送、网络请求、后台运行等。Service workers 应用程序运行在自己的进程中,拥有更高的可靠性和更快的响应速度。
Service workers 还自带缓存 API,可以实现离线存取,压缩请求,加速响应。
- 安装 Angular Service Worker 相关依赖
首先,你需要安装 Angular Service Worker 及其所需的库,你可以通过以下命令:
npm install --save @angular/service-worker
在你的 Angular 应用程序中,为了使用 Service Worker,你还需要安装 @angular/pwa:
ng add @angular/pwa
这个命令执行后,会将 Angular 服务工人集成到你的应用程序中,准备离线支持等功能。
- 配置 Angular Service Worker
安装依赖后,您需要在 Angular 应用程序中配置 Service Worker。开发人员可以使用 Angular CLI 来生成一个默认的设置。为此,您需要使用以下命令:
ng set apps.0.serviceWorker=true
这将自动将 Service Worker 安装并启用在你的应用中。服务工人默认从一个名为 ngsw-config.json 的 JSON 配置文件读取配置。
ngsw-config.json 是配置你 ServiceWorker 的重要文件,需要配置 cache 模式,如果需要新增一些缓存,可以继续添加 cache ,具体示例代码如下所示:
{ "$schema": "./node_modules/@angular/service-worker/config/schema.json", "index": "/index.html", "assetGroups": [ { "name": "app", "installMode": "prefetch", "resources": { "files": [ "/favicon.ico", "/*.css", "/*.js", "/*.jpg", "/*.png", "/*.svg" ], "urls": [ "https://fonts.googleapis.com/css?family=Roboto:300,400,500", "https://fonts.googleapis.com/icon?family=Material+Icons", "https://fonts.gstatic.com/s/roboto/v18/KFOmCnqEu92Fr1Mu4mxP.ttf", "https://fonts.gstatic.com/s/materialicons/v41/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2" ] } }, { "name": "assets", "installMode": "lazy", "updateMode": "prefetch", "resources": { "files": [ "/assets/**" ] } } ...
由于限制篇幅,这里不再赘述每个参数的含义,具体可以参考 Angular 官方文档。
- 编写 Angular Service Worker
接下来是我们希望你们最喜欢的部分,写代码! 这里我们将提供以下示例代码,展示如何读取 Service Worker,为 Worker 添加 push 消息及缓存操作等。
angular-register-sw
import { Component, OnInit } from '@angular/core'; import { SwUpdate } from '@angular/service-worker'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit { title = 'angular-sw'; message!: string; updateAvailable: boolean = false; constructor(private swUpdate: SwUpdate) { } ngOnInit(): void { this.updateAvailable = this.swUpdate.isEnabled; if (this.updateAvailable) { this.swUpdate.available.subscribe(() => { const updateMessage = '新版本可用,是否重新加载?'; if (confirm(updateMessage)) { window.location.reload(); } }); } navigator.serviceWorker.addEventListener('message', event => { this.message = (event.data as any).message || 'no message'; }); } sendMessage() { navigator.serviceWorker.controller?.postMessage({ type: 'CLIENT_MESSAGE', message: `Hello from the client! (${new Date().toISOString()})` }); } }
sw.js
const CACHE_NAME = 'mycache'; const CACHE_VERSION = 1; const CACHE_PRIORITY = ['api', 'material', 'scss']; const API_CACHE_NAME = 'netflixcoin'; const API_CACHE_REGEX = [/collection/, /coin/]; // Install our PWA self.addEventListener('install', event => { console.log('Installing...'); event.waitUntil( caches.open(CACHE_NAME).then(cache => { cache.addAll([ '/', '/index.html', '/favicon.ico', ]); }) ); }); // On activate, delete old caches and log version self.addEventListener('activate', event => { console.log('Activating...'); event.waitUntil( caches.keys().then(keys => Promise.all([ keys.forEach(key => { if (key !== CACHE_NAME) caches.delete(key); console.log(`Caches deleted: ${key}`); }) ])).then(() => { console.log(`Service worker v${CACHE_VERSION} activated.`); }) ); }); // Background fetch self.addEventListener('backgroundfetchsuccess', async event => { console.log('Background fetch successful.'); const cache = await caches.open(API_CACHE_NAME); // Filter downloaded content with regex const matching = new RegExp(API_CACHE_REGEX.join('|')); const filteredRecords = event.fetches.filter(fetch => matching.test(fetch.request.url)); const results = await Promise.all(filteredRecords.map(record => record.responseReady)); await cache.addAll(results.map(r => new Response(r.body, r))); event.waitUntil( self.registration.showNotification(`Updates Available`, { body: `Downloaded ${results.length} items!`, data: 'backgroundFetch' }) ); }); self.addEventListener('backgroundfetchfail', event => { console.log('Background Fetch failed:', event); }); self.addEventListener('backgroundfetchabort', event => { console.log('Background Fetch failed:', event); }); self.addEventListener('backgroundfetchclick', event => { console.log('Background fetch notification clicked:', event); event.waitUntil( clients.matchAll({ type: 'window' }).then(clientList => { // If there is already a YouTube tab, navigate to that page. // Otherwise, open a new tab with the video. for (let i = 0; i < clientList.length; i++) { const client = clientList[i]; // If we already have a window open to the site, focus it. if (client.url === 'http://127.0.0.1:8080/') { return client.focus(); } } return clients.openWindow('/'); }) ); }); self.addEventListener('push', async event => { console.log('Push received', event.data.text()); const client = await self.clients.get(event.source.id); const payload = JSON.parse(event.data.text()); if (payload && client) { client.postMessage({ message: payload.message }); } }); // Listen for incoming messages from clients self.addEventListener('message', async event => { if (event.data && event.data.type === 'CLIENT_MESSAGE') { console.log('[Service Worker] Message received:', event.data.message); event.waitUntil( self.registration.showNotification('Title', { body: event.data.message, tag: 'new-message' }) ); } }); // Respond with cached resources self.addEventListener('fetch', event => { const cachePriority = CACHE_PRIORITY.findIndex(c => event.request.url.match(c)); event.respondWith( caches.match(event.request).then(response => { const freshResource = fetch(event.request).then(response => { const responseClone = response.clone(); caches.open(CACHE_NAME).then(cache => { cache.put(event.request, responseClone); }); return response; }); // Return cached resource or otherwise fresh resource return response || freshResource.catch(() => console.log('Error retrieving resource')); }) ); });
- 运行你的 Angular Service Worker 应用程序
在添加了 Service Worker 后,你需要运行搭建程序来检查是否正常运作。可以使用以下命令运行程序:
ng serve --open
Service worker 相关的 code 最后会被编译到 sw.js 文件,其中的 listeners会随着service worker 程序的运行而启动。
- 总结
以上就
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65b613a2add4f0e0ffec6851