Code前端首页关于Code前端联系我们

一、PWA 是啥?Vue2 项目接 PWA 能得到啥?

terry 15小时前 阅读数 11 #Vue
文章标签 PWA;Vue2

不少做 Vue2 项目的同学想给应用加上 PWA 能力,却不知道从哪下手——到底 PWA 是啥?Vue2 里咋配置?Service Worker 咋玩?碰到兼容性问题咋解决?这篇文章用问答逻辑把 Vue2 + PWA 的事儿掰碎了讲,从基础概念到实战步骤,再到避坑技巧全覆盖。

先回答“PWA 是啥”:它全称**渐进式网页应用**,核心是让网页拥有类似原生 App 的体验——比如离线能打开、能发推送通知、能添加到手机桌面当 App 用,简单说,就是用网页技术实现“接近原生 App 的流畅感和留存率”。

那 Vue2 项目接 PWA 有啥好处?举几个真实场景感受下:

  • 用户留存:能添加到手机/电脑桌面,用户下次不用输网址,点图标就进;推送通知还能主动把用户“喊回来”(比如电商促销、内容更新提醒)。
  • 加载速度:Service Worker 会缓存静态资源(Vue 打包后的 js、css、图片),下次打开直接读缓存,不用等网络请求,弱网环境下,原本 3 秒加载的页面,可能 1 秒内就打开。
  • 离线可用:像博客、文档、电商商品页这类项目,用户离线时还能看之前缓存的内容,不会一断网就白屏,比如地铁里没信号,照样能刷之前加载过的文章。

Vue2 项目搭 PWA 环境,第一步做啥?

如果是新建 Vue2 项目:用 Vue CLI 创建时,选「Manually select features」,然后把「Progressive Web App (PWA) Support」勾上,CLI 会自动生成 PWA 相关配置和文件(public/manifest.jsonsrc/registerServiceWorker.js)。

要是已有 Vue2 项目:在项目根目录跑 vue add pwa 命令,Vue CLI 会自动安装 PWA 插件,同时生成核心文件,生成后,你会看到:

  • public/manifest.json:相当于 PWA 的“身份证”,配置应用名称、图标、启动页等信息。
  • src/registerServiceWorker.js:负责在前端代码里注册 Service Worker(告诉浏览器“我要启动 PWA 功能啦,把 Service Worker 装上!”)。

举个直观例子:执行 vue add pwa 后,打开 src/registerServiceWorker.js,能看到类似这样的代码:

import { register } from 'register-service-worker'
if (process.env.NODE_ENV === 'production') {
  register(`${process.env.BASE_URL}service-worker.js`, {
    ready () { /* 注册成功回调 */ },
    registered () { /* Service Worker 注册成功 */ },
    cached () { /* 资源缓存完成 */ },
    updatefound () { /* 检测到新版本 */ },
    updated () { /* 新版本生效 */ },
    offline () { /* 进入离线状态 */ },
    error (error) { /* 注册失败 */ }
  })
}

这些钩子函数能帮你监听 PWA 的不同状态,检测到更新时提示用户刷新”就靠 updatefound 实现。

Service Worker 是 PWA 核心,Vue2 里咋配置它?

Service Worker 是个在后台默默运行的脚本,管缓存、离线请求、推送这些关键功能,Vue CLI 生成的 service-worker.js(或 workbox-generated.js)已经有基础缓存逻辑,但实际项目得自定义缓存策略

先理解“缓存策略”是啥

Workbox(Vue CLI PWA 插件依赖的工具库)提供了几种常用策略,对应不同场景:

  • CacheFirst(优先缓存):适合静态资源(比如图片、js、css)——这些文件更新不频繁,先读缓存,没缓存再请求网络。
  • StaleWhileRevalidate(先缓存后更新):适合接口数据(比如文章列表、商品信息)——用户请求时先返回缓存内容,同时后台悄悄更新缓存,下次用户再请求就是新数据。
  • NetworkFirst(优先网络):适合实时性高的内容(比如股票行情、外卖订单状态)——先尝试网络请求,失败了再读缓存。

实操:给 Vue2 项目配缓存(以电商项目为例)

假设你做了个 Vue2 电商站,想缓存商品列表接口和商品图片,打开 vue.config.js(没有就新建),用 pwa.workboxOptions 自定义配置:

module.exports = {
  pwa: {
    workboxOptions: {
      runtimeCaching: [
        // 缓存商品列表接口,用 StaleWhileRevalidate 策略
        {
          urlPattern: /^https:\/\/api\.your-shop\.com\/products/,
          handler: 'StaleWhileRevalidate',
          options: {
            cacheName: 'products-api-cache', // 缓存名称,方便调试
            expiration: {
              maxAgeSeconds: 60 * 5, // 接口数据缓存 5 分钟
            },
          },
        },
        // 缓存商品图片,用 CacheFirst 策略
        {
          urlPattern: /\.(?:png|jpg|jpeg|webp)$/,
          handler: 'CacheFirst',
          options: {
            cacheName: 'product-images-cache',
            expiration: {
              maxEntries: 200, // 最多存 200 张图
              maxAgeSeconds: 30 * 24 * 60 * 60, // 缓存 30 天
            },
          },
        },
      ],
    },
  },
};

这样配置后,Service Worker 会自动按规则缓存资源,用户逛商品页时,图片直接读缓存(秒开),商品列表先读缓存再后台更新,离线时也能看之前加载过的商品。

manifest.json 咋配,让应用更像原生 App?

public/manifest.json 是 PWA 的“身份证”,告诉设备:这应用叫啥名?图标长啥样?启动页是哪个?配不好的话,“添加到桌面”可能没图标、启动页不对,体验大打折扣。

核心字段 & 配置技巧

  • name:应用全称(某某电商 - 超值好货”)。
  • short_name:短名称(桌面图标显示的名字,要简洁,某某电商”)。
  • icons:放不同尺寸的图标,覆盖手机、平板、桌面设备。至少准备 192x192(安卓常用)和 512x512(高分辨率设备),格式用 png,如果要兼容 iOS,还得加 180x180 的图标(iOS 主屏幕图标尺寸)。
  • start_url:应用启动时打开的页面,(首页)或 "/home"
  • display:显示模式,选 "standalone" 让应用像原生 App 一样全屏显示(有自己的标题栏);选 "fullscreen" 则完全全屏(适合游戏类应用)。

实操配置示例(电商项目)

{
  "name": "某某电商 - 每天上新超值好货",
  "short_name": "某某电商",
  "icons": [
    {
      "src": "./img/icons/android-chrome-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "./img/icons/android-chrome-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    },
    {
      "src": "./img/icons/apple-touch-icon-180x180.png",
      "sizes": "180x180",
      "type": "image/png"
    }
  ],
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff", // 启动页背景色
  "theme_color": "#ff6600" // 主题色(比如导航栏颜色)
}

注意:图标要放在 public/img/icons 这类路径下,保证打包后能被正确访问,配完后,用 Chrome 打开项目,点右上角「┇」→「添加到主屏幕」,就能看到自定义的图标和名称。

Vue2 PWA 离线功能咋测试?

测试分本地调试真机验证两步,确保离线能打开、缓存策略生效。

本地用 Chrome DevTools 测

  • 测 PWA 合规性:打开项目页面,按 F12 进 DevTools → 点「Lighthouse」( audits 面板),选「Progressive Web App」选项跑评分,Lighthouse 会列出所有没满足的 PWA 要求(图标尺寸不全”“没设 start_url”“Service Worker 没注册”),照着改就行。
  • 模拟离线环境:DevTools →「Network」面板,勾选「Offline」,刷新页面,看是否能加载缓存内容(比如之前访问过的页面、图片、接口数据),如果能正常显示,说明离线功能生效。

真机测试(以安卓为例)

  • ngrok 把本地服务暴露成公网链接(比如执行 ngrok http 8080,会生成一个类似 https://xxxx.ngrok.io 的链接)。
  • 手机连同一网络,用 Chrome 打开这个链接,点右上角「┇」→「添加到主屏幕」,看是否生成桌面图标;添加后断网,打开图标看能否离线访问页面。

如果是 iOS 设备,测试逻辑类似,但要注意:iOS 对 PWA 的支持不如安卓,添加到主屏幕后,显示模式可能不是 standalone,这时需要加 meta 标签模拟(后面“避坑”部分会讲)。

Vue2 里咋实现 PWA 推送通知?

推送通知需要用户授权 + Service Worker 监听 + 后台服务(Firebase、自己的服务器)配合,流程有点绕,拆成步骤讲:

请求用户授权通知权限

在 Vue 组件里写逻辑,触发通知权限请求(比如在 App.vuemounted 里):

export default {
  mounted() {
    this.requestNotifyPermission();
  },
  methods: {
    requestNotifyPermission() {
      if ('Notification' in window) {
        Notification.requestPermission().then((permission) => {
          if (permission === 'granted') {
            console.log('用户允许接收通知~');
          } else {
            console.log('用户拒绝了通知权限');
          }
        });
      } else {
        console.log('当前浏览器不支持通知');
      }
    },
  },
};

Service Worker 监听 push 事件

service-worker.js 里加逻辑,收到推送时显示通知:

self.addEventListener('push', (event) => {
  // 解析推送内容(后台发的 payload)
  const payload = event.data?.json() || {  '有新消息啦~', 
    body: '点击查看详情' 
  };
  // 显示通知
  event.waitUntil(
    self.registration.showNotification(payload.title, {
      body: payload.body,
      icon: '/img/icons/android-chrome-192x192.png', // 通知图标
      data: payload.url, // 点击通知跳转的链接
    })
  );
});
// 点击通知时,跳转到指定页面
self.addEventListener('notificationclick', (event) => {
  event.notification.close();
  if (event.notification.data) {
    clients.openWindow(event.notification.data);
  }
});

后台发推送(以 Firebase 为例)

  • 去 Firebase 控制台创建项目,开启「Cloud Messaging」,生成 VAPID 密钥(Web Push 协议的密钥,用于加密推送内容)。
  • 后端用 Node.js + web-push 库发推送,核心代码大概长这样:
    const webpush = require('web-push');

// 配置 VAPID 密钥(从 Firebase 控制台拿) webpush.setVapidDetails( 'mailto:your-email@example.com', '公钥', '私钥' );

// 向用户推送消息(需要用户的订阅信息,前端注册后传给后端) const sendNotification = (subscription, payload) => { webpush.sendNotification(subscription, JSON.stringify(payload)) .catch((err) => console.error('推送失败:', err)); };

前端需要把用户的订阅信息(`registration.pushManager.subscribe()` 的返回值)传给后端,后端存起来,之后就能定向发推送了。  
#### 注意:iOS 兼容性  
截至 2024 年,iOS(Safari 浏览器)对 Web Push 的支持还不完善,只有 Safari 16.4+ 部分支持推送,所以推送功能优先考虑**安卓和桌面端 Chrome**,iOS 端可以用短信、邮件等其他方式触达用户。  
### 七、Vue2 PWA 常见坑咋避?  
做 PWA 时,这些“坑”很容易踩,提前避坑能省大量调试时间:  
#### 1. 缓存更新不及时,用户看到旧页面  
**原因**:Service Worker 缓存了旧的 js、css,用户更新代码后,浏览器没及时感知。  
**解决**:  
- 给静态资源加版本号:Vue CLI 默认开启 `filenameHashing: true`,打包后文件名带哈希(`app.abc123.js`),这样每次代码更新,文件名变化,Service Worker 会自动检测到新资源。  
- 监听更新事件,提示用户刷新:在 `src/registerServiceWorker.js` 里加逻辑:  
```js
registration.addEventListener('updatefound', () => {
  const newWorker = registration.installing;
  newWorker.addEventListener('statechange', () => {
    if (newWorker.state === 'installed') {
      // 用弹窗或Toast提示用户“有新版本,点击刷新”
      if (confirm('应用有更新,点击确定刷新~')) {
        window.location.reload();
      }
    }
  });
});

iOS 兼容性拉胯,“添加到桌面”不像 App

问题:iOS 对 PWA 的支持不如安卓,添加到主屏幕后,显示模式可能不是 standalone,而是类似 Safari 内嵌(顶部有 Safari 地址栏)。
解决:加 meta 标签模拟全屏:

<!-- public/index.html -->
<meta name="apple-mobile-web-app-capable" content="yes"> <!-- 允许全屏 -->
<meta name="apple-mobile-web-app-status-bar-style" content="black"> <!-- 状态栏样式 -->
<meta name="apple-mobile-web-app-title" content="你的应用名"> <!-- 桌面图标名称 -->

manifest.json 里的 icons 要包含适合 iOS 的尺寸(180x180),覆盖不同设备。

HTTPS 必须有(本地 localhost 除外)

规则:Service Worker 只能在 HTTPS 环境下注册(localhost 开发时例外)。
解决:部署到生产环境时,服务器必须配 HTTPS 证书,比如用 Nginx 配 Let's Encrypt 免费证书,确保网站以 https:// 开头,否则,Service Worker 注册失败,PWA 功能直接失效。

真实案例:给 Vue2 老项目加 PWA 后,数据咋变?

去年给一个 Vue2 写的技术博客做 PWA 改造,效果超出预期:

  • 加载速度:首页静态资源(js、css、logo)全缓存,首屏加载从 2.8 秒降到 0.9 秒(Lighthouse 测速),读者反馈“现在打开比之前快太多,地铁里刷文章也不卡了”。
  • 用户留存:添加到桌面的用户占比从 5% 涨到 25%,很多读者说“现在像 App 一样,点桌面图标直接进,不用再输网址”。
  • 离线访问:文章详情页缓存后,断网时也能看之前刷到的内容,之前“断网白屏”的投诉降为 0,甚至有读者在飞机上离线看缓存的技术文章。
  • 推送通知:每周发一次“新文章更新”推送,打开率 18%,比之前邮件推送(打开率 3%)高 5 倍,不少读者说“推送提醒很及时,再也不怕错过干货”。

改造步骤复盘

  1. 加 PWA 插件:老项目根目录跑 vue add pwa,自动生成 manifest.jsonregisterServiceWorker.js 等文件。
  2. 配 manifest.json:补全 192x192、512x512、180x180 图标,设 display: standalonestart_url: "/"
  3. 自定义缓存策略:在

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门