入门教程,升级指南

React 同构应用 PWA 晋级指南

2018/05/25 · JavaScript
· PWA,
React

初稿出处:
林东洲   

渐进式Web应用(PWA)入门教程(下)

2018/05/25 · 基本功才能 ·
PWA

原稿出处: Craig
Buckler   译文出处:葡萄干城控件   

上篇小说我们对渐进式Web应用(PWA)做了部分骨干的介绍。

渐进式Web应用(PWA)入门教程(上)

在这一节中,大家将介绍PWA的原理是怎么着,它是何等最早专门的工作的。

前言

最近在给自个儿的博客网址 PWA 进级,顺便就记录下 React 同构应用在接纳 PWA
时境遇的主题材料,这里不会从头开端介绍怎么着是 PWA,若是你想上学 PWA
相关文化,能够看下上边作者收藏的有的文章:

  • 您的首先个 Progressive Web
    App
  • 【ServiceWorker】生命周期那多少个事儿
  • 【PWA学习与执行】(1)
    2018,初始你的PWA学习之旅
  • Progressive Web Apps (PWA)
    中文版

第一步:使用HTTPS

渐进式Web应用程序要求利用HTTPS连接。固然使用HTTPS会令你服务器的付出变多,但利用HTTPS能够让您的网址变得更安全,HTTPS网址在Google上的排名也会更靠前。

是因为Chrome浏览器会暗中同意将localhost以及127.x.x.x地址视为测验地方,所以在本示例中您并无需开启HTTPS。别的,出于调节和测量试验指标,您能够在开发银行Chrome浏览器的时候利用以下参数来关闭其对网址HTTPS的检讨:

  • –user-data-dir
  • –unsafety-treat-insecure-origin-as-secure

PWA 特性

PWA 不是仅仅的某项工夫,而是一批技术的成团,比方:ServiceWorker,manifest 增加到桌面,push、notification api 等。

而就在近日时间,IOS 11.3 刚刚扶助 Service worker 和好像 manifest
增多到桌面包车型客车特点,所以这次 PWA
更改首要仍旧兑现这两有个别机能,至于其余的特色,等 iphone 帮衬了再晋级吗。

第二步:创设二个应用程序清单(Manifest)

应用程序清单提供了和脚下渐进式Web应用的相关音讯,如:

  • 应用程序名
  • 描述
  • 具有图片(包括主显示器Logo,运维显示器页面和用的图纸大概网页上用的图形)

实为上讲,程序清单是页面上用到的Logo和大旨等能源的元数据。

程序清单是一个位居您使用根目录的JSON文件。该JSON文件重返时必需抬高Content-Type: application/manifest+json 或者 Content-Type: application/jsonHTTP头音讯。程序清单的公文名不限,在本文的示范代码中为manifest.json

{ “name” : “PWA Website”, “short_name” : “PWA”, “description” : “An
example PWA website”, “start_url” : “/”, “display” : “standalone”,
“orientation” : “any”, “background_color” : “#ACE”, “theme_color” :
“#ACE”, “icons”: [ { “src” : “/images/logo/logo072.png”, “sizes” :
“72×72”, “type” : “image/png” }, { “src” : “/images/logo/logo152.png”,
“sizes” : “152×152”, “type” : “image/png” }, { “src” :
“/images/logo/logo192.png”, “sizes” : “192×192”, “type” : “image/png” },
{ “src” : “/images/logo/logo256.png”, “sizes” : “256×256”, “type” :
“image/png” }, { “src” : “/images/logo/logo512.png”, “sizes” :
“512×512”, “type” : “image/png” } ] }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{
  "name"              : "PWA Website",
  "short_name"        : "PWA",
  "description"       : "An example PWA website",
  "start_url"         : "/",
  "display"           : "standalone",
  "orientation"       : "any",
  "background_color"  : "#ACE",
  "theme_color"       : "#ACE",
  "icons": [
    {
      "src"           : "/images/logo/logo072.png",
      "sizes"         : "72×72",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo152.png",
      "sizes"         : "152×152",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo192.png",
      "sizes"         : "192×192",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo256.png",
      "sizes"         : "256×256",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo512.png",
      "sizes"         : "512×512",
      "type"          : "image/png"
    }
  ]
}

程序清单文件建构完今后,你须求在各样页面上引用该文件:

<link rel=”manifest” href=”/manifest.json”>

1
<link rel="manifest" href="/manifest.json">

以下属性在程序清单中常常接纳,介绍表明如下:

  • name: 顾客阅览标行使名称
  • short_name: 应用短名称。当呈现选拔名称的地点相当不够时,将应用该名称。
  • description: 运用描述。
  • start_url: 动用初阶路线,相对路线,默认为/。
  • scope: U奥德赛L范围。比如:假如你将“/app/”设置为UPRADOL范围时,那个动用就能一向在那几个目录中。
  • background_color: 招待页面包车型客车背景颜色和浏览器的背景颜色(可选)
  • theme_color: 采取的核心颜色,日常都会和背景颜色一样。那些装置决定了动用怎么样体现。
  • orientation: 事先旋转方向,可选的值有:any, natural, landscape,
    landscape-primary, landscape-secondary, portrait, portrait-primary,
    and portrait-secondary
  • display: 展现形式——fullscreen(无Chrome),standalone(和原生应用同样),minimal-ui(最小的一套UI控件集)大概browser(最古老的应用浏览器标签突显)
  • icons: 二个带有全体图片的数组。该数组中各类元素包括了图片的UWranglerL,大小和项目。

Service Worker

service worker
在作者眼里,类似于八个跑在浏览器后台的线程,页面第贰次加载的时候会加载那一个线程,在线程激活之后,通过对
fetch 事件,能够对各样得到的财富开展支配缓存等。

其三步:创造四个 Service Worker

Service Worker
是一个可编制程序的服务器代理,它能够阻挡恐怕响应互联网须要。Service Worker
是身处应用程序根目录的一个个的JavaScript文件。

你须要在页面对应的JavaScript文件中注册该瑟维斯Worker:

if (‘serviceWorker’ in navigator) { // register service worker
navigator.serviceWorker.register(‘/service-worker.js’); }

1
2
3
4
if (‘serviceWorker’ in navigator) {
  // register service worker
  navigator.serviceWorker.register(‘/service-worker.js’);
}

一经你无需离线的有关功效,您能够只创制二个 /service-worker.js文件,那样客商就能够直接设置您的Web应用了!

ServiceWorker那些概念恐怕比较难懂,它其实是四个行事在别的线程中的规范的Worker,它不得以访谈页面上的DOM成分,未有页面上的API,可是足以阻挡全部页面上的网络要求,包蕴页面导航,央求财富,Ajax央求。

下边就是采取全站HTTPS的要紧缘由了。假令你未有在您的网址中运用HTTPS,三个第三方的剧本就足以从其余的域名注入他自个儿的ServiceWorker,然后篡改全数的乞求——那的确是那么些危险的。

Service Worker 会响应七个事件:install,activate和fetch。

一望而知怎么着财富要求被缓存?

那就是说在起始应用 service worker 从前,首先要求了解如何财富须求被缓存?

Install事件

该事件将要行使设置达成后触发。我们日常在此间运用Cache
API缓存一些至关重要的文书。

先是,大家需求提供如下配置

  1. 缓存名称(CACHE)以及版本(version)。应用能够有多少个缓存存款和储蓄,可是在利用时只会使用在那之中二个缓存存款和储蓄。每当缓存存款和储蓄有变动时,新的版本号将会钦命到缓存存款和储蓄中。新的缓存存款和储蓄将会作为当前的缓存存储,在此以前的缓存存款和储蓄将会被作废。
  2. 叁个离线的页面地址(offlineU奇骏L):当客商访问了事先未有访谈过的地点时,该页面将会来得。
  3. 三个分包了有着必得文件的数组,包含保持页面不荒谬职能的CSS和JavaScript。在本示例中,作者还增加了主页和logo。当有例外的UOdysseyL指向同三个能源时,你也能够将这一个U奇骏L分别写到那几个数组中。offlineULANDL将会步入到这么些数组中。
  4. 笔者们也得以将一部分非供给的缓存文件(installFilesDesirable)。那个文件在设置进度军长会被下载,但若是下载失利,不会触发安装失利。

// 配置文件 const version = ‘1.0.0’, CACHE = version + ‘::PWAsite’,
offlineU奥迪Q5L = ‘/offline/’, installFilesEssential = [ ‘/’,
‘/manifest.json’, ‘/css/styles.css’, ‘/js/main.js’,
‘/js/offlinepage.js’, ‘/images/logo/logo152.png’ ].concat(offlineURL),
installFilesDesirable = [ ‘/favicon.ico’, ‘/images/logo/logo016.png’,
‘/images/hero/power-pv.jpg’, ‘/images/hero/power-lo.jpg’,
‘/images/hero/power-hi.jpg’ ];

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 配置文件
const
  version = ‘1.0.0’,
  CACHE = version + ‘::PWAsite’,
  offlineURL = ‘/offline/’,
  installFilesEssential = [
    ‘/’,
    ‘/manifest.json’,
    ‘/css/styles.css’,
    ‘/js/main.js’,
    ‘/js/offlinepage.js’,
    ‘/images/logo/logo152.png’
  ].concat(offlineURL),
  installFilesDesirable = [
    ‘/favicon.ico’,
    ‘/images/logo/logo016.png’,
    ‘/images/hero/power-pv.jpg’,
    ‘/images/hero/power-lo.jpg’,
    ‘/images/hero/power-hi.jpg’
  ];

installStaticFiles() 方法应用基于Promise的方法利用Cache
API将文件存款和储蓄到缓存中。

// 安装静态财富 function installStaticFiles() { return
caches.open(CACHE) .then(cache => { // 缓存可选文件
cache.addAll(installFilesDesirable); // 缓存必需文件 return
cache.addAll(installFilesEssential); }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 安装静态资源
function installStaticFiles() {
  return caches.open(CACHE)
    .then(cache => {
      // 缓存可选文件
      cache.addAll(installFilesDesirable);
      // 缓存必须文件
      return cache.addAll(installFilesEssential);
    });
}

最终,大家抬高四个install的风云监听器。waitUntil方法保障了service
worker不会设置直到其有关的代码被施行。这里它会施行installStaticFiles()方法,然后self.skipWaiting()艺术来激活service
worker:

// 应用设置 self.addEventListener(‘install’, event => {
console.log(‘service worker: install’); // 缓存首要文件 event.waitUntil(
installStaticFiles() .then(() => self.skipWaiting()) ); });

1
2
3
4
5
6
7
8
9
10
11
12
// 应用安装
self.addEventListener(‘install’, event => {
  console.log(‘service worker: install’);
  // 缓存主要文件
  event.waitUntil(
    installStaticFiles()
    .then(() => self.skipWaiting())
  );
});

缓存静态财富

先是是像 CSS、JS 这个静态能源,因为自个儿的博客里引用的台本样式都是经过 hash
做悠久化缓存,类似于:main.ac62dexx.js 那样,然后展开强缓存,这样下一次客商下一次再拜候笔者的网址的时候就毫无再行央浼能源。间接从浏览器缓存中读取。对于那有个别能源,service
worker 没要求再去管理,直接放行让它去读取浏览器缓存就能够。

本人觉着一旦你的站点加载静态能源的时候本身并未有张开强缓存,何况你只想通过前端去贯彻缓存,而没有需求后端在参预实行调治,那能够采取service worker 来缓存静态财富,不然就有一些画蛇添足了。

Activate 事件

那么些事件会在service
worker被激活时发出。你大概不必要这么些事件,可是在示范代码中,我们在该事件爆发时将老的缓存全体清理掉了:

// clear old caches function clearOldCaches() { return caches.keys()
.then(keylist => { return Promise.all( keylist .filter(key => key
!== CACHE) .map(key => caches.delete(key)) ); }); } // application
activated self.addEventListener(‘activate’, event => {
console.log(‘service worker: activate’); // delete old caches
event.waitUntil( clearOldCaches() .then(() => self.clients.claim())
); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// clear old caches
function clearOldCaches() {
  return caches.keys()
    .then(keylist => {
      return Promise.all(
        keylist
          .filter(key => key !== CACHE)
          .map(key => caches.delete(key))
      );
    });
}
// application activated
self.addEventListener(‘activate’, event => {
  console.log(‘service worker: activate’);
    // delete old caches
  event.waitUntil(
    clearOldCaches()
    .then(() => self.clients.claim())
    );
});

注意self.clients.claim()实践时将会把近期service
worker作为被激活的worker。

Fetch 事件
该事件将会在网络开端须要时发起。该事件管理函数中,我们能够行使respondWith()办法来威吓HTTP的GET伏乞然后回来:

  1. 从缓存中取到的能源文件
  2. 万一第一步战败,财富文件将会从互连网中动用Fetch API来博取(和service
    worker中的fetch事件无关)。获取到的能源将会步入到缓存中。
  3. 假设第一步和第二步均退步,将会从缓存中回到准确的财富文件。

// application fetch network data self.addEventListener(‘fetch’, event
=> { // abandon non-GET requests if (event.request.method !== ‘GET’)
return; let url = event.request.url; event.respondWith(
caches.open(CACHE) .then(cache => { return cache.match(event.request)
.then(response => { if (response) { // return cached file
console.log(‘cache fetch: ‘ + url); return response; } // make network
request return fetch(event.request) .then(newreq => {
console.log(‘network fetch: ‘ + url); if (newreq.ok)
cache.put(event.request, newreq.clone()); return newreq; }) // app is
offline .catch(() => offlineAsset(url)); }); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// application fetch network data
self.addEventListener(‘fetch’, event => {
  // abandon non-GET requests
  if (event.request.method !== ‘GET’) return;
  let url = event.request.url;
  event.respondWith(
    caches.open(CACHE)
      .then(cache => {
        return cache.match(event.request)
          .then(response => {
            if (response) {
              // return cached file
              console.log(‘cache fetch: ‘ + url);
              return response;
            }
            // make network request
            return fetch(event.request)
              .then(newreq => {
                console.log(‘network fetch: ‘ + url);
                if (newreq.ok) cache.put(event.request, newreq.clone());
                return newreq;
              })
              // app is offline
              .catch(() => offlineAsset(url));
          });
      })
  );
});

offlineAsset(url)方法中使用了部分helper方法来回到精确的数码:

// 是不是为图片地址? let iExt = [‘png’, ‘jpg’, ‘jpeg’, ‘gif’, ‘webp’,
‘bmp’].map(f => ‘.’ + f); function isImage(url) { return
iExt.reduce((ret, ext) => ret || url.endsWith(ext), false); } //
return 再次来到离线财富 function offlineAsset(url) { if (isImage(url)) { //
再次来到图片 return new Response( ‘<svg role=”img” viewBox=”0 0 400 300″
xmlns=”
d=”M0 0h400v300H0z” fill=”#eee” /><text x=”200″ y=”150″
text-anchor=”middle” dominant-baseline=”middle” font-family=”sans-serif”
font-size=”50″ fill=”#ccc”>offline</text></svg>’, {
headers: { ‘Content-Type’: ‘image/svg+xml’, ‘Cache-Control’: ‘no-store’
}} ); } else { // return page return caches.match(offlineURL); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 是否为图片地址?
let iExt = [‘png’, ‘jpg’, ‘jpeg’, ‘gif’, ‘webp’, ‘bmp’].map(f => ‘.’ + f);
function isImage(url) {
  
  return iExt.reduce((ret, ext) => ret || url.endsWith(ext), false);
  
}
  
  
// return 返回离线资源
function offlineAsset(url) {
  
  if (isImage(url)) {
  
    // 返回图片
    return new Response(
      ‘<svg role="img" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg"><title>offline</title><path d="M0 0h400v300H0z" fill="#eee" /><text x="200" y="150" text-anchor="middle" dominant-baseline="middle" font-family="sans-serif" font-size="50" fill="#ccc">offline</text></svg>’,
      { headers: {
        ‘Content-Type’: ‘image/svg+xml’,
        ‘Cache-Control’: ‘no-store’
      }}
    );
  
  }
  else {
  
    // return page
    return caches.match(offlineURL);
  
  }
  
}

offlineAsset()艺术检查要求是或不是为二个图片,然后回到三个分包“offline”文字的SVG文件。别的乞请将会回去
offlineU昂CoraL 页面。

Chrome开辟者工具中的ServiceWorker部分提供了关于当前页面worker的消息。在那之中博览会示worker中产生的谬误,仍可以强制刷新,也得以让浏览器步入离线形式。

Cache Storage
部分例举了现阶段怀有曾经缓存的能源。你能够在缓存须求更新的时候点击refresh开关。

缓存页面

缓存页面鲜明是必备的,那是最中央的片段,当你在离线的情事下加载页面会之后出现:

图片 1

究其原因便是因为您在离线状态下不能够加载页面,今后有了 service
worker,即便你在没网络的场所下,也得以加载此前缓存好的页面了。

第四步:创制可用的离线页面

离线页面能够是静态的HTML,日常用于提醒客户眼下伏乞的页面目前不可能采用。不过,我们能够提供部分能够阅读的页面链接。

Cache
API能够在main.js中利用。不过,该API使用Promise,在不帮助Promise的浏览器中会退步,全体的JavaScript推行会由此遭逢震慑。为了制止这种场合,在拜见/js/offlinepage.js的时候大家增添了一段代码来检查当前是还是不是在离线意况中:

/js/offlinepage.js 中以版本号为名称保存了多年来的缓存,获取具备UEvoqueL,删除不是页面包车型地铁U奥迪Q7L,将这么些URL排序然后将具备缓存的U中华VL浮今后页面上:

// cache name const CACHE = ‘::PWAsite’, offlineURL = ‘/offline/’, list
= document.getElementById(‘cachedpagelist’); // fetch all caches
window.caches.keys() .then(cacheList => { // find caches by and order
by most recent cacheList = cacheList .filter(cName =>
cName.includes(CACHE)) .sort((a, b) => a – b); // open first cache
caches.open(cacheList[0]) .then(cache => { // fetch cached pages
cache.keys() .then(reqList => { let frag =
document.createDocumentFragment(); reqList .map(req => req.url)
.filter(req => (req.endsWith(‘/’) || req.endsWith(‘.html’)) &&
!req.endsWith(offlineURL)) .sort() .forEach(req => { let li =
document.createElement(‘li’), a =
li.appendChild(document.createElement(‘a’)); a.setAttribute(‘href’,
req); a.textContent = a.pathname; frag.appendChild(li); }); if (list)
list.appendChild(frag); }); }) });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// cache name
const
  CACHE = ‘::PWAsite’,
  offlineURL = ‘/offline/’,
  list = document.getElementById(‘cachedpagelist’);
// fetch all caches
window.caches.keys()
  .then(cacheList => {
    // find caches by and order by most recent
    cacheList = cacheList
      .filter(cName => cName.includes(CACHE))
      .sort((a, b) => a – b);
    // open first cache
    caches.open(cacheList[0])
      .then(cache => {
        // fetch cached pages
        cache.keys()
          .then(reqList => {
            let frag = document.createDocumentFragment();
            reqList
              .map(req => req.url)
              .filter(req => (req.endsWith(‘/’) || req.endsWith(‘.html’)) && !req.endsWith(offlineURL))
              .sort()
              .forEach(req => {
                let
                  li = document.createElement(‘li’),
                  a = li.appendChild(document.createElement(‘a’));
                  a.setAttribute(‘href’, req);
                  a.textContent = a.pathname;
                  frag.appendChild(li);
              });
            if (list) list.appendChild(frag);
          });
      })
  });

缓存后端接口数据

缓存接口数据是急需的,但亦不是必须经过 service worker
来促成,前端存放数据的地点有大多,举个例子通过 localstorage,indexeddb
来实行仓库储存。这里小编也是经过 service worker
来兑现缓存接口数据的,假如想经过其他措施来贯彻,只必要潜心好 url
路线与数据对应的照射关系就可以。

开辟者工具

Chrome浏览器提供了一密密麻麻的工具来帮助您来调解ServiceWorker,日志也会一直浮今后调控台上。

您最佳利用佚名方式来进展支付工作,那样能够清除缓存对开荒的郁闷。

最后,Chrome的Lighthouse扩张也得认为你的渐进式Web应用提供部分革新新闻。

缓存战术

令人瞩目了怎么能源要求被缓存后,接下去就要斟酌缓存攻略了。

渐进式Web应用的大旨

渐进式Web应用是一种新的手艺,所以利用的时候势要求小心。也正是说,渐进式Web应用能够令你的网址在多少个钟头内获取改革,何况在不协助渐进式Web应用的浏览器上也不会影响网站的显得。

但是大家必要怀恋以下几点:

页面缓存战术

因为是 React
单页同构应用,每回加载页面包车型客车时候数据都是动态的,所以本身使用的是:

  1. 网络优先的艺术,即优先得到互联网上风行的财富。当互连网需要战败的时候,再去获取
    service worker 里此前缓存的能源
  2. 当互联网加载成功未来,就更新 cache
    中对应的缓存能源,有限帮助下一次历次加载页面,都以上次作客的新星能源
  3. 举个例子找不到 service worker 中 url 对应的能源的时候,则去赢得 service
    worker 对应的 /index.html 默许首页

// sw.js self.add伊芙ntListener(‘fetch’, (e) => {
console.log(‘以后正在呼吁:’ + e.request.url); const currentUrl =
e.request.url; // 相称上页面路线 if (matchHtml(currentUrl)) { const
requestToCache = e.request.clone(); e.respondWith( // 加载网络上的财富fetch(requestToCache).then((response) => { // 加载失利 if (!response
|| response.status !== 200) { throw Error(‘response error’); } //
加载成功,更新缓存 const responseToCache = response.clone();
caches.open(cacheName).then((cache) => { cache.put(requestToCache,
responseToCache); }); console.log(response); return response;
}).catch(function() { //
获取对应缓存中的数据,获取不到则战败到收获暗许首页 return
caches.match(e.request).then((response) => { return response ||
caches.match(‘/index.html’); }); }) ); } });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// sw.js
self.addEventListener(‘fetch’, (e) => {
  console.log(‘现在正在请求:’ + e.request.url);
  const currentUrl = e.request.url;
  // 匹配上页面路径
  if (matchHtml(currentUrl)) {
    const requestToCache = e.request.clone();
    e.respondWith(
      // 加载网络上的资源
      fetch(requestToCache).then((response) => {
        // 加载失败
        if (!response || response.status !== 200) {
          throw Error(‘response error’);
        }
        // 加载成功,更新缓存
        const responseToCache = response.clone();
        caches.open(cacheName).then((cache) => {
          cache.put(requestToCache, responseToCache);
        });
        console.log(response);
        return response;
      }).catch(function() {
        // 获取对应缓存中的数据,获取不到则退化到获取默认首页
        return caches.match(e.request).then((response) => {
           return response || caches.match(‘/index.html’);
        });
      })
    );
  }
});

何以存在命中每每缓存页面包车型地铁景观?

  1. 先是要求显明的是,顾客在第三回加载你的站点的时候,加载页面后才会去运转sw,所以首先次加载不容许通过 fetch 事件去缓存页面
  2. 本人的博客是单页应用,然则客户并不一定会通过首页进入,有相当的大概率会经过别的页面路线步向到本人的网址,这就导致本身在
    install 事件中常有无法钦定必要缓存那多个页面
  3. 最终实现的遵守是:客商率先次张开页面,登时断掉互联网,仍旧得以离线访谈小编的站点

构成地点三点,笔者的不二法门是:第二回加载的时候会缓存 /index.html 那些能源,并且缓存页面上的数量,要是顾客马上离线加载的话,那时候并从未缓存对应的渠道,比如 /archives 能源访谈不到,那再次回到 /index.html 走异步加载页面包车型大巴逻辑。

在 install 事件缓存 /index.html,保障了 service worker
第二次加载的时候缓存私下认可页面,留下退路。

import constants from ‘./constants’; const cacheName =
constants.cacheName; const apiCacheName = constants.apiCacheName; const
cacheFileList = [‘/index.html’]; self.addEventListener(‘install’, (e)
=> { console.log(‘Service Worker 状态: install’); const
cacheOpenPromise = caches.open(cacheName).then((cache) => { return
cache.addAll(cacheFileList); }); e.waitUntil(cacheOpenPromise); });

1
2
3
4
5
6
7
8
9
10
11
12
import constants from ‘./constants’;
const cacheName = constants.cacheName;
const apiCacheName = constants.apiCacheName;
const cacheFileList = [‘/index.html’];
 
self.addEventListener(‘install’, (e) => {
  console.log(‘Service Worker 状态: install’);
  const cacheOpenPromise = caches.open(cacheName).then((cache) => {
    return cache.addAll(cacheFileList);
  });
  e.waitUntil(cacheOpenPromise);
});

在页面加载完后,在 React 组件中马上缓存数据:

// cache.js import constants from ‘../constants’; const apiCacheName =
constants.apiCacheName; export const saveAPIData = (url, data) => {
if (‘caches’ in window) { // 伪造 request/response 数据
caches.open(apiCacheName).then((cache) => { cache.put(url, new
Response(JSON.stringify(data), { status: 200 })); }); } }; // React 组件
import constants from ‘../constants’; export default class extends
PureComponent { componentDidMount() { const { state, data } =
this.props; // 异步加载数据 if (state === constants.INITIAL_STATE ||
state === constants.FAILURE_STATE) { this.props.fetchData(); } else {
// 服务端渲染成功,保存页面数据 saveAPIData(url, data); } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// cache.js
import constants from ‘../constants’;
const apiCacheName = constants.apiCacheName;
 
export const saveAPIData = (url, data) => {
  if (‘caches’ in window) {
    // 伪造 request/response 数据
    caches.open(apiCacheName).then((cache) => {
      cache.put(url, new Response(JSON.stringify(data), { status: 200 }));
    });
  }
};
 
// React 组件
import constants from ‘../constants’;
export default class extends PureComponent {
  componentDidMount() {
    const { state, data } = this.props;
    // 异步加载数据
    if (state === constants.INITIAL_STATE || state === constants.FAILURE_STATE) {
      this.props.fetchData();
    } else {
        // 服务端渲染成功,保存页面数据
      saveAPIData(url, data);
    }
  }
}

那样就保险了顾客率先次加载页面,立即离线访问站点后,即便不也许像第贰遍同样能够服务端渲染数据,不过随后能因此取得页面,异步加载数据的方法创设离线应用。

图片 2

客商率先次访问站点,假如在不刷新页面包车型地铁处境切换路由到别的页面,则会异步获取到的数据,当下一次作客对应的路由的时候,则战败到异步获取数据。

图片 3

当客户第二遍加载页面包车型大巴时候,因为 service worker
已经调控了站点,已经具备了缓存页面包车型大巴手艺,之后在做客的页面都将会被缓存可能更新缓存,当客商离线访谈的的时候,也能访谈到服务端渲染的页面了。

图片 4

URL隐藏

当您的应用正是四个单UENVISIONL的应用程序时(比方游戏),小编提出您遮蔽地址栏。除此而外的场馆本人并不建议你遮蔽地址栏。在Manifest中,display: minimal-ui 或者 display: browser对于多数景色的话丰盛用了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注