各位老铁,晚上好!今儿个咱们聊聊 Vue CLI 里的 plugin-pwa
,看看它怎么把 Workbox 这玩意儿给安排上,给咱们的 Vue 应用整个 PWA,让它离线也能浪起来。咱可不是光说不练的主儿,代码伺候!
开场白:PWA 是个啥?Workbox 又是个啥?
先来个热身运动,简单说说 PWA 和 Workbox。
- PWA (Progressive Web App): 这玩意儿就是想让你的 Web 应用像 Native App 一样丝滑。离线访问、推送通知、添加到桌面,这些都是它的拿手好戏。
- Workbox: 这是 Google 出的工具箱,专门用来简化 Service Worker 的开发。有了它,你就不用手撸复杂的 Service Worker 代码了,配置一下就能搞定缓存策略、离线支持等等。
Vue CLI plugin-pwa
:PWA 的好帮手
Vue CLI 的 plugin-pwa
就像个贴心的管家,帮你把 PWA 的基础设施都安排好了。它主要做了以下几件事:
- 生成 Service Worker: 自动生成一个 Service Worker 文件(通常是
service-worker.js
或registerServiceWorker.js
),负责处理离线缓存、资源更新等逻辑。 - 集成 Workbox: 使用 Workbox 来管理 Service Worker 的缓存策略,简化开发流程。
- 注册 Service Worker: 在你的 Vue 应用中注册 Service Worker,让它开始工作。
- 生成 Manifest 文件: 生成
manifest.json
文件,定义 PWA 的元数据,比如应用名称、图标、启动画面等等。
源码分析:plugin-pwa
是怎么玩转 Workbox 的?
咱们现在就来深入源码,看看 plugin-pwa
到底是怎么把 Workbox 集成进来的。
1. 安装和配置
当你使用 Vue CLI 创建项目并选择安装 plugin-pwa
时,它会做以下事情:
-
安装依赖: 安装
workbox-webpack-plugin
和register-service-worker
这两个关键的 npm 包。workbox-webpack-plugin
:在 Webpack 打包过程中生成 Service Worker 文件,并配置缓存策略。register-service-worker
:一个简单的库,用于在你的 Vue 应用中注册 Service Worker。
-
修改
vue.config.js
: 在你的vue.config.js
文件中添加pwa
配置项,用于自定义 PWA 的行为。// vue.config.js module.exports = { pwa: { name: 'My Awesome PWA', // 应用名称 themeColor: '#4DBA87', // 主题颜色 msTileColor: '#000000', appleMobileWebAppCapable: 'yes', appleMobileWebAppStatusBarStyle: 'black', // configure the workbox plugin workboxPluginMode: 'GenerateSW', // 或 InjectManifest workboxOptions: { // swSrc: 'src/service-worker.js', // 如果使用 InjectManifest,需要指定 Service Worker 文件 // ...其他 Workbox 配置 } } }
2. Workbox 插件模式:GenerateSW
vs InjectManifest
workboxPluginMode
选项决定了 plugin-pwa
如何使用 Workbox。它有两个可选值:
-
GenerateSW
(默认): 这是最简单的模式。Workbox 会自动生成完整的 Service Worker 文件,并根据你的配置自动处理缓存策略。你只需要配置workboxOptions
即可。 -
InjectManifest
: 这个模式更灵活。你需要自己创建一个 Service Worker 文件 (例如src/service-worker.js
),并在其中编写自定义的 Service Worker 逻辑。Workbox 会将你的配置注入到这个文件中。
2.1 GenerateSW
模式
这是最常用的模式,因为它简单易用。
-
配置
workboxOptions
: 你可以通过workboxOptions
对象来配置 Workbox 的行为。例如,你可以指定缓存的文件类型、缓存策略等等。// vue.config.js module.exports = { pwa: { workboxPluginMode: 'GenerateSW', workboxOptions: { skipWaiting: true, // 立即激活新的 Service Worker clientsClaim: true, // 控制 Service Worker 的范围 runtimeCaching: [ // 配置运行时缓存 { urlPattern: new RegExp('https://fonts.(googleapis|gstatic).com/(.*)'), handler: 'CacheFirst', options: { cacheName: 'google-fonts-cache', expiration: { maxEntries: 30, }, cacheableResponse: { statuses: [0, 200] } } }, { urlPattern: /.(png|jpg|jpeg|svg|gif)$/, handler: 'CacheFirst', options: { cacheName: 'images-cache', expiration: { maxEntries: 60, maxAgeSeconds: 30 * 24 * 60 * 60 // 30 Days }, cacheableResponse: { statuses: [0, 200] } } } ] } } }
-
自动生成 Service Worker: 在 Webpack 打包过程中,
workbox-webpack-plugin
会根据你的配置自动生成dist/service-worker.js
文件。这个文件包含了 Workbox 的核心代码和你的缓存策略。 -
Service Worker 内容示例:
dist/service-worker.js
的内容大致如下 (简化版):importScripts("https://storage.googleapis.com/workbox-cdn/releases/6.6.1/workbox-sw.js"); if (workbox) { console.log(`Workbox is loaded`); workbox.routing.registerRoute( new RegExp('https://fonts.(googleapis|gstatic).com/(.*)'), new workbox.strategies.CacheFirst({ cacheName: 'google-fonts-cache', plugins: [ new workbox.expiration.ExpirationPlugin({ maxEntries: 30, }), new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200], }) ] }) ); workbox.routing.registerRoute( /.(png|jpg|jpeg|svg|gif)$/, new workbox.strategies.CacheFirst({ cacheName: 'images-cache', plugins: [ new workbox.expiration.ExpirationPlugin({ maxEntries: 60, maxAgeSeconds: 2592000, }), new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200], }) ] }) ); // 预缓存静态资源 workbox.precaching.precacheAndRoute([ { url: '/index.html', revision: 'YOUR_REVISION' }, { url: '/css/app.css', revision: 'YOUR_REVISION' }, { url: '/js/app.js', revision: 'YOUR_REVISION' }, // ... 其他静态资源 ]); // 其他 Workbox 配置... } else { console.log(`Workbox didn't load`); }
2.2 InjectManifest
模式
如果你需要更精细地控制 Service Worker 的行为,可以使用 InjectManifest
模式。
-
创建 Service Worker 文件: 首先,你需要创建一个 Service Worker 文件,例如
src/service-worker.js
。在这个文件中,你可以编写自定义的 Service Worker 逻辑,比如处理推送通知、后台同步等等。// src/service-worker.js import { precacheAndRoute } from 'workbox-precaching'; import { registerRoute } from 'workbox-routing'; import { CacheFirst } from 'workbox-strategies'; import { CacheableResponsePlugin } from 'workbox-cacheable-response'; import { ExpirationPlugin } from 'workbox-expiration'; // 预缓存静态资源 (使用 webpack 的 definePlugin 注入) precacheAndRoute(self.__WB_MANIFEST); // 缓存 Google Fonts registerRoute( new RegExp('https://fonts.(googleapis|gstatic).com/(.*)'), new CacheFirst({ cacheName: 'google-fonts-cache', plugins: [ new CacheableResponsePlugin({ statuses: [0, 200], }), new ExpirationPlugin({ maxEntries: 30, }), ], }) ); // 自定义推送通知处理 self.addEventListener('push', (event) => { const title = 'My Awesome PWA'; const options = { body: event.data.text(), icon: '/img/icons/android-chrome-192x192.png', }; event.waitUntil(self.registration.showNotification(title, options)); }); // 其他自定义 Service Worker 逻辑...
-
配置
workboxOptions
: 在vue.config.js
中,你需要指定swSrc
选项,告诉 Workbox 你的 Service Worker 文件的路径。// vue.config.js module.exports = { pwa: { workboxPluginMode: 'InjectManifest', workboxOptions: { swSrc: 'src/service-worker.js', // 指定 Service Worker 文件 swDest: 'service-worker.js', // 输出的 Service Worker 文件名 (可选) } } }
-
注入配置: 在 Webpack 打包过程中,
workbox-webpack-plugin
会读取你的src/service-worker.js
文件,并将你的配置注入到这个文件中。例如,它会将预缓存的资源列表注入到self.__WB_MANIFEST
变量中。
3. 注册 Service Worker
plugin-pwa
会在你的 Vue 应用中自动注册 Service Worker。它会创建一个 registerServiceWorker.js
文件,并在你的 main.js
文件中引入它。
-
registerServiceWorker.js
内容:// registerServiceWorker.js import { register } from 'register-service-worker' if (process.env.NODE_ENV === 'production') { register(`${process.env.BASE_URL}service-worker.js`, { ready () { console.log( 'App is being served from cache by a service worker.n' + 'For more details, visit https://goo.gl/AFskqB' ) }, registered () { console.log('Service worker has been registered.') }, cached () { console.log('Content has been cached for offline use.') }, updatefound () { console.log('New content is downloading.') }, updated () { console.log('New content is available; please refresh.') }, offline () { console.log('No internet connection found. App is running in offline mode.') }, error (error) { console.error('Error during service worker registration:', error) } }) }
-
main.js
引入:// main.js import Vue from 'vue' import App from './App.vue' import './registerServiceWorker' // 引入 registerServiceWorker.js Vue.config.productionTip = false new Vue({ render: h => h(App), }).$mount('#app')
缓存策略:Workbox 的核心
Workbox 提供了多种缓存策略,你可以根据你的需求选择合适的策略。
策略 | 描述 | 适用场景 |
---|---|---|
CacheFirst |
首先从缓存中获取资源,如果缓存中没有,则从网络获取,并将资源添加到缓存中。 | 静态资源 (例如图片、字体、CSS、JS 文件),这些资源通常不会频繁更新。 |
NetworkFirst |
首先从网络获取资源,如果网络请求失败,则从缓存中获取。 | 动态资源 (例如 API 请求),这些资源需要保持最新。 |
StaleWhileRevalidate |
首先从缓存中获取资源,同时在后台更新缓存。用户会立即看到缓存中的内容,但下次访问时会看到最新的内容。 | 对实时性要求不高,但希望尽快显示内容的场景 (例如新闻列表)。 |
NetworkOnly |
始终从网络获取资源,不使用缓存。 | 某些特殊的 API 请求,不希望被缓存。 |
CacheOnly |
始终从缓存中获取资源,不访问网络。 | 离线应用或者某些不需要更新的资源。 |
自定义缓存策略
你可以通过 workboxOptions.runtimeCaching
数组来配置自定义的缓存策略。每个元素都代表一个缓存规则,包含以下属性:
urlPattern
: 一个正则表达式,用于匹配需要缓存的 URL。handler
: 缓存策略的名称 (例如CacheFirst
,NetworkFirst
)。options
: 缓存策略的选项,例如cacheName
(缓存名称)、expiration
(过期时间) 等等。
其他配置
plugin-pwa
还提供了许多其他的配置选项,你可以根据你的需求进行调整。
name
: PWA 应用的名称,显示在添加到桌面时的图标下方。themeColor
: 应用的主题颜色,用于浏览器地址栏和任务栏。msTileColor
: Windows 磁贴的颜色。appleMobileWebAppCapable
: 是否以全屏模式运行在 iOS 设备上。appleMobileWebAppStatusBarStyle
: iOS 状态栏的样式。
总结
Vue CLI 的 plugin-pwa
极大地简化了 PWA 的开发流程。它通过集成 Workbox,让你能够轻松地配置缓存策略、实现离线访问等功能。你可以根据你的需求选择 GenerateSW
或 InjectManifest
模式,并自定义缓存策略,打造一个高性能、可靠的 PWA 应用。
最后的唠叨:注意事项
- HTTPS: Service Worker 只能在 HTTPS 环境下运行 (或者 localhost)。
- 缓存更新: Service Worker 的更新机制比较复杂,需要仔细测试。
- 调试: 使用 Chrome DevTools 的 "Application" 面板可以调试 Service Worker。
好啦,今天的讲座就到这里。希望对大家有所帮助! 祝大家早日写出牛逼的 PWA 应用!