nursit / offline
Requires
- php: ^5.4.0 || ^7
This package is auto-updated.
Last update: 2024-09-06 14:46:21 UTC
README
适用于SPIP 3.1+的插件,可轻松实现现有SPIP网站的离线访问
原理
离线插件基于ServiceWorkers,允许在浏览器中缓存网站页面,并在断开互联网连接时重新使用此缓存。
ServiceWorker是一段独立代码,发送到用户的浏览器中,然后独立运行,拦截针对相关网站的请求,并在连接时将其放入缓存,或者在离线时使用缓存中的文件。
使用说明
安装插件
在.htaccess
文件的开始处添加以下RewriteRules
RewriteCond %{REQUEST_URI} offline\.api\.(.+)$
RewriteCond local/offline/%1 -f
RewriteRule ^offline\.api\.(.+)$ local/offline/$1 [QSA,L,skip=100]
在.htaccess
中修改RewriteRule以允许使用类似/offline.api.sw.js
格式的URL调用API操作
RewriteRule ^([\w]+)\.api([/.](.*))?$ spip.php?action=api_$1&arg=$3 [QSA,L]
这样,对/offline.api.sw.js
的调用将
- 如果存在,则服务静态文件
local/offline/sw.js
- 否则,将使用
?action=api_offline&arg=sw.js
的url,该url负责重建它
配置
_OFFLINE_DEBUG
常量允许插件在JS控制台输出详细日志并在服务器端不缓存ServiceWorker。首先将其添加到您的mes_options.php
文件中以测试插件(但请注意,在正式部署之前需要删除它)
define('_OFFLINE_DEBUG', true);
访问插件配置页面ecrire/?exec=configurer_offline
以配置和激活离线模式。
- 缓存版本:此版本号将用于浏览器端使用的缓存名称。例如,您可以强制用户缓存中的页面更新,以便在您发布网站的新版本后。
- 离线模式激活:选择激活模式(参见下面的工作原理)
- 页面策略:选择网站页面的服务策略
- 您可以选择优先使用网络以确保获得最新版本,但在移动网络中断的情况下,用户必须等待浏览器发现连接无法通过,然后才能从缓存中获取页面
- 您可以选择优先使用已缓存的缓存内容。在这种情况下,如果可能,内容将从网络更新,以便下次内容是最新版本
- 资源策略:这里涉及与页面关联的所有图像、CSS、JS等资源的策略
- 如果您优先使用网络,则与页面的情况相同,我们将首先尝试使用连接
- 如果您优先使用缓存,则运行将更快。在这里,对于SPIP已知的所有静态资源和带时间戳的资源,我们可以避免在后台进行更新,从而节省更多的网络请求
- 缓存媒体的最大大小(ko):您可以限制媒体(图像、音频、视频)的最大缓存大小,以避免耗尽用户的缓存。如果设置为0,则没有限制(不建议)
如果您使用大小限制,仍然可以通过在URL中添加?offline-cache
来强制缓存离线媒体。 - 离线404 URL:这是当用户请求一个不在缓存中的URL且没有网络响应时显示给用户的页面URL。默认情况下,插件提供一个基于您网站404页面的
404_offline
页面,但您可以自定义它或选择其他URL。 - 要缓存的额外资源:默认情况下,在激活时会缓存主页、离线404 URL及其资源。
如果某些特定资源缺失或您想默认缓存其他页面,请在此处指定URL。
工作原理
离线插件基于ServiceWorkers,允许在浏览器中缓存网站页面,并在断开互联网连接时重新使用此缓存。
需要理解ServiceWorker是一段发送到用户浏览器的独立代码片段,然后独立运行。如果我们修改代码或缓存版本,用户只有在访问发送新更新页面的网站并关闭然后重新打开浏览器到该网站时才会看到这些修改的效果。
因此,如果我们只是简单地停止在网站上提供此功能,所有用户将继续使用他们已下载的最后一个ServiceWorker版本。
因此,如果我们向已连接的用户提供离线模式,他们将已连接状态下安装此功能,然后每次连接时都会更新功能。但当他们断开连接时,他们将仍然享受此功能,只是没有代码更新或忽略缓存的新版本。
同样,要禁用访客的离线功能,绝对不要禁用插件!相反,您需要选择“禁用访客离线模式”并让它这样运行——或者获取禁装代码,将其硬编码在网站上,然后可以禁用插件(参看https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle#updates)
服务URLs
以下URL用于提供服务脚本:
/offline.api.install.js
:服务安装脚本,如果选择自动激活,将自动集成到公共页面的<head>
中。/offline.api.sw.js
:实际的ServiceWorker,包含配置和有用的功能。/offline.api.uninstall.js
:服务卸载脚本,如果选择禁用,将自动集成到公共页面的<head>
中。
在浏览器中,ServiceWorker的执行空间与页面的执行空间是独立的。因此,在页面(和控制台)中可用的JS函数对ServiceWorker不可用。同样,ServiceWorker的功能也无法从网站的Web页面访问。
在调试模式下,这些URL通过action/api_offline.php
动态提供服务。在生产环境中,插件会在local/offline/
中生成静态的、压缩后的文件,Apache通过修改您的.htaccess
文件以静态方式提供服务。如果您在测试生产模式后想切换回调试模式,必须删除静态文件,以便PHP脚本可以接管。
构建
Service Worker 与要下载的 URL 列表一起上传,以使某些页面离线可用 - 至少是网站主页和 404 错误页面。为了使这些页面离线可用,需要构建这些页面使用的 URL 列表。此机制需要下载每个页面,然后遍历以检测有用的资源,并检查其有效性(如果缓存请求中包含无效的 URL 或 404,则安装时不会缓存任何 URL)。
此构建可能需要时间,因此绝不会立即同步执行。它在记录新配置时作为后台任务触发。
如果您访问的网站不多或您想立即使用,您可以通过 spip-cli 命令启动。
spip offline:build:services
下载网站的部分内容以备后用。
插件提供了一个 #BOUTON_TELECHARGER_OFFLINE
标签,可以按以下方式使用。
<BOUCLE_titre(RUBRQUES){id_rubrique}>
<h1>#TITRE</h1>
[(#BOUTON_TELECHARGER_OFFLINE{rubrique,#ID_RUBRIQUE})]
</BOUCLE_titre>
您还可以传递两个可选的额外参数,对应于活动和非活动下载按钮的标签。
#BOUTON_TELECHARGER_OFFLINE{rubrique,#ID_RUBRIQUE,'Télécharger cette documentation','Téléchargement non disponible'}
下载按钮依赖于两个模板。
- 模板
offline/urls-{objet}.html
(对于文章是offline/urls-rubrique.html
)列出要下载的页面 URL,这些页面通过模板的#ENV
传递。列表是文本格式,每行一个 URL。 - 模板
offline/bouton-telecharger.html
负责显示按钮。
#BOUTON_TELECHARGER_OFFLINE
标签负责检查是否存在 offline/urls-{objet}.html
模板。如果模板不存在,则不会显示任何内容。
标签还负责检查是否已为该对象构建了 URL 列表,从由模板 offline/urls-{objet}.html
提供的页面列表构建。如果未构建 URL 列表,则启动 cron 作业构建此列表,并以 unactive
状态显示按钮。为了性能原因,按钮不是动态的:它不会在每次显示时检查列表状态,而只是在缓存更新时检查。因此,需要等待下一次缓存更新或使用 ?var_mode=calcul
强制退出此状态。
当请求的对象的 URL 列表可用时,按钮在 HTML 中以 unactive activable
状态显示。这是一个 JavaScript 函数,它负责在客户端检查 Service Worker 是否已加载,然后切换按钮到 active
状态。
同时,它还检查是否已为该对象加载了 URL 列表,如果是这样,则添加 offline-ok
类。注意,这不考虑内容更新后 URL 列表可能发生的任何更改!
最后,当用户点击按钮以(重新)下载内容时,按钮会接收到 offline-download
类。
对象的 URL 下载列表的构建可以自动通过 cron 执行,也可以通过 spip-cli 手动执行。
spip offline:build:urls --objet=rubrique --id_objet=1
构建会创建一个文本文件 config/offline/objets/urls-rubrique-1.txt
,然后浏览器通过 URL offline.api.urlsdownload.json?objet=rubrique&id_objet=1
以 json 格式加载。
在多域名网站上使用
多域名支持尚未完全可用。要下载的 URL 必须相对于访问的域名,并且如果没有 CORS 指令,则将阻止交叉 URL。
更新 URL 列表
为了确保更新所有现有的 URL 列表,可以从系统 cron 启动以下命令
spip offline:rebuild
该命令将重建 Service Worker,更新安装时需要加载的 URL 列表,并重新遍历每个存在的 config/offline/objets/urls-{objet}-{id_objet}.txt
文件,重新计算该对象的 URL 列表。
性能考虑
为了优化资源(CSS、JS)的加载和重新验证时间,建议在每个页面中将它们压缩并合并为一个单独的文件。SPIP附带的可压缩插件可以自动完成这项任务。
然而,在使用离线插件和为离线导航缓存资源时,这种做法需要重新考虑。
离线功能
从功能角度来看,合并到一个文件中存在一个主要缺点:合并文件的命名取决于其中包含的资源列表。
因此,如果某个页面包含了额外的资源,引用的合并文件将不同于其他页面,这将导致该页面的离线导航中断,或者至少需要缓存更多资源。
更糟糕的是:为了保证当包含的资源发生变化时合并文件能够更新,通常需要使用时间戳来引用这些资源。结果是:如果资源被编辑并且(即使是轻微地)修改,页面上引用的合并文件将完全更改名称。
相反,如果保留页面中的资源未合并,离线缓存的管理将简化,因为每个资源都可以独立提供。此外,插件可以智能地处理时间戳资源:缓存使用时间戳,但也使用不带时间戳的通用回退。因此,如果缓存中的某个页面缺少时间戳资源,插件将能够提供几乎等效的回退版本(除非服务器端资源有重大修改,在这种情况下建议增加缓存版本的版本号)
性能:离线 + HTTP/2
由于安全原因,使用离线插件需要https(service-workers可以深入修改网站的功能和内容,因此必须确保用户在接收时没有风险受到中间人攻击)因此,如果结合https和HTTP/2,那么全局最优解可能是禁用将样式表和JS合并为一个文件的压缩,并优先考虑资源的原子服务。
在没有使用离线模式、没有浏览器缓存的情况下,对冷启动的访问,这种页面结构的影响非常小,因为HTTP/2通过在管道中依次提供资源来补偿。一旦离线模式激活,就可以从资源原子缓存中受益,这些资源在下载一次后始终从缓存中提供服务(URL的时间戳确保在资源更改时进行新的下载)。包含更多资源的页面将加载得更快。
一旦网站访问者的主要类型是常规访问者,并且使用HTTP/2,因此应该优先考虑这种页面结构(同时要注意保留资源的单独压缩)。
参考文献
参考资料
- https://jakearchibald.github.io/isserviceworkerready/
- https://jakearchibald.com/2014/offline-cookbook/
- https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/
https://developers.google.com/web/fundamentals/primers/service-workers/
- https://mdn.org.cn/fr/docs/Web/API/Service_Worker_API
- https://mdn.org.cn/en-US/docs/Web/API/Service_Worker_API
- https://www.w3.org/TR/service-workers-1/
- https://fetch.spec.whatwg.org/#request-class
- https://fetch.spec.whatwg.org/#response-class
- https://medium.com/dev-channel/service-worker-caching-strategies-based-on-request-types-57411dd7652c
- https://googlechrome.github.io/samples/service-worker/
- https://hacks.mozilla.ac.cn/2015/03/this-api-is-so-fetching/
- https://storage.spec.whatwg.org/
重审
- https://www.captechconsulting.com/blogs/my-experience-using-service-workers
- https://philna.sh/blog/2017/07/04/experimenting-with-the-background-fetch-api/
- https://www.twilio.com/blog/2017/02/send-messages-when-youre-back-online-with-service-workers-and-background-sync.html
- https://philna.sh/blog/2018/10/23/service-workers-beware-safaris-range-request/
- https://www.construct.net/en/blogs/ashleys-blog-2/service-workers-are-a-pain-in-the-ass-934
库/框架
- https://developers.google.com/web/tools/workbox/
- http://daleharvey.github.io/Presentations/SOTR-Edinburgh-2014-06-06/#/60
- https://github.com/HubSpot/offline
- https://stackoverflow.com/questions/3181080/how-to-detect-online-offline-event-cross-browser