Расскажите о PWA

внешний интерфейс сервер браузер PWA

1. Предпосылки

статьяОбзор фронтенд-событий и трендов 2017 года. Куда пойдет 2018 год?В статье упоминается десятка достойных внимания событий во фронтенде в 2017 году, среди которых упоминается PWA.

Все знают, что родное приложение действительно очень удобно, после загрузки на мобильный телефон оно очень удобно. Есть у него и некоторые недостатки:

  • Высокая стоимость разработки (ios и Android)
  • Программное обеспечение нуждается в проверке
  • Обновления версии требуют загрузки новой версии в другой магазин приложений.
  • Если вы хотите использовать приложение, вы должны загрузить его, чтобы использовать его, даже если вам нужно использовать его время от времени.

Стоимость разработки веб-страниц низкая.При обновлении веб-сайта последние ресурсы могут быть загружены на сервер, а браузер можно открыть с помощью мобильного телефона и использовать. Тем не менее, опыт все еще хуже, чем у родного приложения, и есть некоторые очевидные недостатки.

  • Вход с мобильного рабочего стола недостаточно удобен, если вы хотите зайти на страницу, вы должны запомнить ее адрес или добавить закладку
  • Нет сети, нет ответа, нет автономной работы
  • Невозможно отправлять сообщения, такие как APP

Так что же такое PWA?

2. Что такое PWA?

Полное название PWA — Progressive Web App, то есть прогрессивное веб-приложение.

Приложение PWA — это сначала веб-страница, а приложение веб-страницы может быть написано с помощью веб-технологий. Затем добавляются App Manifest и Service Worker для реализации установки PWA и автономных функций. Какие проблемы были решены?

  • Его можно добавить на главный экран, щелкните значок главного экрана, чтобы реализовать анимацию запуска и скрыть адресную строку.
  • Реализовать функцию автономного кэширования, даже если мобильный телефон пользователя не подключен к сети, некоторые автономные функции все же можно использовать.
  • Реализован push сообщений

Он решает проблемы, упомянутые выше, и эти функции будут постепенно приближать веб-приложения к нативным приложениям.

3. Внедрение PWA

3.1 Реализация манифеста добавлена ​​на главный экран

index.html

<head>
  <title>Minimal PWA</title>
  <meta name="viewport" content="width=device-width, user-scalable=no" />
  <link rel="manifest" href="manifest.json" />
  <link rel="stylesheet" type="text/css" href="main.css">
  <link rel="icon" href="/e.png" type="image/png" />
</head>

manifest.json

{
  "name": "Minimal PWA", // 必填 显示的插件名称
  "short_name": "PWA Demo", // 可选  在APP launcher和新的tab页显示,如果没有设置,则使用name
  "description": "The app that helps you understand PWA", //用于描述应用
  "display": "standalone", // 定义开发人员对Web应用程序的首选显示模式。standalone模式会有单独的
  "start_url": "/", // 应用启动时的url
  "theme_color": "#313131", // 桌面图标的背景色
  "background_color": "#313131", // 为web应用程序预定义的背景颜色。在启动web应用程序和加载应用程序的内容之间创建了一个平滑的过渡。
  "icons": [ // 桌面图标,是一个数组
    {
    "src": "icon/lowres.webp",
    "sizes": "48x48",  // 以空格分隔的图片尺寸
    "type": "image/webp"  // 帮助userAgent快速排除不支持的类型
  },
  {
    "src": "icon/lowres",
    "sizes": "48x48"
  },
  {
    "src": "icon/hd_hi.ico",
    "sizes": "72x72 96x96 128x128 256x256"
  },
  {
    "src": "icon/hd_hi.svg",
    "sizes": "72x72"
  }
  ]
}

Справочная документация манифеста:developer.Mozilla.org/this-cn/docs/…

может открыть сайтDevelopers.Google.capable/Web/show CAS…Посмотрите анимацию, добавленную на главный экран.

Если вы используете телефон Android, вы можете загрузить браузер Chrome, чтобы увидеть его самостоятельно.

3.2 Service Worker реализует автономное кэширование

3.2.1 Что такое сервис-воркер

Service Worker — это веб-API, предложенный и продвигаемый командой Chrome для обеспечения расширенных возможностей устойчивой фоновой обработки для веб-приложений.

Сервисные работники подобны перехватчикам между сервером и веб-страницей, способными перехватывать входящие и исходящие HTTP-запросы, предоставляя вам полный контроль над вашим веб-сайтом.

Основная особенность

  • После того, как страница зарегистрирована и успешно установлена, она работает в фоновом режиме браузера, на нее не влияет обновление страницы, и она может отслеживать и перехватывать HTTP-запросы всех страниц в пределах области действия.
  • Веб-сайты должны использовать HTTPS. За исключением отладки с использованием локальной среды разработки (например, с использованием localhost для имени домена).
  • Работая в фоновом режиме браузера, он может контролировать все запросы страниц в рамках открытой области.
  • Отдельная область видимости, отдельная среда выполнения и поток выполнения
  • Страница DOM не может быть изменена. Но это можно обработать через механизм событий
  • поток обслуживания, управляемый событиями

Причина, по которой веб-сайт должен быть HTTPS, вероятно, заключается в том, что сервис-воркер имеет слишком много полномочий для перехвата всех запросов страниц.Если http-сайт установлен с сервис-воркером, его легко атаковать.

Поддержка браузера

Для получения подробной информации о поддержке браузера см.:rubnewsor.com/#feat=Сайлви…

Жизненный цикл

Когда пользователь переходит по URL-адресу в первый раз, сервер возвращает веб-страницу в ответ.

  • Шаг 1: Когда вы вызываете функцию register(), Service Worker начинает загрузку.
  • Шаг 2: В процессе регистрации браузер загружает, анализирует и выполняет Service Worker(). Если на этом шаге возникнут какие-либо ошибки, обещание, возвращаемое функцией register(), будет отклонено, а Service Worker будет удален.
  • Шаг 3. После успешного выполнения Service Worker будет активировано событие установки.
  • Шаг 4: После завершения установки Service Worker активируется и контролирует все в пределах своей области. Если все события в жизненном цикле выполнены успешно, Service Worker готов и готов к использованию!

chrome://serviceworker-internalsчтобы увидеть подробную информацию обо всех установленных Service Workers в текущем браузере

3.2.2 HTTP-кэш и кэш сервис-воркеров

  • HTTP-кеширование

Веб-сервер может использовать заголовок Expires для уведомления веб-клиента, который может использовать текущую копию ресурса до указанного «срока действия». И наоборот, браузер может кэшировать этот ресурс и снова проверять новую версию только после действительного истечения срока действия. Использование кеша HTTP означает, что вы хотите полагаться на сервер, чтобы сообщить вам, когда ресурсы кеша и когда истечет срок их действия.

  • кеш сервис-воркера

Сила Service Workers заключается в их способности перехватывать HTTP-запросы. Введите любой входящий HTTP-запрос и решите, как вы хотите ответить. В вашем сервис-воркере вы можете написать логику, чтобы решить, какие ресурсы вы хотите кэшировать, какие условия должны быть выполнены и как долго ресурсы должны кэшироваться. Все под вашим контролем!

3.2.3 Внедрение автономного кэширования

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello Caching World!</title>
  </head>
  <body>
    <!-- Image -->
    <img src="/images/hello.png" />                 
    <!-- JavaScript -->
    <script async src="/js/script.js"></script>     
    <script>
      // 注册 service worker
      if ('serviceWorker' in navigator) {           
        navigator.serviceWorker.register('/service-worker.js', {scope: '/'}).then(function (registration) {
          // 注册成功
          console.log('ServiceWorker registration successful with scope: ', registration.scope);
        }).catch(function (err) {                   
          // 注册失败 :(
          console.log('ServiceWorker registration failed: ', err);
        });
      }
    </script>
  </body>
</html>

Примечание. Путь регистрации Service Worker определяет область действия по умолчанию его области. Если service-worker.js находится по пути к странице /sw/, это заставляет сервис-воркер получать события выборки только по пути к странице /sw/ по умолчанию. При сохранении в корневом пути веб-сайта будут получены все события выборки для этого веб-сайта. Если вы хотите изменить его область действия, вы можете установить область действия во втором параметре. В примере он изменен на корневой каталог, который действует для всего сайта.

service-worker.js

var cacheName = 'helloWorld';     // 缓存的名称  
// install 事件,它发生在浏览器安装并注册 Service Worker 时        
self.addEventListener('install', event => { 
/* event.waitUtil 用于在安装成功之前执行一些预装逻辑
 但是建议只做一些轻量级和非常重要资源的缓存,减少安装失败的概率
 安装成功后 ServiceWorker 状态会从 installing 变为 installed */
  event.waitUntil(
    caches.open(cacheName)                  
    .then(cache => cache.addAll([    // 如果所有的文件都成功缓存了,便会安装完成。如果任何文件下载失败了,那么安装过程也会随之失败。        
      '/js/script.js',
      '/images/hello.png'
    ]))
  );
});
  
/**
为 fetch 事件添加一个事件监听器。接下来,使用 caches.match() 函数来检查传入的请求 URL 是否匹配当前缓存中存在的任何内容。如果存在的话,返回缓存的资源。
如果资源并不存在于缓存当中,通过网络来获取资源,并将获取到的资源添加到缓存中。
*/
self.addEventListener('fetch', function (event) {
  event.respondWith(
    caches.match(event.request)                  
    .then(function (response) {
      if (response) {                            
        return response;                         
      }
      var requestToCache = event.request.clone();  //          
      return fetch(requestToCache).then(                   
        function (response) {
          if (!response || response.status !== 200) {      
            return response;
          }
          var responseToCache = response.clone();          
          caches.open(cacheName)                           
            .then(function (cache) {
              cache.put(requestToCache, responseToCache);  
            });
          return response;             
    })
  );
});

Примечание. Зачем использовать request.clone() и response.clone() Это необходимо, потому что запрос и ответ представляют собой поток, который можно использовать только один раз. Поскольку мы уже использовали его один раз через кеш, а затем сделали еще один HTTP-запрос, нам нужно клонировать запрос на этом этапе. Клонировать запрос — запрос представляет собой поток и может быть использован только один раз.

3.2.4 Отладка

хром браузер открытьGoogle chrome.GitHub.IO/samples/Sail…, это веб-сайт, который реализует функцию автономного кэширования сервис-воркера, откройте инструмент отладки

Представьте 1. и 2. на рисунке.

  1. Установите флажок, чтобы имитировать офлайн-ситуацию веб-сайта.После проверки в сети появится желтый значок предупреждения, а веб-сайт отключен. Обновите страницу в это время, страница все еще может отображаться нормально
  2. Область действия текущего сервисного работника. Он может перехватывать запросы в https://googlechrome.github.io/samples/service-worker/basic/index.html, а также https://googlechrome.github.io/samples/service-worker/basic/ Requests в */*.html

Что конкретно представляет собой панель отладки?Маленький 5.Tencent.com/ не говоря уже о/дорогой/это…третья часть

3.3 Service Worker реализует отправку сообщений

  • Шаг 1. Подскажите пользователю и получите информацию о его подписке
  • Шаг 2. Сохраните эти данные на сервере
  • Шаг 3. Отправьте любое сообщение, когда это необходимо

Разные браузеры требуют разных push-сообщений. В качестве примера возьмем Google Cloud Messaging как push-сервис в Chrome. Первым шагом будет регистрация ApplicationServerKey (доступ к регистрации GCM) и подписка или инициирование подписки на странице. Каждая сессия будет иметь отдельную конечную точку (endpoint), свойство объекта подписки (PushSubscription.endpoint) является значением конечной точки. После отправки конечных точек на сервер сервер использует это значение для отправки сообщения сервисному работнику активации сеанса (передается через GCM и клиент браузера).

Шаг 1 и Шаг 2 index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Progressive Times</title>
    <link rel="manifest" href="/manifest.json">                                      
  </head>
  <body>
    <script>
      var endpoint;
      var key;
      var authSecret;
      var vapidPublicKey = 'BAyb_WgaR0L0pODaR7wWkxJi__tWbM1MPBymyRDFEGjtDCWeRYS9EF7yGoCHLdHJi6hikYdg4MuYaK0XoD0qnoY';
      // 方法很复杂,但是可以不用具体看,知识用来转化vapidPublicKey用
      function urlBase64ToUint8Array(base64String) {                                  
        const padding = '='.repeat((4 - base64String.length % 4) % 4);
        const base64 = (base64String + padding)
          .replace(/\-/g, '+')
          .replace(/_/g, '/');
        const rawData = window.atob(base64);
        const outputArray = new Uint8Array(rawData.length);
        for (let i = 0; i < rawData.length; ++i) {
          outputArray[i] = rawData.charCodeAt(i);
        }
        return outputArray;
      }
      if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register('sw.js').then(function (registration) {
          return registration.pushManager.getSubscription()                            
            .then(function (subscription) {
              if (subscription) {                                                      
                return;
              }
              return registration.pushManager.subscribe({                              
                  userVisibleOnly: true,
                  applicationServerKey: urlBase64ToUint8Array(vapidPublicKey)
                })
                .then(function (subscription) {
                  var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
                  key = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : '';
                  var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
                  authSecret = rawAuthSecret ?
                    btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : '';
                  endpoint = subscription.endpoint;
                  return fetch('./register', {                                         
                    method: 'post',
                    headers: new Headers({
                      'content-type': 'application/json'
                    }),
                    body: JSON.stringify({
                      endpoint: subscription.endpoint,
                      key: key,
                      authSecret: authSecret,
                    }),
                  });
                });
            });
        }).catch(function (err) {
          // 注册失败 :(
          console.log('ServiceWorker registration failed: ', err);
        });
      }
    </script>
  </body>
</html>

Шаг 3 Сервер отправляет сообщение сервис-воркеру

app.js

const webpush = require('web-push');                 
const express = require('express');
var bodyParser = require('body-parser');
const app = express();
webpush.setVapidDetails(                             
  'mailto:contact@deanhume.com',
  'BAyb_WgaR0L0pODaR7wWkxJi__tWbM1MPBymyRDFEGjtDCWeRYS9EF7yGoCHLdHJi6hikYdg4MuYaK0XoD0qnoY',
  'p6YVD7t8HkABoez1CvVJ5bl7BnEdKUu5bSyVjyxMBh0'
);
app.post('/register', function (req, res) {           
  var endpoint = req.body.endpoint;
  saveRegistrationDetails(endpoint, key, authSecret); 
  const pushSubscription = {                          
    endpoint: req.body.endpoint,
    keys: {
      auth: req.body.authSecret,
      p256dh: req.body.key
    }
  };
  var body = 'Thank you for registering';
  var iconUrl = 'https://example.com/images/homescreen.png';
  // 发送 Web 推送消息
  webpush.sendNotification(pushSubscription,          
      JSON.stringify({
        msg: body,
        url: 'http://localhost:3111/',
        icon: iconUrl
      }))
    .then(result => res.sendStatus(201))
    .catch(err => {
      console.log(err);
    });
});
app.listen(3111, function () {
  console.log('Web push app listening on port 3111!')
});

Сервисный работник прослушивает push-событие и отправляет детали уведомления пользователю.

service-worker.js

self.addEventListener('push', function (event) {
 // 检查服务端是否发来了任何有效载荷数据
  var payload = event.data ? JSON.parse(event.data.text()) : 'no payload';
  var title = 'Progressive Times';
  event.waitUntil(
    // 使用提供的信息来显示 Web 推送通知
    self.registration.showNotification(title, {                           
      body: payload.msg,
      url: payload.url,
      icon: payload.icon
    })
  );
});

Расширенные знания: [Обновление Service Worker] (https://lzw.me/a/pwa-service-worker.html#3.3 Обновление Service Worker)

Суммировать

Преимущества PWA

  • Вы можете разместить ярлык приложения на рабочем столе и запустить его в полноэкранном режиме, как и родное приложение.
  • Может использоваться в различных сетевых средах, включая плохую сеть и условия отключения, не будет отображаться неопределенное
  • Возможность отправлять сообщения
  • Его суть - веб-страница без различных условий запуска нативных приложений, быстро реагирующая на инструкции пользователя.

Проблемы с PWA

  • Уровень поддержки невелик: PWA сейчас не поддерживается на мобильных телефонах ios, а IE пока не поддерживает.
  • Chrome по-прежнему имеет значительную долю настольной версии в Китае, но очень низкую долю на мобильном терминале Android.
  • Крупные производители еще явно не поддерживают pwa.
  • Зависимый сервис GCM нельзя использовать в Китае.
  • Конкурс мини-программ WeChat

Несмотря на некоторые из вышеперечисленных недостатков, технология PWA все же имеет массу достоинств, которые можно использовать.

  • Технология Service Worker реализует автономное кэширование, которое может помещать в кэш некоторые статические файлы, которые редко изменяются, чтобы улучшить взаимодействие с пользователем.
  • Сервисный работник реализует push-сообщение и использует функцию push-уведомлений браузера для привлечения пользователей.
  • Прогрессивная разработка, несмотря на то, что некоторые браузеры временно не поддерживаются, может использовать преимущества вышеописанных методов, чтобы повысить удобство работы пользователей, использующих поддерживаемые браузеры.

Справочная документация