以下文档介绍了如何在 AEM 中构建 PWA。
先决条件:
“Adobe Experience Manager 6.4.0”的工作实例。
已安装演示 web 应用程序“weretail”(这是 AEM 默认安装的一部分)。
主机的 SSL 设置完成,即可以通过 https 访问“weretail”webapp。
请确保您可以相应地访问演示 web 应用程序“weretail”和 AEM 的管理界面。对于本文的其余部分,我们假设以下 URL:
管理界面:https://example.com:8443/aem/start
数字资产管理器(DAM)接口:https://example.com:8443/damadmin#/
Weretail webapp:https://example.com:8443/content/we-retail/us/en/experience/arctic-surfing-in-lofoten.html
根据您自己的系统的需要调整 URL。
开始
在浏览器中打开“weretail”网络应用程序。 https://example.com:8443/content/we-retail/us/en/experience/arctic-surfing-in-lofoten.html
使用 Lighthouse 测试网站(例如,使用 Chrome 的 DevTools 中内置的“审核”功能)。 “weretail” webapp 没有通过“PWA”审核。
将“weretail”webapp 转变为 PWA
从技术角度来看,如果添加以下额外资源,每个网站都可以变成 PWA:
- Service Worker,一个浏览器在后台运行的 JS 脚本,与网页分开,为不需要网页或用户交互的功能打开了大门。
- Web App Manifest,一个简单的 JSON 文件,它告诉浏览器您的 Web 应用程序以及它在“安装”在用户的移动设备或桌面上时的行为方式。
- “离线”网页,一个简单的 HTML 页面,当没有可用的网络连接时向用户显示。
- 一组图标,这些图标用于主屏幕、应用启动器、任务切换器、闪屏等地方。
服务工作者
在以下示例中,我们使用了一个非常简单的 Service Worker,基于 Workbox.js,它提供以下 PWA 功能:
“sw.js”文件内容:
importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.0/workbox-sw.js');
const offlinePage = '/content/dam/we-retail/en/experiences/48-hours-of-wilderness/offline.html';
const offlineImage = '/content/dam/we-retail/en/experiences/48-hours-of-wilderness/offline.svg';
/**
* Pages to precache
*/
workbox.precaching.precacheAndRoute([
offlinePage,
offlineImage,
]);
/**
* Enable navigation preload.
*/
workbox.navigationPreload.enable();
/**
* Basic caching for HTML pages, CSS+JS (caching max. 1 week).
*/
workbox.routing.registerRoute(
/\.(?:html|htm|js|css)$/,
new workbox.strategies.NetworkFirst({
networkTimeoutSeconds: 5,
cacheName: 'html_css_js',
plugins: [
new workbox.expiration.Plugin({
// Cache files for a week
maxAgeSeconds: 7 * 24 * 60 * 60,
// Only cache 30 files.
maxEntries: 30,
}),
],
})
);
/**
* Basic caching for JSON data (caching max. 1 day).
*/
workbox.routing.registerRoute(
/\.json$/,
new workbox.strategies.NetworkFirst({
networkTimeoutSeconds: 30,
cacheName: 'json',
plugins: [
new workbox.expiration.Plugin({
// Cache pages for a day
maxAgeSeconds: 24 * 60 * 60,
// Only cache 10 files.
maxEntries: 10,
}),
],
})
);
/**
* Basic caching for max. 60 images (caching max. 30 days).
*/
workbox.routing.registerRoute(
/\.(?:png|gif|jpg|jpeg|svg)$/,
new workbox.strategies.CacheFirst({
cacheName: 'images',
plugins: [
new workbox.expiration.Plugin({
// Cache images for 30 days
maxAgeSeconds: 30 * 24 * 60 * 60,
// Only cache 60 images.
maxEntries: 60,
}),
],
})
);
/**
* Use a stale-while-revalidate strategy for all other requests.
*/
workbox.routing.setDefaultHandler(
new workbox.strategies.StaleWhileRevalidate()
);
/**
* Basic "offline page" support
*/
workbox.routing.setCatchHandler(({event}) => {
switch (event.request.destination) {
case 'document':
// Only provide fallback for navigational requests
if (event.request.mode === 'navigate')
return caches.match(offlinePage);
else
return Response.error();
break;
case 'image':
return caches.match(offlineImage);
break;
default:
// If we don't have a fallback, just return an error response.
return Response.error();
}
});
/**
* Basic "Push notification" functionality.
*/
self.addEventListener('push', (event) => {
const title = 'Example push notification';
const options = {
body: event.data.text()
};
event.waitUntil(self.registration.showNotification(title, options));
});
网络应用清单
PWA 的“添加到主屏幕”功能需要 Web 应用清单。一个非常简单的 manifest.json 文件可能如下所示:
{
"short_name": "weretail",
"name": "WE.Retail demo webapp",
"icons": [
{
"src": "/content/dam/we-retail/en/experiences/48-hours-of-wilderness/icons-192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/content/dam/we-retail/en/experiences/48-hours-of-wilderness/icons-512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": "/content/we-retail/us/en/experience/arctic-surfing-in-lofoten.html",
"background_color": "#3367D6",
"display": "standalone",
"scope": "/content/we-retail",
"theme_color": "#3367D6"
}
“离线”网页
如果浏览器未连接到网络,则会向用户显示“离线”网页。一个非常简单的示例网页可能如下所示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Offline Page</title>
<script>
window.addEventListener('online', function(e) {
location.reload();
}, false);
</script>
</head>
<body>
<div style="text-align:center; margin-top:40px;">
<img src="/content/dam/we-retail/en/experiences/48-hours-of-wilderness/offline.svg" height="80" />
<p>You don't have an internet connection.</p>
<p>Please check your network connection and try again.</p>
<div>
</body>
</html>
一组图标
这些图标用于主屏幕、应用启动器、任务切换器、启动屏幕等位置。PWA 至少需要两个分辨率分别为 192x192 像素和 512x512 像素的图标。
将所有内容添加到 AEM
manifest.json、图标、离线页面等静态资源可以通过“数字资产管理器”上传。
如果 Service Worker 应该控制整个 webapp,那么 Service Worker 应该位于“/content/we-retail”下。
从技术上讲,Service Worker 可以放置在任何地方,但如果 Service Worker 不在网站的根目录中,则 PWA 仅限于网站的(子)部分。
有关 Service Worker 的“范围”的更多详细信息可以在这里找到:https://developers.google.com/web/ilt/pwa/introduction-to-service-worker#registration_and_scope
最后一步是将 sw.js 文件 + manifest.json 文件包含到 webapp 中。在这个非常简单的演示中,我们只需修改文件“/apps/weretail/components/structure/page/customheaderlibs.html”。
以下代码行应添加到文件“customheaderlibs.html”中:
<link rel="manifest" crossorigin="use-credentials" href="/content/dam/we-retail/en/experiences/48-hours-of-wilderness/manifest.json">
<link rel="apple-touch-icon" href="/apps/weretail/components/structure/page/clientlib/resources/apple-touch-icon.png">
<meta name="theme-color" content="black">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script>
if ('serviceWorker' in navigator)
{
window.addEventListener('load', () => {
navigator.serviceWorker.register('/content/we-retail/sw.js');
});
}
</script>
保存所有更改并重新加载 web 应用。如果一切正常,那么 webapp 现在已经变成了 PWA。使用 Lighthouse 再次验证 webapp。