最近,渐进式 Web 应用程序通过混合方法和渐进式增强提供了更好的 Web 体验和丰富的用户交互。此外,它快速、使用安全、无需互联网连接即可工作,并解决了网站和移动应用程序的一些问题。
在本教程中,我们会将 React 项目转换为 PWA。我们还将探索一些附加功能,例如 Web 应用清单和服务工作者。
先决条件
对 React 的基本了解。
什么是渐进式 Web 应用程序?
渐进式 Web 应用程序是一种现代 Web 技术,它具有本机应用程序的大部分优点。这是一种在本机应用程序中创建类似体验的 Web 开发方法。它本质上结合了 Web 和原生应用程序的品质,以提供更好的用户体验和转化率。
PWA 的特点
除了提供更好的设备集成外,PWA 还具有以下功能:
- 易于开发和升级到新版本。
- 在多个移动设备和台式计算机上独立工作。
- 可以在所有主要浏览器和平台上安装。
- 使用智能缓存快速离线和在线工作
- 快速加载时间和性能。
- 访问推送通知。
PWA 工作原理的图示
PWA 的组成部分
PWAs 由三个主要部分组成,即:
- 网络应用清单
- 服务人员
- 应用分发模块
这些已集成到 Web 应用程序中,并使用 Web 标准或 React 等框架构建,以更轻松地呈现内容和测试 PWA。
网络应用清单
这是一个 W3C 规范标准,包含提供有关 Web 应用程序信息的元数据。它是一个 JSON 文件,其中包含添加到服务器并在标签中引用的详细信息。
服务工作者
这就像 Web 应用程序、浏览器和可用网络之间的代理一样。它拦截应用程序发出的所有网络请求。
应用分发模块
这维护了界面并在有或没有网络连接的情况下处理内容。
将 React 应用程序转换为 PWA
为了通过几个简单的步骤创建一个渐进式 Web 应用程序,我们将使用一个已经存在的项目 - React Play,因此我们可以专注于添加 PWA 功能。下一步是 fork Github 存储库并运行以下命令:
git clone https://github.com/reactplay/react-play.git
cd reactplay
npm install
#OR
yarn install
使用以下命令以开发模式启动应用程序:
npm start
#OR
yarn start
现在,我们应该在浏览器中看到这个项目https://localhost/3000
构建 PWA 的步骤
1.更新Manifest.json
首先,我们导航到public
目录并生成一个manifest.json
文件。设置提供的图标和其他选项。让我们首先public/manifest.json
使用以下代码进行更新:
{
"short_name": "ReactPlay",
"name": "ReactPlay",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192x192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512x512.png",
"type": "image/png",
"sizes": "512x512"
},
{
"src": "maskable_icon.png",
"sizes": "64x64 32x32 24x24 16x16 512x512 192x192",
"type": "image/png",
"purpose": "maskable"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
那么,这些字段代表什么:
-
name
:网络应用程序的名称。 -
short name
: 一个准确易记的名字,它可以是一个首字母缩略词。 -
icons
:Web 应用程序的自定义图标集。 -
start_url``home
:指示浏览器在 PWA 启动时加载页面。 -
display
:外观类似于原生应用。 -
theme_color
:工具栏的颜色。 -
background_color``splash screen
: PWA 启动时的颜色。
您需要为大小为 16、32、48、152 和 192 像素等尺寸的项目创建自定义图标。
为确保 PWA 得到很好的优化,请确保文件中包含以下meta
标签:``index.html
2.创建服务工作者
在src
我们的 React 应用程序的目录中,创建一个service-worker.js
并添加以下逻辑:
import { createHandlerBoundToURL, precacheAndRoute } from "workbox-precaching";
import { clientsClaim } from "workbox-core";
import { registerRoute } from "workbox-routing";
import { CacheFirst, StaleWhileRevalidate } from "workbox-strategies";
import { ExpirationPlugin } from "workbox-expiration";
import { CacheableResponsePlugin } from "workbox-cacheable-response";
clientsClaim();
precacheAndRoute(self.__WB_MANIFEST);
const fileExtensionRegexp = new RegExp("/[^/?]+\\.[^/]+$");
registerRoute(({ request, url }) => {
if (request.mode !== "navigate") {
return false;
}
if (url.pathname.startsWith("/_")) {
return false;
}
if (url.pathname.match(fileExtensionRegexp)) {
return false;
}
return true;
}, createHandlerBoundToURL(process.env.PUBLIC_URL + "/index.html"));
registerRoute(
({ url }) => {
const formatImages = [".jpeg", ".jpg", ".png", ".svg", ".gif"];
const ifImage = formatImages.some((i) => url.pathname.endsWith(i));
return url.origin === self.location.origin && ifImage;
},
new StaleWhileRevalidate({
cacheName: "images-cache",
plugins: [new ExpirationPlugin({ maxEntries: 50 })],
})
);
registerRoute(
({ url }) => {
return url.origin === self.location.origin;
},
new CacheFirst({
cacheName: "api-cache",
plugins: [
new CacheableResponsePlugin({
statuses: [200],
}),
],
})
);
self.addEventListener("message", (event) => {
if (event.data && event.data.type === "SKIP_WAITING") {
self.skipWaiting();
}
});
3.注册Service Worker
registerServiceWorker.js
接下来,在同一src
目录中创建一个。
import { Workbox } from "workbox-window";
const register = () => {
if (process.env.NODE_ENV !== "production") return;
if (navigator?.serviceWorker) {
const wb = new Workbox(`${process.env.PUBLIC_URL}/service-worker.js`);
const checkForUpdate = () => {
const isUpdate = window.confirm("New Update Available. Click OK to update");
if (isUpdate) {
wb.messageSkipWaiting();
}
};
wb.addEventListener("waiting", checkForUpdate);
wb.register();
}
};
export default register;
下一步是注册网络应用程序service worker
。所以,导入registerServiceWorker.js
.index.js
import register from "./registerServiceWorker";
紧接着const container = document.getElementById("root"); createRoot(container).render(
,调用register
函数:
register();
此实现使应用程序脱机工作并更快地加载。
这是它的外观:
import RouteDefs from "common/routing/RouteDefs";
import { SearchContext } from "common/search/search-context";
import "index.css";
import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import reportWebVitals from "reportWebVitals";
import register from "./registerServiceWorker";
if (process.env.NODE_ENV !== "development") {
console.log = () => {};
console.debug = () => {};
console.info = () => {};
console.disableYellowBox = true;
}
const Index = () => {
const [searchTerm, setSearchTerm] = useState("");
const [showShareModal, setShowShareModal] = useState(false);
const [filterQuery, setFilterQuery] = useState({
level_id: "",
tags: [],
owner_user_id: "",
language: "",
});
const value = {
searchTerm,
setSearchTerm,
filterQuery,
setFilterQuery,
showShareModal,
setShowShareModal,
};
return (
);
};
const container = document.getElementById("root");
createRoot(container).render( );
register();
现在,该图标应该出现在您的桌面浏览器选项卡上,以便直接安装。
在移动设备上,安装提示看起来有点不同。
单击时,显示一个弹出窗口Install。
测试 PWA
Web 应用程序必须通过某些标准才能被识别为 PWA。这些标准是使用 PWA 工具测量的,例如 Lighthouse - 一种用于根据 PWA 标准测试网站的开源 Chrome 工具。
导航到Developer tools面板,选择Lighthouse、选中Progressive Web App,然后选择Analyze page load。在分析结束时,它将显示通过的标准和失败的标准(如果有)。
PWA 得分 100%
通过的标准会给出一段green check mark时间,而失败的标准会red check mark用问题的详细信息表示。
结论
尽管 PWA 提供了本机应用程序的一些品质和功能,但它们有一些限制,并且不会完全取代本机应用程序。
正如我们所见,将 React 应用程序转换为渐进式 Web 应用程序具有一些优势。我希望您发现这对您有所帮助,并会考虑将此功能集成到您的下一个项目中。
来源:https://blog.reactplay.io/building-a-progressive-web-application-pwa-using-react