渐进式web应用程序

tech2022-07-14  182

渐进式web应用程序

This article on retrofitting your website as a progressive web app is included in our anthology, Modern JavaScript. If you want everything in one place to get up to speed on modern JavaScript, sign up for SitePoint Premium and download yourself a copy.

有关将网站改造为渐进式Web应用程序的文章包含在我们的选集Modern JavaScript中 。 如果您希望所有内容都集中在一个地方,以适应最新JavaScript,请注册SitePoint Premium并下载一个副本。

There’s been a lot of buzz around Progressive Web Apps (PWAs) lately, with many people questioning whether they represent the future of the (mobile) web.

最近,有关渐进式Web应用程序(PWA)的讨论越来越多,许多人质疑它们是否代表了(移动)网络的未来。

I’m not going to get into the whole native app vs PWA debate, but one thing’s for sure: they go a long way to enhancing mobile and improving its user experience.

我不会涉及整个本机应用程序与PWA的争论,但可以肯定的是:它们在增强移动性和改善其用户体验方面还有很长的路要走。

With mobile web access destined to surpass that of all other devices combined, can you afford to ignore this trend?

随着移动Web的访问量注定要超过所有其他设备的总和,您可以忽略这一趋势吗?

The good news is that making a PWA is not hard. In fact, it’s quite possible to take an existing website and convert it into a PWA. And that’s exactly what I’ll be doing in this tutorial. By the time you’re finished, you’ll have a website that behaves like a native web app. It will work offline and have its own home-screen icon.

好消息是制作PWA并不困难。 实际上,可以将现有网站转换为PWA。 这正是我在本教程中要做的。 待您完成时,您将拥有一个行为类似于本地Web应用程序的网站。 它可以脱机工作,并具有自己的主屏幕图标。

目录 ( Table of Contents)

What Are Progressive Web Apps?

什么是渐进式Web应用程序?

Progressive Web Apps are Progressive Enhancements

渐进式Web应用程序是渐进式增强功能

It’s Not Just Apps

不只是应用

Demonstration Code

示范代码

Connect a Device

连接设备

Step 1: Enable HTTPS

步骤1:启用HTTPS

Step 2: Create a Web App Manifest

步骤2:创建Web App清单

Step 3: Create a Service Worker

步骤3:建立服务人员

Install Event

安装事件

Activate Event

激活事件

Fetch Event

提取事件

Bonus Step 4: Create a Useful Offline Page

奖励步骤4:创建有用的离线页面

Development Tools

开发工具

PWA Gotchas

PWA陷阱

URL Hiding

URL隐藏

Cache Overload

缓存过载

Cache Refreshing

缓存刷新

Useful Links

有用的链接

Comments

注释

什么是渐进式Web应用程序? (What Are Progressive Web Apps?)

Progressive Web Apps (referred to as PWAs) are an exciting innovation in web technology. PWAs comprise a mixture of technologies to make a web app function like a native mobile app. The benefits for developers and users overcome the constraints imposed by web-only and native-only solutions:

渐进式Web应用程序(简称PWA )是Web技术中令人兴奋的创新。 PWA包含多种技术,可以使Web应用程序像本地移动应用程序一样运行。 为开发人员和用户带来的好处克服了纯Web解决方案和纯本机解决方案带来的限制:

You only need one app developed with open, standard W3C web technologies. There’s no need to develop separate native codebases.

您只需要使用开放的标准W3C网络技术开发的一个应用程序即可。 无需开发单独的本机代码库。 Users can discover and try your app before installation.

用户可以在安装前发现并尝试您的应用。 There’s no need to use an AppStore, abide with arcane rules or pay fees. Application updates occur automatically without user interaction.

无需使用AppStore,遵守不可思议的规则或支付费用。 应用程序更新会自动进行,而无需用户干预。 Users are prompted to “install”, which adds an icon to their home screen.

提示用户“安装”,这会将图标添加到其主屏幕。 When launched, the PWA displays an attractive splash screen.

启动后,PWA将显示一个吸引人的启动屏幕。 The browser chrome options can be modified if necessary to provide a full-screen experience.

如有必要,可以修改浏览器的chrome选项以提供全屏体验。

Essential files are cached locally so PWAs respond faster than standard web apps. (They can even be faster than native apps.)

基本文件在本地缓存,因此PWA的响应速度比标准Web应用程序快。 (它们甚至可以比本地应用程序更快。)

Installation is lightweight — perhaps a few hundred KB of cached data.

安装是轻量级的-可能需要数百KB的缓存数据。 All data exchanges must occur over a secure HTTPS connection.

所有数据交换必须通过安全的HTTPS连接进行。 PWAs function offline and can synchronize data when the connection returns.

PWA脱机运行,并且可以在连接返回时同步数据。

It’s early days, but case studies are positive. Flipkart, India’s largest ecommerce site, experienced a 70% increase in sales conversions and trebled on-site time when they abandoned their native app for a PWA. Alibaba, the world’s largest business trading platform, experienced a similar conversion rate increase of 76%.

现在还处于初期,但案例研究是积极的 。 印度最大的电子商务网站Flipkart在放弃本地应用程序进行PWA时,销售转化率提高了70%,现场时间增加了三倍 。 世界上最大的商业交易平台阿里巴巴的转换率也增长了76% 。

Solid PWA technology support is available in Firefox, Chrome and the other Blink-based browsers. Microsoft is working on an Edge implementation. Apple remains silent, although there are promising comments in the WebKit five-year plan. Fortunately, browser support is mostly irrelevant …

Firefox,Chrome和其他基于Blink的浏览器均提供Solid PWA技术支持。 Microsoft正在开发Edge实施。 尽管WebKit五年计划中有令人鼓舞的评论,苹果仍然保持沉默。 幸运的是,浏览器支持基本上无关紧要……

渐进式Web应用程序是渐进式增强功能 (Progressive Web Apps are Progressive Enhancements)

Your app will still run in browsers that don’t support PWA technology. The user won’t get the benefits of offline functionality, but everything will continue to work as before. Given the cost-to-benefit rewards, there’s little reason not to add PWA technologies to your system.

您的应用仍将在不支持PWA技术的浏览器中运行。 用户将无法获得脱机功能的好处,但是一切将继续像以前一样工作。 考虑到成本效益的回报,没有理由不将PWA技术添加到您的系统中。

不只是应用 (It’s Not Just Apps)

Google has led the PWA movement, so most tutorials describe how to build a Chrome-based, native-looking mobile app from the ground up. However, you don’t need a special single-page app or have to follow material interface design guidelines. Most websites can be PWA-ized within a few hours. That includes your WordPress or static site.

Google领导了PWA运动 ,因此大多数教程都从头开始描述如何构建基于Chrome的本机外观移动应用程序。 但是,您不需要特殊的单页应用程序,也不必遵循重要的界面设计准则。 大多数网站可以在几个小时内实现PWA认证。 其中包括您的WordPress或静态站点。

示范代码 (Demonstration Code)

Demonstration code is available from GitHub.

演示代码可从GitHub获得 。

It provides a simple, four-page website with a few images, one stylesheet and a single main JavaScript file. The site works in all modern browsers (IE10+). If the browser supports PWA technologies, the user can read previously viewed pages when they’re offline.

它提供了一个简单的四页网站,其中包含一些图像,一个样式表和一个主JavaScript文件。 该网站可在所有现代浏览器(IE10 +)中使用。 如果浏览器支持PWA技术,则用户可以在脱机时阅读以前查看的页面。

To run the code, ensure Node.js is installed, then start the provided web server in your terminal with:

要运行代码,请确保已安装Node.js ,然后使用以下命令在终端中启动提供的Web服务器:

node ./server.js [port]

In the above code, [port] is optional, and defaults to 8888. Open Chrome or another Blink-based browser such as Opera or Vivaldi, then navigate to http://localhost:8888/ (or whichever port you specified). You can also open the Developer Tools (F12 or Cmd/Ctrl + Shift + I) to view various console messages.

在上面的代码中, [port]是可选的,默认为8888。打开Chrome或其他基于Blink的浏览器,例如Opera或Vivaldi,然后导航到http:// localhost:8888 / (或您指定的任何端口)。 您也可以打开开发人员工具(F12或Cmd / Ctrl + Shift + I )以查看各种控制台消息。

View the home page, and perhaps one other, then go offline by either:

查看主页,也许也可以查看另一个页面,然后通过以下两种方法之一使其离线:

stopping the web server with Cmd/Ctrl + C, or

使用Cmd / Ctrl + C停止Web服务器,或者

check the Offline checkbox in the Network or Application – Service Workers tab of the Developer Tools.

选中开发人员工具的网络或应用程序-服务工作者标签中的离线复选框。

Revisit any of the pages you viewed earlier and they’ll still load. Visit a page you’ve not seen to be presented with a “you’re offline” page containing a list of viewable pages:

重新访问您先前查看的任何页面,它们仍将加载。 访问未显示有“您处于离线状态”页面的页面,该页面包含可见页面列表:

连接设备 (Connect a Device)

You can also view the demonstration page on an Android smartphone connected to your PC/Mac via USB. Open the Remote devices panel from More tools in the top-left three-dot menu.

您还可以在通过USB连接到PC / Mac的Android智能手机上查看演示页面。 从左上角三点菜单中的“ 更多”工具打开“ 远程设备”面板。

Select Settings on the left and click Add Rule to forward port 8888 to localhost:8888. You can now open Chrome on the smartphone and navigate to http://localhost:8888/.

选择左侧的“设置” ,然后单击“ 添加规则”将端口8888转发到localhost:8888。 现在,您可以在智能手机上打开Chrome并浏览至http:// localhost:8888 / 。

You can use the browser menu to “Add to Home screen”. Make a couple of visits and the browser should prompt you to “install”. Both options create a new icon on your home screen. Browse a few pages, then close Chrome and disconnect your device. You can then launch the PWA Website app. You’ll see a splash screen and be able to view pages you read previously, despite having no connection to the server.

您可以使用浏览器菜单来“添加到主屏幕”。 进行两次访问,浏览器将提示您“安装”。 这两个选项都会在主屏幕上创建一个新图标。 浏览几页,然后关闭Chrome并断开设备连接。 然后,您可以启动PWA网站应用程序。 尽管没有连接到服务器,您将看到一个初始屏幕,并且能够查看以前阅读的页面。

There are three essential steps to transform your website into a Progressive Web App …

只需三个基本步骤即可将您的网站转换为渐进式Web应用程序……

步骤1:启用HTTPS (Step 1: Enable HTTPS)

PWAs require an HTTPS connection, for reasons that will become apparent shortly. Prices and processes will differ across hosts, but it’s worth the cost and effort, given that Google search is ranking secure sites higher.

PWA需要HTTPS连接,原因很快就会显现出来。 价格和流程因主机而异,但值得花成本和精力,因为Google搜索对安全网站的排名更高。

HTTPS is not necessary for the demonstration above because Chrome permits the use of localhost or any 127.x.x.x address for testing. You can also test PWA technology on HTTP sites if you launch Chrome with the following command line flags:

上面的演示不需要HTTPS,因为Chrome允许使用localhost或任何127.xxx地址进行测试。 如果您使用以下命令行标志启动Chrome,也可以在HTTP网站上测试PWA技术:

--user-data-dir

--user-data-dir

--unsafety-treat-insecure-origin-as-secure

--unsafety-treat-insecure-origin-as-secure

步骤2:创建Web App清单 (Step 2: Create a Web App Manifest)

The web app manifest provides information about the application such as the name, description and images, which are used by the OS to configure home screen icons, splash pages and the viewport. In essence, the manifest is a single file alternative to the numerous vendor-specific icon and theme meta tags you may already have in your pages.

Web应用程序清单提供了有关应用程序的信息,例如名称,描述和图像,操作系统可使用它们来配置主屏幕图标,初始页面和视口。 本质上,清单是单个文件的替代品,可以替代您可能已在页面中包含的大量特定于供应商的图标和主题元标记。

The manifest is a JSON text file in the root of your app. It must be served with a Content-Type: application/manifest+json or Content-Type: application/json HTTP header. The file can be called anything but has been named /manifest.json in the demonstration code:

清单是应用程序根目录中的JSON文本文件。 它必须与Content-Type: application/manifest+json或Content-Type: application/json HTTP标头一起提供。 该文件可以被命名为任何东西,但在演示代码中已被命名为/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" : "72x72", "type" : "image/png" }, { "src" : "/images/logo/logo152.png", "sizes" : "152x152", "type" : "image/png" }, { "src" : "/images/logo/logo192.png", "sizes" : "192x192", "type" : "image/png" }, { "src" : "/images/logo/logo256.png", "sizes" : "256x256", "type" : "image/png" }, { "src" : "/images/logo/logo512.png", "sizes" : "512x512", "type" : "image/png" } ] }

A link to this file is required in the <head> of all your pages:

您所有页面的<head>中都需要此文件的链接:

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

The main manifest properties are:

主要清单属性是:

name: the full name of the application to be displayed to the user

name :要显示给用户的应用程序的全名

short_name: the short name for situations where there is insufficient space for the full name

short_name :对于全名没有足够空间的情况,简称

description: a long description of the application

description :应用程序的详细描述

start_url: the relative URL to start the application (typically /)

start_url :启动应用程序的相对URL(通常为/ )

scope: the navigation scope — for example, a scope of /app/ would restrict the app to that folder

scope :导航范围-例如, /app/的范围会将应用限制为该文件夹

background_color: the background color used for splash screens and browser chrome (if required)

background_color :用于初始屏幕和浏览器镶边的背景颜色(如果需要)

theme_color: the application’s color, typically the same as the background, which can affect how the app is displayed

theme_color :应用程序的颜色,通常与背景相同,这会影响应用程序的显示方式

orientation: the preferred orientation — any, natural, landscape, landscape-primary, landscape-secondary, portrait, portrait-primary, and portrait-secondary

方向 :首选方向- any , natural , landscape , landscape-primary landscape-secondary , portrait , portrait-primary portrait-secondary

display: the preferred view — fullscreen (no chrome), standalone (looks like a native app), minimal-ui (a small set of UI controls) and browser (a conventional browser tab)

display :首选视图- fullscreen (无chrome), standalone (看起来像本机应用程序), minimal-ui (一minimal-ui UI控件)和browser (传统的浏览器标签)

icons: an array of image objects defining the src URL, sizes and type (a range of icons should be defined).

icons :定义src URL, sizes和type (应定义图标范围)的图像对象数组。

MDN provides a full list of Web App Manifest properties.

MDN提供了Web App Manifest属性的完整列表。

The Manifest section of Chrome’s Development Tools Application tab validates your manifest JSON and provides an “Add to homescreen” link, which functions on desktop devices:

Chrome的“开发工具”的“ 应用程序”选项卡的“清单”部分验证您的清单JSON并提供“添加到主屏幕”链接,该链接可在桌面设备上运行:

步骤3:建立服务人员 (Step 3: Create a Service Worker)

Service Workers are programmable proxies which can intercept and respond to network requests. They’re a single JavaScript file which resides in the application root.

服务人员是可编程的代理,可以拦截和响应网络请求。 它们是驻留在应用程序根目录中的单个JavaScript文件。

Your page JavaScript (/js/main.js in the demonstration code) can check for service worker support and register the file:

您的页面JavaScript(在演示代码中为/js/main.js )可以检查对Service Worker的支持并注册文件:

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

If you don’t need offline capabilities, simply create an empty /service-worker.js file. Users will be prompted to install your app!

如果您不需要离线功能,只需创建一个空的/service-worker.js文件。 将提示用户安装您的应用程序!

Service workers can be bewildering, but you should be able to adapt the demonstration code for your own purposes. It’s a standard web worker script that the browser downloads (when possible) and runs on a separate thread. It has no access to the DOM or other page APIs, but will intercept network requests triggered by page changes, asset downloads, and Ajax calls.

服务人员可能会感到困惑,但是您应该能够根据自己的目的调整演示代码。 这是浏览器下载(如果可能)并在单独的线程上运行的标准Web工作者脚本。 它无权访问DOM或其​​他页面API,但将拦截由页面更改,资产下载和Ajax调用触发的网络请求。

This is the primary reason your site requires HTTPS. Imagine the chaos if a third-party script could inject its own service worker from another domain. It would be able to examine and modify all data exchanges between the client and server!

这是您的站点需要HTTPS的主要原因。 想象一下,如果第三方脚本可以从另一个域注入其自己的服务工作者,那么该混乱情况。 它将能够检查和修改客户端与服务器之间的所有数据交换!

Service workers react to three primary events: install, activate and fetch.

服务人员对三个主要事件作出React: install , activate和fetch 。

安装事件 (Install Event)

This occurs when the application is installed. It’s typically used to cache essential files using the Cache API.

在安装应用程序时会发生这种情况。 它通常用于使用Cache API缓存基本文件。

First, we’ll define some configuration variables for:

首先,我们将为以下定义一些配置变量:

The cache name (CACHE) and version (version). Your application can have multiple cache stores, but we only require one. A version number is applied, so if we make significant changes, a new cache will be used and all previously cached files are ignored.

缓存名称( CACHE )和版本( version )。 您的应用程序可以有多个缓存存储,但是我们只需要一个。 版本号已应用,因此,如果我们进行了重大更改,将使用新的缓存,而所有先前缓存的文件将被忽略。

An offline page URL (offlineURL). This is a page which will be presented when the user is offline and attempts to load a page they haven’t visited before.

离线页面URL( offlineURL )。 这是一个页面,当用户脱机并尝试加载他们之前未曾访问过的页面时,将显示该页面。

An array of essential files to install, which ensure the site functions offline (installFilesEssential). This should include assets such as CSS and JavaScript, but I’ve also included the home page (/) and logo. You should also include variations such as / and /index.html if URLs can be addressed in more than one way. Note that offlineURL is added to this array.

一系列要安装的基本文件,可确保站点离线运行( installFilesEssential )。 这应该包括CSS和JavaScript之类的资产,但是我还包括了主页( / )和徽标。 如果URL可以通过多种方式寻址,则还应包含/和/index.html变体。 请注意, offlineURL已添加到此数组。

Optionally, an array of desirable files (installFilesDesirable). These will be downloaded, if possible, but won’t make the installation abort on failure.

(可选)一个所需文件的数组( installFilesDesirable )。 如果可能,将下载这些文件,但不会使安装因失败而中止。

// configuration 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' ];

The installStaticFiles() function adds files to the cache using the promise-based Cache API. A return value is only generated when the essential files are cached:

installStaticFiles()函数使用基于Promise的Cache API将文件添加到缓存中。 仅在缓存基本文件时才生成返回值:

// install static assets function installStaticFiles() { return caches.open(CACHE) .then(cache => { // cache desirable files cache.addAll(installFilesDesirable); // cache essential files return cache.addAll(installFilesEssential); }); }

Finally, we add an install event listener. The waitUntil method ensures the service worker won’t install until all enclosed code has executed. It runs installStaticFiles() then self.skipWaiting() to make the service worker active:

最后,我们添加一个install事件侦听器。 waitUntil方法可确保服务工作者在所有包含的代码执行waitUntil才能安装。 它先运行installStaticFiles()然后运行self.skipWaiting()以使服务工作者处于活动状态:

// application installation self.addEventListener('install', event => { console.log('service worker: install'); // cache core files event.waitUntil( installStaticFiles() .then(() => self.skipWaiting()) ); });

激活事件 (Activate Event)

This occurs when the service worker is activated, either immediately after installation or on return. You may not require this handler, but the demonstration code uses one to delete old caches when they exist:

在安装后或返回时立即激活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()) ); });

Note the final self.clients.claim() call sets this service worker as the active worker for the site.

请注意,最后的self.clients.claim()调用将此服务工作程序设置为站点的活动工作程序。

提取事件 (Fetch Event)

This occurs whenever a network request is made. It calls the respondWith() method to hijack GET requests and return:

每当发出网络请求时,就会发生这种情况。 它调用respondWith()方法劫持GET请求并返回:

An asset from the cache.

缓存中的资产。

If #1 fails, the asset is loaded from the network using the Fetch API) (unrelated to the service worker fetch event). That asset is then added to the cache.

如果#1失败,则使用Fetch API从网络中加载资产(与服务工作者获取事件无关)。 然后将该资产添加到缓存中。

If #1 and #2 fail, an appropriate response is returned.

如果#1和#2失败,则返回适当的响应。 // 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)); }); }) ); });

The final call to offlineAsset(url) returns an appropriate response using a couple of helper functions:

最后对offlineAsset(url)调用使用几个辅助函数返回适当的响应:

// is image URL? 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 offline asset function offlineAsset(url) { if (isImage(url)) { // return image return new Response( '<svg role="img" viewBox="0 0 400 300" xmlns="https://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); } }

The offlineAsset() function checks whether the request is for an image and returns an SVG containing the text “offline”. All other requests return the offlineURL page.

offlineAsset()函数检查请求是否针对图像,并返回包含文本“ offline”的SVG。 所有其他请求都返回offlineURL页面。

The Service Worker section of Chrome’s Development Tools Application tab provides information about your workers, with errors and facilities to force reload and make the browser go offline:

Chrome的“开发工具”的“ 应用程序”选项卡的“ 服务工作者”部分提供了有关您的工作者的信息,并包含错误和设施,这些错误和设施会强制重新加载并使浏览器离线:

The Cache Storage section lists all caches within the current scope and the cached assets they contain. You may need to click the refresh button when the cache is updated:

缓存存储部分列出了当前范围内的所有缓存及其包含的缓存资产。 缓存更新后,您可能需要单击刷新按钮:

Unsurprisingly, the Clear storage section can delete your service worker and caches:

毫不奇怪,“ 清除存储”部分可以删除服务工作者和缓存:

奖励步骤4:创建有用的离线页面 (Bonus Step 4: Create a Useful Offline Page)

The offline page can be static HTML informing the user that the page they requested is not available offline. However, we can also provide a list of page URLs that are available to read.

脱机页面可以是静态HTML,通知用户他们请求的页面不可脱机使用。 但是,我们也可以提供可供阅读的页面URL列表。

The Cache API can be accessed within our main.js script. However, the API uses promises that fail in unsupported browsers and will cause all JavaScript to halt execution. To avoid this, we’ll add code that checks whether the offline list element and the Caches API is available before loading another /js/offlinepage.js JavaScript file (which must be present in the installFilesEssential array above):

可以在我们的main.js脚本中访问Cache API 。 但是,API使用的Promise会在不受支持的浏览器中失败,并会导致所有JavaScript停止执行。 为避免这种情况,我们将添加代码,以在加载另一个/js/offlinepage.js JavaScript文件(该文件必须存在于上述installFilesEssential数组中)之前检查脱机列表元素和Caches API是否可用:

// load script to populate offline page list if (document.getElementById('cachedpagelist') && 'caches' in window) { var scr = document.createElement('script'); scr.src = '/js/offlinepage.js'; scr.async = 1; document.head.appendChild(scr); }

/js/offlinepage.js locates the most recent cache by version name, gets a list of all URL keys, removes non-page URLs, sorts the list and appends it to the DOM node with the ID cachedpagelist:

/js/offlinepage.js通过版本名称查找最新的高速缓存,获取所有URL密钥的列表,删除非页面URL,对列表进行排序并将其附加到ID为cachedpagelist的DOM节点上:

// 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); }); }) });

开发工具 (Development Tools)

If you think JavaScript debugging is tough, service workers won’t be much fun! Chrome’s Application tab of the Developer Tools provides a solid set of features and logging statements are also output to the console.

如果您认为JavaScript调试很困难,那么服务人员就不会很有趣! 开发人员工具的Chrome的“ 应用程序”标签提供了一组可靠的功能,日志记录语句也输出到控制台。

You should consider running your app in an Incognito window during development, since cached files are not retained after you close the tab.

在开发过程中,您应该考虑在隐身窗口中运行您的应用程序,因为关闭选项卡后不会保留缓存的文件。

Firefox offers a JavaScript debugger accessed from the Service Workers option of the tools menu. Better facilities are promised soon.

Firefox提供了一个JavaScript调试器,可通过工具菜单的Service Workers选项进行访问。 承诺很快会提供更好的设施。

Finally, the Lighthouse extension for Chrome also provides useful information about your PWA’s implementation.

最后, Chrome的Lighthouse扩展程序还提供了有关PWA实施的有用信息。

PWA陷阱 (PWA Gotchas)

Progressive Web Apps require new technologies, so some caution is advised. That said, they’re an enhancement of your existing website which should take no longer than a few hours and have no negative effect on unsupported browsers.

渐进式Web应用程序需要新技术,因此建议谨慎使用。 就是说,它们是对您现有网站的增强,该过程应该不会超过几个小时,并且不会对不支持的浏览器产生负面影响。

Developer opinions vary, but there are several points to consider …

开发人员的意见各不相同,但有几点要考虑……

URL隐藏 (URL Hiding)

The demonstration site hides the URL bar, which I would not recommend unless you have a single-URL app such as a game. The manifest options display: minimal-ui or display: browser are possibly best for most sites.

该演示站点将隐藏URL栏,除非您具有游戏等单一URL应用程序,否则我不建议这样做。 清单选项display: minimal-ui或display: browser对于大多数站点, display: browser可能是最好的。

缓存过载 (Cache Overload)

You could cache every page and asset on your site. That’s fine for small sites, but would it be practical for those with thousands of pages? No one is likely to be interested in all your content, and device storage limits could be exceeded. Even if you only store visited pages and assets like the demonstration, the cache could grow excessively.

您可以缓存网站上的每个页面和资产。 这对于小型网站来说很好,但是对于具有数千个页面的网站来说是否可行? 没有人可能对您的所有内容都感兴趣,并且可能会超出设备存储限制。 即使仅像演示一样存储访问的页面和资产,缓存也可能过度增长。

Perhaps consider:

也许考虑:

only caching important pages such as the home, contact, and the most recent articles

仅缓存重要页面,例如主页,联系人和最新文章 not caching images, videos and other large files

不缓存图像,视频和其他大文件 regularly wiping older cached files

定期清除较早的缓存文件 providing a “store this page for offline reading” button so the user can choose what to cache.

提供一个“存储此页面以供离线阅读”按钮,以便用户可以选择要缓存的内容。

缓存刷新 (Cache Refreshing)

The demonstration looks for assets in the cache before loading from the network. That’s great when users are offline, but means they could be viewing old pages even when they’re online.

该演示在从网络加载之前在高速缓存中查找资产。 当用户离线时,这很棒,但意味着即使他们在线也可以查看旧页面。

URLs for assets such as images and videos should never change, so long-term caching is rarely a problem. You can ensure they remain cached for at least a year (31,536,000 seconds) with the Cache-Control HTTP header:

诸如图片和视频之类的资产的URL永远都不应更改,因此长期缓存几乎不是问题。 您可以使用Cache-Control HTTP标头确保它们保留至少一年(31,536,000秒)的Cache-Control :

Cache-Control: max-age=31536000

Pages, CSS and script files can change more frequently, so you could set a shorter expiry of 24 hours and ensure it is validated against the server version when online:

页面,CSS和脚本文件的更改频率可能更高,因此您可以将有效期设置为较短的24小时,并确保在线时针对服务器版本对它进行了验证:

Cache-Control: must-revalidate, max-age=86400

You could also consider cache-busting techniques to ensure older assets cannot be used — for example, naming your CSS file styles-abc123.css and changing the hash on every release.

您还可以考虑使用缓存清除技术来确保无法使用较旧的资产,例如,命名CSS文件styles-abc123.css并在每个发行版上更改哈希。

Caching can become complex, so I’d recommend you read Jake Archibold’s Caching best practices & max-age gotchas.

缓存可能会变得很复杂,因此,我建议您阅读Jake Archibold的“ 缓存最佳实践”和“最大寿命”。

The following resources are useful if you want to know more about Progressive Web Apps:

如果您想了解有关渐进式Web应用程序的更多信息,以下资源很有用:

PWA.rocks example applications

PWA.rocks示例应用程序

Progressive Web Apps

渐进式Web应用

Your First PWA

您的第一个PWA

Mozilla Service Worker Cookbook

Mozilla服务工作者食谱

MDN Using Service Workers

使用服务工作者的MDN

There are also many articles online that influenced how I approached this demonstration code. Feel free to adapt the code and let me know how it went. Best of luck!

网上也有许多文章影响了我处理此演示代码的方式。 随时修改代码,让我知道它的运行方式。 祝你好运!

This article was peer reviewed by AJ Latour, Panayiotis «pvgr» Velisarakos and Dave Maxwell. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

本文由AJ Latour , Panayiotis«pvgr»Velisarakos和Dave Maxwell进行同行评审。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!

翻译自: https://www.sitepoint.com/retrofit-your-website-as-a-progressive-web-app/

渐进式web应用程序

最新回复(0)