十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Angular Service Worker 入门实战:ng add @angular/pwa、离线缓存机制与 SwRegistrationOptions 全解

Angular Service Worker 入门实战:ng add @angular/pwa、离线缓存机制与 SwRegistrationOptions 全解 Angular Service Worker 入门实战ng add angular/pwa、离线缓存机制与 SwRegistrationOptions 全解【免费下载链接】angularDeliver web apps with confidence 项目地址: https://gitcode.com/GitHub_Trending/an/angular本文基于 Angular 官方文档《Getting started with service workers》完整讲解如何在 Angular 项目中启用 Service Worker、如何在本地验证离线加载与版本更新流程以及SwRegistrationOptions各注册选项的精细配置。读完本文你将掌握从ng add angular/pwa一键接入到断网测试、缓存资源分析、后台更新切换的完整实战链路并能结合源码理解注册时机、注册策略解析与缓存策略ngsw-config.json背后的实现机制。一、为项目添加 Service Worker在 Angular 项目中启用 Service Worker 支持只需执行一条 Angular CLI 命令ng add angular/pwaCLI 会完成以下配置动作引自文档 getting-started向项目添加angular/service-worker包在 CLI 中启用 Service Worker 构建支持在应用根 provider 中导入并注册 Service Worker对应provideServiceWorker(...)调用更新index.html加入指向manifest.webmanifest文件的链接添加theme-color元标签安装图标文件以支持已安装的 PWAProgressive Web App创建 Service Worker 配置文件ngsw-config.json其中指定缓存行为及其他设置。该文件的完整结构定义见仓库中的 JSON Schemapackages/service-worker/config/schema.json。配置完成后执行构建ng build此时 CLI 项目即已具备使用 Angular Service Worker 的能力。从源码结构看angular/service-worker的运行时代码位于 packages/service-worker/src 目录worker 侧实现位于 packages/service-worker/worker 目录。ng add angular/pwa生成的provideServiceWorker(ngsw-worker.js, ...)调用最终绑定到该包中的provideServiceWorker函数其定义见 provider.tsexport function provideServiceWorker( script: string, options: SwRegistrationOptions {}, ): EnvironmentProviders { return makeEnvironmentProviders([ SwPush, SwUpdate, {provide: SCRIPT, useValue: script}, {provide: SwRegistrationOptions, useValue: options}, { provide: NgswCommChannel, useFactory: ngswCommChannelFactory, }, provideAppInitializer(ngswAppInitializer), ]); }可以看到provideServiceWorker一次性注册了SwPush、SwUpdate两个服务、SCRIPT脚本路径、注册选项并通过provideAppInitializer(ngswAppInitializer)把注册逻辑挂到应用初始化阶段——这就是CLI 只需改根 provider 即可生效的底层原因。二、本地开发时运行带 Service Worker 的应用开发服务器ng serve默认 development 配置不启用 Service Worker。要在本地开发阶段验证需要使用 production 配置启动ng serve --configurationproduction或者使用支持 Service Worker 应用的http-servernpm 包无需安装直接运行npx http-server -p 8080 -c-1 dist/project-name/browser该命令会在http://localhost:8080提供带 Service Worker 支持的应用。-c-1参数关闭静态资源的 HTTP 缓存避免浏览器缓存干扰 Service Worker 缓存测试。三、实战演练Service Worker 的工作过程3.1 首次加载服务器运行在8080端口后用浏览器访问http://localhost:8080应用应正常加载。提示测试 Angular Service Worker 时建议使用浏览器的隐身/隐私窗口确保 Service Worker 不会读到上一次测试遗留的状态从而避免意外行为。注意如果不使用 HTTPSService Worker 只在通过localhost访问应用时才会被注册。3.2 模拟断网为了模拟网络问题需要禁用应用的网络交互。以 Chrome 为例选择ToolsDeveloper Tools位于右上角 Chrome 菜单中进入Network标签页在Throttling下拉菜单中选择Offline。此时应用不再有任何网络访问能力。对于未启用 Angular Service Worker 的应用此时刷新页面会显示 Chrome 的没有网络连接断开提示页。而加入 Angular Service Worker 之后行为发生了变化刷新后页面照常加载。可以在 Network 标签页验证 Service Worker 已处于激活状态。Size 列下请求的状态显示为(ServiceWorker)意味着这些资源并非来自网络而是从 Service Worker 的缓存中加载的。3.3 哪些资源被缓存了注意观察浏览器渲染该应用所需的所有文件都已被缓存。ngsw-config.json的默认boilerplate配置会缓存 CLI 用到的具体资源index.htmlfavicon.ico构建产物JS 与 CSS bundleassets目录下的任何内容直接位于配置的outputPath默认./dist/project-name/或resourcesOutputPath下的图片与字体重要生成的ngsw-config.json只包含一份有限的可缓存字体与图片扩展名列表某些情况下你可能需要修改 glob 模式以适配自身需求。重要如果在配置文件生成之后修改了resourcesOutputPath或assets路径需要在ngsw-config.json中手动同步修改这些路径。从 Schema 定义可以确认ngsw-config.json中描述缓存哪些文件的字段是assetGroups[*].resources.files匹配发行目录中的文件或 glob 模式而运行时匹配的 URL 模式则放在assetGroups[*].resources.urls中见 schema.json。3.4 修改应用并观察更新了解缓存机制后下一步是理解更新如何发生。对应用做一次修改然后观察 Service Worker 安装更新如果是在隐身窗口中测试先打开一个空白新标签页。这样在测试期间可以保持隐身窗口及缓存状态存活关闭应用标签页但不要关闭窗口开发者工具也会随之关闭停止http-serverCtrl-c打开src/app/app.component.html进行编辑将文本Welcome to {{title}}!改为Bienvenue à {{title}}!重新构建并启动服务器ng build npx http-server -p 8080 -c-1 dist/project-name/browser3.5 浏览器如何应用更新现在观察浏览器和 Service Worker 如何处理更新后的应用在同一个窗口中再次打开http://localhost:8080会发生什么页面仍然显示旧文案Welcome to ...。这其实没有问题Angular Service Worker 正在履行职责即使服务器上已有新版本它提供的仍然是已安装的那个版本。出于速度考量Service Worker 不会在提供应用之前阻塞等待检查更新。查看http-server日志可以看到 Service Worker 请求了/ngsw.json[2023-09-07T00:37:24.372Z] GET /ngsw.json?ngsw-cache-bust0.9365263935102124 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36这就是 Service Worker 检查更新的方式——ngsw.json是构建时生成的版本清单带ngsw-cache-bust随机查询参数以避免被 HTTP 缓存挡住。刷新页面。文案已变为Bienvenue à ...。Service Worker 在后台安装了应用的更新版本下一次页面加载或刷新时Service Worker 就会切换到最新版本。从源码看这套后台安装、下次切换机制有明确的实现支撑。在 provider.ts 中ngswAppInitializer在controllerchange事件新 worker 接管控制权上会向 worker 发送{action: INITIALIZE}消息且监听器通过ngZone.runOutsideAngular注册在 Zone 之外避免无谓的变更检测。而应用与 worker 之间的所有消息通信版本事件、操作回执都封装在 NgswCommChannel 中它基于Subject转发versionUpdates事件VERSION_DETECTED、VERSION_READY等并提供postMessageWithOperation这样的请求-回执nonce 匹配机制。controllerchange事件正是 3.5 节中刷新后切换到新版本时由浏览器触发的。四、Service Worker 注册配置SwRegistrationOptions 详解Angular Service Worker 通过SwRegistrationOptions接口提供全面的配置选项对注册行为、缓存与脚本执行提供细粒度控制。该抽象类的完整定义含每个选项的默认值与 JSDoc 说明见 provider.ts。4.1 enabled启用与禁用 Service Workerenabled选项控制 Service Worker 是否会被注册以及相关服务SwPush、SwUpdate是否会尝试与其通信。默认值为true。import {ApplicationConfig, isDevMode} from angular/core; import {provideServiceWorker} from angular/service-worker; export const appConfig: ApplicationConfig { providers: [ provideServiceWorker(ngsw-worker.js, { enabled: !isDevMode(), // 开发环境禁用生产环境启用 }), ], };源码中对应的判断逻辑在 ngswAppInitializerif (typeof ngServerMode ! undefined ngServerMode) { return; // SSR 环境下直接跳过注册 } const options inject(SwRegistrationOptions); if (!(serviceWorker in navigator options.enabled ! false)) { return; }这意味着enabled: false时模块的行为与浏览器不支持 Service Worker一致且相关服务在浏览器端收到的是Service workers are disabled or not supported by this browser错误事件错误码与文案定义于 low_level.ts 中的ERR_SW_NOT_SUPPORTED。4.2 updateViaCache更新时的 HTTP 缓存控制updateViaCache选项控制浏览器在 Service Worker 更新时如何咨询 HTTP 缓存从而精细控制何时真正从网络拉取更新的 Service Worker 脚本及其导入模块。export const appConfig: ApplicationConfig { providers: [ provideServiceWorker(ngsw-worker.js, { enabled: !isDevMode(), updateViaCache: imports, }), ], };可选值imports对 Service Worker 脚本导入的脚本会咨询 HTTP 缓存但对 Service Worker 脚本本身不咨询all对 Service Worker 脚本及其导入的脚本都咨询 HTTP 缓存none对 Service Worker 脚本及其导入的脚本都不咨询 HTTP 缓存。4.3 typeES Module 支持type选项在注册 Service Worker 时指定脚本类型为 Service Worker 脚本提供 ES Module 特性支持。export const appConfig: ApplicationConfig { providers: [ provideServiceWorker(ngsw-worker.js, { enabled: !isDevMode(), type: module, // 启用 ES Module 特性 }), ], };可选值classic默认传统 Service Worker 脚本执行方式脚本中不允许使用import、export等 ES Module 特性module将脚本注册为 ES Module允许使用import/export语法及模块特性。4.4 scope注册作用域控制scope选项定义 Service Worker 的注册作用域即它能够控制的 URL 范围。export const appConfig: ApplicationConfig { providers: [ provideServiceWorker(ngsw-worker.js, { enabled: !isDevMode(), scope: /app/, // Service Worker 只控制 /app/ 之下的 URL }), ], };控制 Service Worker 可以拦截并管理的 URL 范围默认为 Service Worker 脚本所在目录该值在调用ServiceWorkerContainer.register()时使用。4.5 registrationStrategy注册时机策略registrationStrategy选项定义 Service Worker 何时向浏览器注册控制注册的时机。export const appConfig: ApplicationConfig { providers: [ provideServiceWorker(ngsw-worker.js, { enabled: !isDevMode(), registrationStrategy: registerWhenStable:30000, }), ], };可用的注册策略registerWhenStable:timeout默认registerWhenStable:30000——应用一旦稳定没有待处理的微/宏任务就立即注册但最迟不超过指定的毫秒超时时间registerImmediately——立即注册registerWithDelay:timeout——延迟指定毫秒数后注册。更多示例// 立即注册 export const immediateConfig: ApplicationConfig { providers: [ provideServiceWorker(ngsw-worker.js, { enabled: !isDevMode(), registrationStrategy: registerImmediately, }), ], }; // 延迟 5 秒注册 export const delayedConfig: ApplicationConfig { providers: [ provideServiceWorker(ngsw-worker.js, { enabled: !isDevMode(), registrationStrategy: registerWithDelay:5000, }), ], };也可以提供一个 Observable 工厂函数来自定义注册时机import {timer} from rxjs; export const customConfig: ApplicationConfig { providers: [ provideServiceWorker(ngsw-worker.js, { enabled: !isDevMode(), registrationStrategy: () timer(10_000), // 10 秒后注册 }), ], };源码中该策略字符串的解析过程印证了文档描述provider.tsconst {registrationStrategy} options; if (typeof registrationStrategy function) { readyToRegister new Promise((resolve) registrationStrategy().subscribe(() resolve())); } else { const [strategy, ...args] (registrationStrategy || registerWhenStable:30000).split(:); switch (strategy) { case registerImmediately: readyToRegister Promise.resolve(); break; case registerWithDelay: readyToRegister delayWithTimeout(args[0] || 0); break; case registerWhenStable: readyToRegister Promise.race([appRef.whenStable(), delayWithTimeout(args[0])]); break; default: throw new RuntimeError(RuntimeErrorCode.UNKNOWN_REGISTRATION_STRATEGY, ...); } }两个值得注意的实现细节整个注册流程包在ngZone.runOutsideAngular中执行源码注释明确说明原因——避免阻止应用达到稳定态尤其是某些注册策略本身就在等待应用稳定这解释了为什么registerWhenStable不会因注册动作自身而死锁注册调用把scope、updateViaCache、type三个选项原样透传给浏览器 APInavigator.serviceWorker.register(script, {scope, updateViaCache, type})provider.ts注册失败时通过console.error打印格式化运行时错误不会抛出未捕获的 Promise rejection。五、ngsw-config.json构建期缓存策略Schema 视角第四节讲的是运行时注册配置而ngsw-config.json描述的是构建期缓存策略。它由构建工具读取最终生成 3.5 节中 Service Worker 用来校验版本的ngsw.json。仓库中的 JSON Schemapackages/service-worker/config/schema.json定义了全部可用字段关键项如下index必填作为导航请求响应所用 index 页的文件通常是/index.htmlassetGroups随应用版本一起更新的应用资源组。核心字段installModeprefetch默认安装时预取所有列出的资源带宽消耗大但随时可用或lazy按需缓存只有收到请求才缓存updateMode发现新版本时对组内已变更资源的更新方式取值同为prefetch/lazy默认继承installModeresources.files/resources.urls前者匹配发行目录中的文件支持 glob后者是运行时匹配的 URL 模式例如 CDN 上的 Google Fonts按 HTTP 头缓存且不做内容哈希cacheQueryOptions.ignoreSearch匹配缓存时是否忽略 URL 查询串dataGroupsAPI 等数据请求的缓存策略。与资源不同数据请求不随应用版本更新。核心字段urls匹配的 URL 模式列表version整数默认1。当 API 发生不向后兼容的格式变更时提升该值使旧缓存条目被丢弃cacheConfigmaxSize与maxAge必填maxSize缓存最大条目数maxAge响应保留的有效期时长字符串单位为d天、h小时、m分钟、s秒、u毫秒例如3d12h为三天半timeout网络超时时长超时后回退到缓存响应refreshAhead在缓存过期前提前多久主动从网络刷新资源strategyperformance默认缓存优先允许一定陈旧度或freshness网络优先仅在超时后回退缓存cacheOpaqueResponses是否缓存不透明响应performance策略默认falsefreshness策略默认truenavigationUrls可选的自定义 URL 模式列表这些 URL 会被重定向到index文件navigationRequestStrategyperformance默认导航请求走缓存或freshness所有导航请求强制走网络applicationMaxAge整个应用可保留在缓存中的最长时间超时后视为失效并被绕过时长字符串格式同上appData任意自定义数据会随版本一起下发SwUpdate服务的更新通知中会携带这些字段常用于在更新弹窗中展示版本说明。六、进一步深入在掌握本文入门内容后可结合仓库中的以下源码继续深入packages/service-worker/src/update.tsSwUpdate服务实现消费VERSION_DETECTED、VERSION_READY等版本事件用于应用内检测并应用更新packages/service-worker/src/push.tsSwPush服务实现处理推送订阅与推送消息对应文档体系中的与 Service Worker 通信 / 推送通知主题packages/service-worker/src/low_level.tsNgswCommChannel完整实现含UnrecoverableStateEvent不可恢复状态需要整页刷新等事件类型定义packages/service-worker/config/schema.jsonngsw-config.json的完整 Schema用于在编辑器中获得配置项补全与校验packages/service-worker/PACKAGE.mdangular/service-worker包的说明文档。此外ngsw-config.json在构建时的解析与校验实现位于 packages/service-worker/config/src集成测试示例可参考 integration/service-worker-schema 目录。【免费下载链接】angularDeliver web apps with confidence 项目地址: https://gitcode.com/GitHub_Trending/an/angular创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表