java web 速成
渐进式Web应用程序(PWA)试图通过向移动用户提供每种功能的最佳功能来重叠移动Web应用程序和本机移动应用程序的世界。
它们提供类似应用程序的用户体验(启动屏幕和主屏幕图标),由受HTTPS保护的服务器提供服务,即使在质量较低或网络速度较慢的情况下,也可以快速加载(由于页面加载性能的最佳做法),并且他们具有离线支持,即时加载和推送通知。 PWA的概念最初是由Google提出的,但仍受许多Chrome功能和出色工具的支持,例如Lighthouse,这是一个用于辅助功能,性能和渐进性审核的开源工具,我们将在稍后进行探讨。
在整个崩溃过程中,我们将使用ES6和React从零开始构建PWA,并使用Lighthouse逐步对其进行优化,直到在UX和性能方面取得最佳结果为止。
术语“ 渐进式”仅表示PWA的设计方式,使其可以在现代浏览器中逐步增强,这些浏览器已经支持许多新功能和新技术,但在没有尖端功能的旧浏览器中也可以正常工作。
本地应用程序可以从移动操作系统的相应应用程序商店中分发和下载。 另一方面,只需在Web浏览器中输入地址或URL,即可访问它们。 从用户的角度来看,启动浏览器并导航到某个地址比去应用商店并下载,安装然后启动该应用更加方便。 从开发者/所有者的角度来看,支付一次费用来获取应用商店帐户,然后上载其应用以供全世界的用户访问,这比必须处理网络托管的复杂性要好。
本机应用程序可以脱机使用。 如果需要从某个API服务器检索远程数据,则可以轻松地设计该应用程序以支持对最新访问数据的某种SQLite缓存。
谷歌等搜索引擎可为移动网络应用编制索引,并且通过搜索引擎优化,您可以吸引更多用户。 对于本机应用程序也是如此,因为应用程序商店拥有自己的搜索引擎,开发人员可以在其中使用不同的技术(通常称为“应用程序商店优化”)来吸引更多用户。
本地应用程序会立即加载,至少会在启动屏幕上加载,直到为执行该应用程序准备好所有资源为止。
这些是最重要的感知差异。 每种应用程序分发方法都对最终用户(关于用户体验,可用性等)和应用程序所有者(关于成本,客户覆盖范围等)都有好处。 考虑到这一点,Google引入了PWA,将双方的最佳功能整合到一个概念中。 Google Chrome工程师Alex Russell在这份清单中总结了这些方面。 (来源: 不经常提及 。)
Lighthouse是用于审核Google创建的Web应用程序的工具。 它与Chrome开发工具集成在一起,可以从“审核”面板中触发。
您还可以将Lighthouse用作NodeJS CLI工具:
npm install -g lighthouse
然后可以使用以下命令运行它:
lighthouse https://sitepoint.com/
Lighthouse也可以安装为Chrome扩展程序,但是Google建议使用与DevTools集成的版本,并且仅在您因某种原因无法使用DevTools时才使用该扩展程序。
请注意,即使您使用的是基于CLI的版本,也需要在系统上安装Chrome才能使用Lighthouse。
在本节中,我们将从头开始创建一个渐进式Web应用程序。 首先,我们将使用React和Reddit的API创建一个简单的Web应用程序。 接下来,我们将按照Lighthouse报告提供的说明添加PWA功能。
请注意,公共无身份验证Reddit API启用了CORS标头,因此您可以在没有中间服务器的情况下从客户端应用程序使用它。
在我们开始之前,本课程将假设您已经安装了NodeJS和NPM的开发环境设置。 如果您没有这样做,请从令人敬畏的Homestead Improvementd开始 ,它正在运行每个版本的最新版本,并且可以立即进行开发和测试。
我们首先安装Create React App,这是React团队创建的项目样板,可帮助您避免WebPack配置的麻烦。
npm install -g create-react-app
create-react-app react-pwa
cd react-pwa/
应用程序外壳是渐进式Web应用程序的基本概念。 这只是负责呈现用户界面的最少HTML,CSS和JavaScript代码。
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
此应用程序外壳程序对性能有很多好处。 您可以缓存应用程序外壳程序,以便当用户下次访问您的应用程序时,将立即加载该外壳程序,因为浏览器不需要从远程服务器获取资产。
为了构建一个简单的UI,我们将使用Material UI,这是React中Google Material design的一个实现。
让我们从NPM安装软件包:
npm install material-ui --save
接下来打开src/App.js
然后添加:
import React, { Component } from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import AppBar from 'material-ui/AppBar';
import {Card, CardActions, CardHeader,CardTitle,CardText} from 'material-ui/Card';
import FlatButton from 'material-ui/FlatButton';
import IconButton from 'material-ui/IconButton';
import NavigationClose from 'material-ui/svg-icons/navigation/close';
import logo from './logo.svg';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
posts: []
};
}
render() {
return (
React PWA}
iconElementLeft={ }
iconElementRight={ this.fetchNext('reactjs', this.state.lastPostName)} label="next" />
}
/>
{this.state.posts.map(function (el, index) {
return
{el.data.selftext}
{
window.open(el.data.url);
}} />
})}
this.fetchNext('reactjs', this.state.lastPostName)} label="next" />
);
}
}
export default App;
接下来,我们需要使用两种方法fetchFirst()
和fetchNext()
来获取Reddit帖子:
fetchFirst(url) {
var that = this;
if (url) {
fetch('https://www.reddit.com/r/' + url + '.json').then(function (response) {
return response.json();
}).then(function (result) {
that.setState({ posts: result.data.children, lastPostName: result.data.children[result.data.children.length - 1].data.name });
console.log(that.state.posts);
});
}
}
fetchNext(url, lastPostName) {
var that = this;
if (url) {
fetch('https://www.reddit.com/r/' + url + '.json' + '?count=' + 25 + '&after=' + lastPostName).then(function (response) {
return response.json();
}).then(function (result) {
that.setState({ posts: result.data.children, lastPostName: result.data.children[result.data.children.length - 1].data.name });
console.log(that.state.posts);
});
}
}
componentWillMount() {
this.fetchFirst("reactjs");
}
您可以在GitHub Repository中找到源代码。
在对您的应用进行审核之前,您需要构建并使用本地服务器在本地为您的应用提供服务:
npm run build
该命令调用package.json
的构建脚本,并在react-pwa/build
文件夹中生成一个构建。
现在,您可以使用任何本地服务器来服务您的应用程序。 在Homestead Improvementd上,您只需将nginx虚拟主机指向build文件夹并在浏览器中打开homestead.app
,或者可以通过NodeJS使用serve
软件包:
npm install -g serve
cd build
serve
使用serve
,您的应用程序将从http:// localhost:5000 /在本地提供。
您可以审核您的应用程序而没有任何问题,但是如果您想在移动设备上对其进行测试,则还可以使用surge.sh
服务通过一个命令来部署它!
npm install --global surge
接下来,从任何目录中运行涌流,以将该目录发布到Web上。
您可以从此链接中找到此应用程序的托管版本。
现在,我们打开Chrome DevTools,转到“审核”面板,然后单击“执行审核”。
从报告中我们可以看到, 渐进式Web App的得分为45/100 , 性能为68/100 。
在Progressive Web App下,我们有6个失败的审核和5个通过的审核。 这是因为默认情况下,生成的项目已经添加了一些PWA功能,例如Web清单,视口meta和
标记。
在“ 性能”下,我们具有诊断程序和不同的计算指标,例如“第一有意义的油漆”,“第一交互式”,“一致交互式”,“感知速度指数”和“估计输入延迟”。 稍后我们将对其进行研究。
Lighthouse建议通过减少下载大小或推迟不必要的资源下载来减少关键渲染链的长度,从而提高页面加载性能。
请注意, 性能得分和指标值可以在同一台计算机上的不同审核会话之间改变,因为它们受许多不同条件的影响,例如您当前的网络状态以及您当前的计算机状态。
根据DoubleClick(一家Google广告公司)的说法,如果加载网页需要3秒钟以上的时间,则将有53%的移动网站访问被放弃 。 通过优化页面加载性能和速度,PWA通过一系列技术和策略为用户提供即时的Web体验,我们将在后面介绍。
大多数客户端应用程序是使用某种JavaScript库或框架(例如React,Preact,Angular,Vue等)构建的。如果要构建PWA,则需要确保选择移动优先的库,或者换句话说,首先是为移动网络设计的库。 否则,优化应用程序的性能将是不可能完成的任务。
您需要使用不同的测试工具(例如Chrome DevTools,Lighthouse,Google PageSpeed等)来在不同的模拟网络条件下对应用程序进行大量测试,以便成功优化应用程序页面加载性能。
您可以使用Lighthouse通过不同的指标,诊断和机会来衡量和优化应用程序的页面加载性能。
Lighthouse使用不同的指标。 让我们一一介绍它们:
第一有意义的绘画是仅指示用户可以在屏幕上看到有意义或主要内容的时间的度量。 审核次数越少,您的应用感知性能越好。
这是我们应用的指标。
我们看到,从1.3s开始,浏览器开始呈现空白背景,然后从2s开始,浏览器开始呈现标题,而2.4s则显示了标题和底部的按钮。 直到第三秒才发布帖子。 整个过程耗时3.4秒,第一个有意义的绘制时间为2.340毫秒 -呈现了没有下一个按钮的标题时。
首先有意义的绘画实际上取决于我们认为有意义的内容,不同用户之间可能会有所不同。 如果用户只对阅读帖子感兴趣,那么对他们来说,第一个有意义的绘画是在3秒标记之后。 您可以查看Google如何根据此文档计算该指标。
这是同一应用程序的另一个幻灯片,在最后一个屏幕截图中,Lighthouse报告FMP为2.560ms ,其中帖子标题完全显示在首屏区域中。
其次,您可以看到页面是逐步呈现的,而不是一次呈现的,这很好地表明了性能。
您可以通过优化关键渲染路径来优化此度量。
关键的渲染路径是与Web浏览器如何渲染页面有关的概念,即从接收HTML,CSS和JavaScript资产的第一刻到浏览器处理和渲染实际有意义的内容的步骤。 要优化关键渲染路径,您需要赋予与用户当前操作相关的内容更高的优先级。 也就是说,如果他们要访问您的应用程序,则可以首先显示UI的可见部分,即所谓的“首屏”区域。
有关更多详细信息,您可以阅读“ 优化关键渲染路径 ”。
您还可以看到此清单工具的清单,这些清单用于内联关键CSS资产。 还要检查以下工具以内联JavaScript和其他资产:
关键请求链是与关键渲染路径有关的概念,可以用分解表示关键资源以绘制页面,每个资源花费多少时间以及为每个资源下载多少字节的图表来表示。 您可以使用“关键请求链”图更好地了解关键资源,以消除,延迟或标记为异步。 以下是我们的示例PWA报告的屏幕截图:
现在,我们尝试使用inline-source
和inline-source-cli
解决此问题:
npm install -g inline-source inline-source-cli
然后,我们在build文件夹中导航并打开index.html
,然后将关键字inline添加到要内联的和
元素中:
让我们内联这些资源:
cd build
cat ./index.html | inline-source --root ./ > ./index.html
通过内联CSS和JavaScript资产,我们将关键请求链减少到2个。
这两个指标均指示用户能够与该应用进行交互的时间。 两种指标都表示参与性和可用性,但是它们之间存在差异。 第一个交互式测量当页面是最低限度的互动,而一贯互动页面时完全互动的措施。
您可以通过优化关键渲染路径来优化交互时间。
感知速度指数是一种度量页面的视觉性能的指标,同时考虑了布局稳定性(UI元素没有突然移位)。 它仅表示页面内容的可见填充速度。
PSI是SI或Speed Index度量标准的修改版本,SI或Speed Index度量标准是显示折叠(可见)区域而不考虑视觉稳定性的平均时间。
您还可以通过优化关键渲染路径来优化此指标。
估计的输入等待时间是一个指标,它指示主线程何时准备好处理输入。
您可以在此处阅读有关此指标的更多信息以及如何通过它。
维基百科将TTFB定义为:
到第一字节的时间(TTFB)是一种度量,用于指示Web服务器或其他网络资源的响应能力。 TTFB测量从用户或客户端发出HTTP请求到客户端的浏览器接收到页面的第一个字节的持续时间。
您可以使用WebpageTest和Lighthouse等工具来测量PWA的TTFB。 有关更多信息,请参见此链接 。
现在,让我们看看开发人员用来优化这些指标的一组概念和常用技术。
近年来,JavaScript生态系统发生了翻天覆地的变化,诸如WebPack和Browserify之类的模块捆绑器等新工具用于将所有脚本捆绑到一个文件中。 这被认为是一种好习惯,因为它有助于将对多个脚本文件的网络请求减少为一个请求(用于获取整个捆绑包),从而优化了关键的渲染路径(没有长时间阻塞JavaScript和CSS资产)。 但是问题是,对于大型应用程序,捆绑包的大小会更大,从而导致下载捆绑包,处理捆绑包,然后启动应用程序的过程效率极低,这会影响即时Web体验(增加了首次有意义的时间绘画和UI互动的时间)。
作为此问题的解决方案,不同的应用程序使用代码拆分和基于路由的分块(将代码拆分为仅对每个路由都是必需的块)。 因此,浏览器只需要下载呈现第一个页面/路线所需的第一个块,然后在用户导航其他路线时懒加载剩余的块。
服务器端渲染是在服务器而非浏览器上渲染初始内容的过程-在许多情况下,这可以提高页面加载性能,因为浏览器可以在下载内容后立即显示内容(纯HTML)。
由于需要下载和启动JavaScript资产,因此仅服务器端渲染对优化用户交互时间没有太大帮助。
PRPL是一种性能模式,它利用诸如HTTP / 2服务器推送,预加载标头,服务工作程序和延迟加载之类的概念来提高PWA交付和启动的性能。
PRPL代表:
资料来源:Google Web基础知识
缓存是将经常请求的数据保存在紧密存储位置的过程。 对于网络,这就是浏览器的内存或数据库。 浏览器实际上具有专门用于缓存网络响应的缓存位置,但是开发人员还可以利用其他存储机制,例如HTML5 Local Storage API和IndexedDB。
您可以缓存应用程序外壳程序(负责呈现UI的资产),数据或理想情况下两者。 缓存UI对于实现即时Web体验至关重要。 但是数据呢?
我们可以在这里考虑两类应用。 仅需要网络连接来使资产负责呈现UI和/或需要它来提供核心功能的应用程序。 例如,考虑一个为用户提供个人核算的应用程序,该应用程序仅取决于算法和计算(本地CPU)。
第二类是依赖远程服务器获取更新信息的应用程序。 您可能想知道为什么要缓存数据,因为它很快就会过时并且用户大多需要更新的信息。 问题是,在世界许多地方,问题不在于网络连接的永久中断,而是网络在缓慢和良好信号之间的波动状态,即使应用已经加载,这仍会影响用户体验。
该应用可以利用数据缓存(利用Background Sync API的优势)来保证用户在页面之间导航时(即使他们在短时间内离开并回到应用中)的服务,方法是持续观看网络状态,然后继续在不中断用户的情况下获取/发送数据。
现在,让我们解决失败的问题以获得更高的分数。
第一次失败的审核是说该应用程序未注册服务工作者。 在进行更改之前,让我们首先了解服务人员和相关功能。
服务工作者是一种现代浏览器技术,可以用作客户端代理,允许您的应用程序(通过拦截网络请求)实施缓存以添加诸如即时加载和脱机支持等功能。
服务人员还可以用于实施更新和处理推送通知。
服务工作者无法访问页面DOM,但可以通过postMessage()
方法与客户端(Window,Worker或SharedWorker)进行通信。
许多浏览器API可用于服务工作者内部,例如:
服务人员有许多生命周期事件,需要适当处理。
.register()
之后触发(在下载和安装事件之后) React项目已经包含一个服务工作者。 我们可以使用它,也可以创建一个新的库,以便更好地了解服务人员的工作方式。
在public
文件夹中,让我们创建一个名为service-worker.js
的新文件,然后通过在
之前添加以下代码从public/index.html
文件中注册该文件:
这段代码首先检查浏览器是否支持服务人员,然后侦听页面加载事件。 加载页面后,它会调用navigator.serviceWorker.register
方法来注册public/service-worker.js
。
现在,我们需要创建一个JavaScript文件public/service-worker.js
并添加以下代码来设置缓存:
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('react-pwa-v1')
.then(function(cache) {
// The asset-manifest.json contains the names of assets to cache
fetch("asset-manifest.json")
.then(response => {
return response.json()
})
.then(assets => {
cache.addAll(
[
"/",
"https://fonts.googleapis.com/css?family=Roboto:300,400,500",
assets["main.js"],
assets["main.css"],
assets["static/media/logo.svg"]
]
);
})
})
);
});
在服务工作者安装事件中,我们首先使用caches.open()
方法打开缓存,然后使用fetch()
获取WebPack生成的asset-manifest.json
文件,以将哈希资产映射到其原始名称。 接下来,我们调用cache.addAll()
将这些资产添加到应用程序缓存中:
// Serves the cached response for the corresponding request
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request).then(function(response) {
if(response) return response;
return fetch(event.request);
})
);
});
此代码通过侦听fetch事件并在应用程序缓存中存在缓存的响应(使用caches.match()
方法)时对其进行响应,从而拦截每个网络请求。 否则,我们通常调用fetch()
来获取资产:
self.addEventListener("activate", event => {
event.waitUntil(
caches.keys()
.then(keys =>
Promise.all(keys.map(key => {
if (key !== 'react-pwa-v1') {
return caches.delete(key);
}
}))
)
);
});
激活该应用后,如果与当前缓存不同,我们将删除旧缓存。
这是用于缓存静态资产的简单服务工作者。 我们还可以使用高级工具来生成服务工作者,例如:
如果我们现在对应用程序进行审核,则PWA分数应为91。
该应用程序现在可以提示用户将其安装在设备的主屏幕或架子上。
我们的审核失败了,这表明我们需要将HTTP流量重定向到HTTPS,但这超出了本文的范围 。 但是,一旦执行此操作,这些就是性能的最终结果:
通过通过JavaScript和CSS内联减少关键请求链 ,我们优化了关键渲染路径 ,这是我们之前看到的大多数性能指标所依赖的。 但是请记住,这个PWA非常简单; 它只有一页,React在设计时考虑了性能。 这就是我们如此之快获得95/100得分的原因。
为了涵盖渐进式Web应用程序的所有核心原则,我还将在Lighthouse报告中解释通过的审核。
由于我们是在本地审核应用程序(来源: http://localhost
),Lighthouse假设它是安全的,因此HTTPS审核被标记为已通过,但是一旦使用实际主机并链接到顶层,就不会发生这种情况。域名,除非您实际拥有SSL证书。 (请注意,仅从安全来源为服务工作者提供服务,本地主机除外)。
您可以使用GitHub Pages托管您的应用程序,从而为您提供HTTPS保护的子域(github.io)。 您还可以将Firebase托管与受保护的子域一起使用,也可以免费使用Surge(surge.sh)(还附带基本的SSL证书)。
如果您决定链接自己的顶级域,则还可以通过Let's Encrypt或Cloudflare获得免费的SSL证书。
对于本课程,我们实际上不需要将应用程序托管在受HTTPS保护的服务器上,因为Lighthouse在本地测试时会通过此审核。
Web应用程序清单是一个JSON文件,可提供有关PWA的信息,例如名称,图标和描述等。 它允许用户像本地应用程序一样在主屏幕上安装Web应用程序,而无需通过应用程序商店。
需要使用rel属性设置为manifest的标记从
index.html
文件引用Web应用程序的清单 。
例如,简单生成的React应用程序具有一个public/manifest.json
文件,其内容如下:
{
"short_name": "ReeditPWA",
"name": "Reedit React PWA",
"icons": [
{
"src": "icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
从public/index.html
引用:
浏览器以前不支持PWA初始屏幕,因此,当用户从主屏幕图标运行应用程序时,他们通常会经过白屏几秒钟,才能看到实际的应用程序用户界面。 从Chrome 47开始,用户可以看到启动屏幕,该屏幕可以提高感知性能,并使用户从轻按主屏幕图标过渡到应用的第一幅画。
简而言之,感知性能是一种与用户的观点和体验有关的指标,而不是与实际性能/页面加载速度相关的指标-提供有关您的应用对最终用户的实际感觉的信息。
您可以阅读有关性能感知的文章,以了解更多信息。
此初始屏幕是根据Web清单中的信息动态地为您的应用程序构建的,但是(根据Lighthouse),您需要在manifest.json
文件中具有至少512×512大小的图标,才能获得高质量的初始屏幕。
因此,只需准备一个尺寸至少为512×512的图标,然后将以下内容添加到manifest.json
下的manifest.json
:
{
"src": "splashscreen-icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
PWA的核心宗旨之一是渐进增强功能,它是指PWA在不同浏览器上运行的功能,但只有在受支持的情况下,才能提供更高级的功能。
您也可以阅读“ JavaScript依赖反弹:神话般的渐进增强 ”,以了解有关渐进增强的更多信息。
渐进增强的一个简单示例是在不支持JavaScript的浏览器中执行应用程序时,或者至少在禁用JavaScript时。 您可以使用HTML 标记告诉用户应该启用JavaScript,而不是什么都不显示:
Chrome是第一个正式支持PWA的浏览器。 因此,Chrome的DevTools具有出色的PWA调试功能,特别是包含在两个面板(“ 审核”面板和“ 应用程序”面板)中。
在“ 审核”面板下,您可以找到我们之前看到的Lighthouse工具。 在“ 应用程序”面板下,您可以找到许多有用的工具来调试PWA的核心方面,例如:
在世界许多地方,移动设备通过速度较慢且不稳定的网络进行连接,因此为了提供更好的用户体验和可接受的加载时间,或者,更好的是,对于网络速度各异的大量用户而言,它们是即时的Web体验-您需要在可能不同的条件下优化应用程序。 借助Chrome DevTools的“ 网络”面板,您可以仿真多种网络条件,例如慢速3G,快速3G和离线状态,甚至可以使用自己的“ 下载” ,“ 上传”和“ 延迟”参数自定义值创建自定义配置文件。
“网络”面板提供了其他功能,例如禁用缓存,关闭脱机状态以及在加载时间获取应用程序屏幕截图。
禁用缓存和激活脱机状态对于调试PWA尤其有用。
有关更多信息,请查看Google的“ 网络分析参考 ”。
PWA不仅是另一个注重性能的应用程序。 不仅如此! 得益于软件行业的大公司-Google,Microsoft等-他们正在成为多个平台上的一流应用程序。
除了性能优势之外,您也可以将其集成到任何Web应用程序中,即使您不打算构建完全合格的PWA,PWA也可以提供以下功能:
的真正的Android应用程序 ,它告诉Android拦截任何链接上的点击属于您的应用范围,然后打开PWA(而不是Chrome)。 希望该速成课程能够帮助您开始使用PWA验证自己的Web应用程序!
翻译自: https://www.sitepoint.com/progressive-web-apps-a-crash-course/
java web 速成