漸進式 Web 應用程序的構建塊
已發表: 2022-03-10Web 應用可以一次性取代原生應用和網站的所有功能。 這些天來,它們越來越引人注目,但仍然沒有足夠多的人熟悉它們或採用它們。
在本文中,您將能夠找到有關如何製作漸進式 Web 應用程序的一些注意事項,以及進一步研究的資源。 我還將討論各種組件並支持圍繞 Web 應用程序的問題。 儘管不是每個瀏覽器都對它們友好,但仍有一些令人信服的理由來了解更多關於這項技術的信息。
是什麼讓 Web 應用程序漸進式?
漸進式網絡應用程序是某些技術的總稱,這些技術共同在網絡上產生類似應用程序的體驗。 為簡單起見,從現在開始,我將它們簡稱為 Web 應用程序。
理想的 Web 應用程序是具有 Web 和本地應用程序的最佳方面的網頁。 它應該能夠快速和快速地進行交互,適合設備的視口,保持離線可用,並且能夠在主屏幕上有一個圖標。
同時,它不能犧牲讓網絡變得偉大的東西,例如深入鏈接到應用程序的能力以及使用 URL 來實現內容共享的能力。 與網絡一樣,它應該跨平台運行良好,而不是僅僅專注於移動設備。 它在台式計算機上的表現應該與在其他形式因素中一樣好,以免我們冒著進入另一個無響應的 m.example.com 網站時代的風險。
漸進式 Web 應用程序並不新鮮。 自 2011 年以來(Chrome Android 上為 2013 年),移動瀏覽器已經能夠將網站添加到手機的主屏幕上, head
的元標記決定了已安裝網頁的外觀。 自 2012 年以來,《金融時報》一直在使用網絡應用程序在移動設備上交付數字內容。
遷移到 Web 應用程序後,《金融時報》能夠使用同一個應用程序在單一分發渠道中跨平台發布。 當我在《金融時報》工作時,通過一個構建,我們能夠支持以下內容:
- iOS,
- 安卓 (4.4+) 鉻,
- 較舊的 Android(通過包裝器),
- 視窗 8,
- 黑莓,
- 火狐操作系統。
真正做到了“一次構建,隨處部署”。
“但它不在 App Store 中”
對於大多數大公司來說,用網站補充原生應用程序仍然是標準做法,這是有充分理由的。 其中包括對瀏覽器支持的擔憂,以及大多數用戶習慣使用本機應用程序這一事實。 稍後我將更詳細地討論這些問題。 這些擔憂中最重要的是,如果應用程序不在應用商店中,它將如何獲得曝光。
我會爭辯說,在應用商店中並沒有太大的優勢,因為已經表明,如果你不在應用商店中排名前 0.1% 的應用程序中,那麼你不會從那裡獲得顯著的好處。
用戶傾向於通過首先找到您的網站來找到您的應用程序。 如果您的網站是一個網絡應用程序,那麼它們已經到達目的地。
Web 應用程序的優勢之一是,它使您能夠通過減少在登陸您的網站和與您的應用程序互動之間重新吸引用戶所需的點擊次數來提高參與度。
通過讓用戶通過將其添加到他們的主屏幕來“安裝”您的網絡應用程序,他們可以繼續與您的網站互動。 當他們關閉網絡瀏覽器時,手機會向他們顯示網絡應用程序的安裝位置,讓您恢復他們的意識。
背景和當前氣候
現代 Web 應用程序基於一種稱為服務工作者的新技術。 服務工作者是位於用戶標籤和更廣泛的互聯網之間的可編程代理。 它們攔截並重寫或製造網絡請求,以允許非常精細的緩存和離線支持。
自 2011 年 Web 應用程序誕生以來,該應用程序可以將網站添加到主屏幕上,已經發生了許多發展,為創建漸進式 Web 應用程序奠定了更多基礎。
Chrome 38 引入了 Web 應用清單,它是一個 JSON 文件,用於描述您的 Web 應用的配置。 這使我們能夠從head
中刪除配置。
在 Chrome 40(2014 年 12 月)中,服務工作者開始在 Firefox 和 Chrome 上推出。 截至撰寫本文時,Apple 已選擇不在 Safari 中實現此功能,但“正在考慮中”。 service worker 的作用是簡化應用下線的過程; 它還為未來的類似應用程序的功能奠定了基礎,例如推送通知和後台同步。
基於新服務工作者和 Web 應用程序清單構建的應用程序被稱為漸進式 Web 應用程序。
漸進式 Web 應用程序與規範不同。 事實上,考慮到瀏覽器中內置的新技術,它一開始是對 Web 應用程序在服務工作者時代的定義。 具體來說,當滿足多個條件時,Chrome 使用此定義在瀏覽器中觸發安裝提示。 條件是網絡應用程序:
- 有一個服務工作者(需要 HTTPS);
- 有一個 Web 應用清單文件(至少具有最少的配置和
display: "standalone"
); - 有兩次不同的訪問。
在這種情況下,“漸進式”意味著瀏覽器支持的功能越多,體驗就越接近應用程序。
目前在 Opera、Chrome 和三星瀏覽器的不同條件下會顯示安裝 Web 應用程序的提示。
Apple 已經表示對 iOS 的漸進式 Web 應用程序感興趣,但在撰寫本文時,它仍然依賴於元標記來配置 Web 應用程序和應用程序緩存 (AppCache) 以供離線使用。
網站在什麼時候成為 Web 應用程序?
我們知道一個網站是什麼樣子,一個應用程序是什麼樣子,但是一個網站在什麼時候變成了一個網絡應用程序? 沒有明確的衡量標準來說明什麼是網絡應用程序而不是網站。
在這裡,我們將詳細介紹 Web 應用程序的特徵。
漸進式 Web 應用程序應該表現出某些類似應用程序的屬性……
- 響應式
這些網站完美地填滿了屏幕,主要針對手機和平板電腦,並且必須響應過多的屏幕尺寸。 它們也應該只用作桌面網站。 多年來,響應式設計一直是網站建設的重要組成部分。 Smashing Magazine 有一些很棒的文章。 - 離線優先
該應用程序必須能夠離線啟動並仍然顯示有用的信息。 - 觸控功能
界面應該是為觸摸而設計的,帶有手勢交互。 用戶交互必須感覺反應靈敏且快速,觸摸和響應之間沒有延遲。 - 應用元數據
該應用程序應該提供元數據來告訴瀏覽器它在安裝時的外觀,以便您在主屏幕上獲得漂亮的高分辨率圖標,並在某些平台上獲得啟動屏幕。 - 推送通知
該應用程序能夠在應用程序未運行時接收通知(如果適用)。
......但應該保持某些類似網絡的屬性
- 進步
該應用程序的安裝能力是一種漸進式增強。 至關重要的是,該應用程序仍可作為普通網站運行,尤其是在尚不支持安裝或服務人員的平台上。 - 開放網絡上的 HTTPS
該應用程序不應鎖定到任何瀏覽器或應用程序商店。 它應該能夠深度鏈接並提供共享當前 URL 的方法。
使您的網站離線
使您的網站離線會帶來一些主要優勢。
首先,當用戶處於不穩定的網絡連接時,它仍然可以工作。
此外,如果應用不依賴網絡,從打開應用到使用應用的時間大大縮短。 這給用戶帶來了很好的體驗。 如果最近使用過瀏覽器,經過精心優化的 Web 應用程序可以比原生應用程序啟動得更快。
有兩種方法可以讓網站離線工作:
- 舊的和失敗的方法
以 AppCache 的形式支持離線啟動您的網站已有多年。 不過,AppCache 有一些嚴重的缺陷,甚至在規範中已被棄用。 它很難使用,如果配置錯誤,可能會永久破壞您的網站。 儘管如此,它仍然是在 iOS 上進行離線操作的唯一方法,至少在 Apple 採取行動支持服務人員之前是這樣。 - 新熱度
同樣有效的是服務工作者,目前在 Chrome、Firefox 和 Opera 中得到支持,並且很快就會在 Edge 中推出。 Apple 的 WebKit 團隊將其標記為“正在考慮中”。
Service Worker 與其他 Web Worker 一樣,它們在單獨的線程中運行,但它們不綁定到任何特定的選項卡。 它們在創建時被分配了一個 URL 範圍,它們可以攔截和重寫此範圍內的任何請求。 如果您的服務工作者位於https://example.com/my-site/sw.js
,它將能夠攔截對/my-site/
或更低級別的任何請求,但無法攔截對根https://example.com/
的請求https://example.com/
。
因為它們不綁定到任何選項卡,所以可以在後台激活它們以處理推送通知或後台同步。 尤其重要的是,它們不可能永久破壞您的網站,因為它們會在檢測到新的 Service Worker 腳本時自動更新。
一個很好的指導原則是,如果您要從頭開始構建新網站,請從服務人員開始。 但是,如果您的網站已經使用 AppCache 離線工作,那麼您可以使用工具 sw-appcache-behavior 從中生成一個 Service Worker,因為我們可能很快就會到達一些瀏覽器只接受 Service Worker 而一些只接受應用緩存。
由於 AppCache 已被棄用,因此我不會在本文中進一步討論它。
設置 Service Worker
(另請參閱“設置 Service Worker”以獲取更詳細的說明。)
因為 Service Worker 是一種特殊類型的共享 Web Worker,所以它在主頁面的單獨線程中運行。 這意味著它由與服務工作者在同一路徑上的所有網頁共享。 例如,位於/my-page/sw.js
的服務工作者將能夠影響/my-page/index.html
和my-page/images/header.jpg
,但不會影響/index.html
。
Service Worker 能夠攔截、重寫或欺騙頁面上的所有網絡請求,包括對data://
URL 的請求!
這種能力使其能夠在沒有數據連接時提供緩存響應以使頁面正常工作。 儘管如此,它仍然足夠靈活,可以允許許多可能的用例。
它只允許在安全上下文(即 HTTPS)中使用,因為它非常強大。 這可以防止第三方使用來自受感染或惡意 Wi-Fi 接入點的注入服務人員永久覆蓋您的網站。
現在設置 HTTPS 可能看起來令人生畏且昂貴,但實際上它從未如此簡單或便宜。 Let's Encrypt 為您提供免費的 SSL 證書和腳本來自動配置您的服務器。 如果您在 GitHub 上託管,GitHub Pages 會自動通過 HTTPS 提供服務。 Tumblr 頁面也可以配置為在 HTTPS 上運行。 CloudFlare 可以代理請求以升級到 HTTPS。
脫機通常涉及為網站的不同部分選擇某些緩存方法,以便更快地提供服務或在沒有 Internet 連接的情況下提供服務。 我將在下面討論各種緩存方法。
我使用 Service Worker Toolbox 來抽像出複雜的緩存邏輯。 該庫可以設置為通過提供四個預配置路由來處理路由,這些路由可以以乾淨的方式進行配置。 它可以被導入到你的 service worker 中。
用例 1:預緩存
在您的網站確定需要它們之前,預緩存會拉下請求。 這可以大大減少首次繪製時間,因為您的網站在開始下載您網站的徽標/images/logo.png
之前不需要解析/site.css
。
toolbox.precache(['/index.html', '/site.css', '/images/logo.png']);
用例 2:離線
在最簡單的情況下,允許用戶在離線時重新訪問您的網站意味著在設備離線時回退到緩存。 在這裡設置超時很重要,因為不穩定的網絡、錯誤配置的路由器或強制門戶可能會讓用戶無限期地等待。
toolbox.router.default = toolbox.networkFirst; toolbox.options.networkTimeoutSeconds = 5;
實際上,我們實際上可以更聰明一點,因為您的大部分資產不會隨著時間而改變。 我們可能只想盡快獲取內容,無論是來自緩存還是網絡。 以下行告訴 Service Worker Toolbox,所有對圖像路徑的請求都應該來自緩存(如果它們在緩存中可用)。
toolbox.router.all('/images/*', toolbox.fastest);
在這種情況下,當用戶進行身份驗證時,重要的是我們不能只返回一個緩存的響應; 我們應該聲明對/auth/
的請求應該是僅限網絡的。
toolbox.router.post('/auth/*', toolbox.networkOnly);
以下是一些離線的良好做法:
- 初始靜態資產應預先緩存。 這會在安裝服務工作者時下載並緩存它們。 這意味著當最終需要它們時,不需要從服務器加載它們。
- 默認情況下,理想情況下,請求應該是從網絡中新獲取的,但會回退到緩存中,以便它們可以離線使用。
- 相對較短的網絡超時意味著請求將能夠在表示它有數據連接但沒有返迴響應的網絡連接上返回緩存數據。
- 不經常更新的資產,例如圖像,應該首先從緩存中分派,然後瀏覽器也會嘗試更新它們。 如果使用
toolbox.cacheOnly
,那麼它也可以保存用戶的數據。
注意:瀏覽器緩存和緩存 API 是不同的動物。 在網絡優先或僅網絡的情況下,緩存 API 已被繞過。 該請求可能仍會命中瀏覽器的緩存,因為請求中的緩存標頭表明它仍然有效。 這可能會導致用戶接收到混合的緩存數據和新數據的問題。 Jake Archibald 有一些很好的建議來避免這個問題。
調試你的 Service Worker
如果您使用的是 Chrome 或 Opera,請轉到chrome://serviceworker-internals
。 這將允許您檢查、暫停和卸載您的服務工作者腳本。
在 Chrome 和 Opera 的最新版本中,您可以通過檢查器中的“應用程序”選項卡獲得詳細的視圖和調試工具。
交互和動畫性能
人們已經開始期望 Web 沒有原生應用程序所具有的流暢動畫界面。 但是,Web 應用程序不能接受相同的標準。 Web 應用程序必須流暢地製作動畫,以免我們的用戶覺得我們正在提供一種降級的二流體驗。 我們有三個目標讓它感覺快:
- 當用戶做某事時,應用程序也必須在 100 毫秒內做某事; 否則,用戶會注意到延遲。 這對點擊、點擊、拖動和滾動都很重要。
- 每幀必須以一致的每秒 60 幀(每幀 16 毫秒)進行渲染。 即使是一些慢幀也會很明顯。
- 它必須在一個運行了三年的廉價手機上運行在一個糟糕的網絡上,而不僅僅是你閃亮的開發機器。
- 它必須快速啟動。 長期以來,我們一直專注於通過讓我們的網站在 1 到 2 秒內可見和可用來保持用戶參與度。 對於 Web 應用程序,啟動時間與以往一樣重要。 如果應用程序的所有內容都被緩存並且瀏覽器仍在設備的內存中,那麼 Web 應用程序可以比原生應用程序更快地啟動。 本機應用程序和網站開發人員犯的一個錯誤是需要網絡內容才能使產品工作。
- Web 應用程序必須很小才能下載和更新:從應用程序商店下載 10 MB 感覺並不多,但是對於很多移動用戶來說,每次下載 10 MB 未緩存的 MB 是非常不可能的。
馬上,最重要的項目就是這個,在文件的head
:
<meta name="viewport" content="width=device-width">
這條線確保在基於 Chromium 或 Firefox 的手機瀏覽器上沒有 300 毫秒的點擊延遲,但它仍然允許用戶通過捏合來放大(非常適合可訪問性)。
根據某些啟發式方法,自從 iOS 8 推出以來,默認情況下點擊速度很快,但如果點擊速度很快,則可能看起來很慢。 如果這對您來說是個問題,我建議使用 FastClick 來消除延遲。
還有動畫性能的問題。 你可能會想要很多漂亮的元素動畫進出,用戶可以拖動的元素,以及其他可愛的交互。
Web 性能可以非常詳細地討論,並且是我非常關心的一個主題,但我不會在這裡詳細介紹。 我將談談我所做的以確保我的交互和動畫清晰流暢。
四處尋找或向您的朋友或家人詢問舊智能手機。 我通常藉用我夥伴的 Nexus 4。
將手機插入計算機,然後轉到chrome://inspect/#devices
。 這將打開一個檢查窗口,您可以使用該窗口檢查手機上運行的網頁。 您可以使用分析和查看時間線來查找性能不佳的來源,然後根據真實的基線設備對其進行優化。
動畫某些 CSS 屬性是抖動動畫的最大原因之一,稱為 jank。 CSS 觸發器是一個很好的資源,用於確定哪些屬性可以安全地進行動畫處理,而不會導致瀏覽器重新繪製或重新佈局整個頁面。
如果編寫高性能動畫對您來說是一項艱鉅的任務,那麼許多庫可以處理這項工作。 我最喜歡的是 GreenSock,它可以很好地處理觸摸交互,例如拖動項目,並且可以做非常花哨的動畫和補間。
推送通知
推送通知是重新與用戶互動的好方法。 通過提示用戶,您可以將您的應用程序帶到他們的腦海中。 他們可以完成未完成的交易或接收有關相關新內容的警報。
確保您的推送通知與用戶當時發生的事件相關。 不要把時間浪費在以後可以做的事情上。 您通知他們的內容應該需要他們採取行動(回复某人或參加活動)。 此外,如果您的 Web 應用程序可見或處於焦點,請不要推送通知。
與之交互時,通知應將用戶帶到離線工作的頁面。 通知可以懸而未決; 當用戶沒有網絡連接時,它們可能會被交互。 如果您的推送通知在嘗試與之交互後拒絕工作,用戶會感到沮喪。
推送通知的最佳體驗讓用戶完全不必打開您的網絡應用程序! “你有一條新消息”是無用的,就像點擊誘餌標題一樣煩人。 顯示消息和發件人。
通知中的操作按鈕可以提供不一定打開瀏覽器的交互提示(“喜歡這篇文章”、“回復是”、“回復不是”、“稍後提醒我”)。 這些以他們的條件為用戶服務,讓他們保持參與並最大限度地減少他們的時間投資。
如果您使用常規或不相關的通知向用戶發送垃圾郵件,他們可能會在瀏覽器中禁用您的應用程序的通知。 在那之後,幾乎不可能再次與他們互動,並且您將無法輕鬆再次提示他們獲得許可!
為避免這種情況,請讓您的應用程序的“禁用通知”按鈕的路徑清晰且簡單。 一旦你解決了任何讓用戶感到沮喪的問題,你就可以嘗試重新參與。
推送通知 API 需要一個服務工作者。 因為在沒有打開瀏覽器選項卡時可以接收推送通知,所以服務工作者將在後台線程中處理通知請求。 它可以執行異步操作,例如在向用戶顯示通知之前向您的 API 發出 fetch 請求。
要創建推送通知,請向瀏覽器製造商提供的端點發出請求。 對於基於 Chromium 的瀏覽器(Opera、Samsung 和 Chrome),這將是 Firebase Cloud Messaging。 這些瀏覽器的行為也有些不合規格。
可以通過請求推送通知權限來找到這方面的詳細信息:
serviceWorkerRegistration .pushManager .subscribe({ // Required parameter as receiving updates // but not displaying a message is not supported everywhere. userVisibleOnly: true }) .then(function(subscription) { return sendSubscriptionToServer(subscription); })
訂閱是一個如下所示的對象:
{ "endpoint": "https://example.com/some/uuid" }
在上面的示例中, uuid
唯一標識當前正在使用的瀏覽器。
注意:基於 Chromium 的瀏覽器的行為略有不同。 您需要一個 Firebase 應用 ID,該 ID 需要在您的 Web 應用的清單文件中輸入(例如, "gcm_sender_id": "90157766285"
)。
此外,端點將無法按照給定的格式工作。 您的服務器需要稍微修改它才能使其正常工作。 它需要是一個POST
請求,您的 API 密鑰在head
中, uuid
在body
中。
發送推送通知時,可以在推送通知本身的正文中發送數據。 這很複雜,涉及對 API 請求中的內容進行加密。 Node.js 的 web-push 包可以處理這個問題,但我不喜歡它。
一旦收到通知就可以執行異步請求,所以我更喜歡向客戶端發送一個稱為“tickle”的最小通知,然後服務工作者將向我的 API 發出一個獲取請求以提取任何最近更新。
注意:服務工作者可以隨時被瀏覽器關閉。 push 事件中的event.waitUntil
函數告訴 service worker 在事件完成之前不要關閉。
self.addEventListener('push', function(event) { event.waitUntil( // Makes API request, returns Promise getMessageDetails() .then(function (details) { self.registration.showNotification( details.title, { body: details.message, icon: '/my-app-logo-192x192.png' }) }) ); });
您也可以在通知事件上收聽單擊或按下交互。 使用這些來決定如何回應。 您可以打開新的瀏覽器選項卡、聚焦現有選項卡或發出 API 請求。 您還可以選擇是關閉通知還是保持打開狀態。 將此功能與通知上的操作一起使用,以在通知本身中構建出色的功能。 這將帶來很好的體驗,因為用戶不需要每次都打開您的應用程序。
不要忽視網絡的優勢
最後也是最重要的一點是,在我們急於獲得類似應用程序的體驗時,我們不應該忘記在一個非常重要的方面保持類似網絡:URL。
已安裝的網絡應用程序通常會隱藏瀏覽器外殼。 沒有地址欄供用戶分享當前網址,用戶無法保存當前頁面以備後用。
URL 具有獨特的網絡優勢:您可以通過單擊而不是描述如何導航來讓人們使用您的應用程序。 儘管如此,很容易忘記將其暴露給用戶。 您可以編寫世界上最好的應用程序,但如果沒有人可以分享它,您將對自己造成重大傷害。
歸結為:提供通過共享按鈕或公開 URL 的按鈕來共享您的應用程序的方法。
不支持漸進式 Web 應用程序的瀏覽器怎麼辦?
查看 ServiceWorker 準備好了嗎? 跨瀏覽器對服務工作者的支持的當前狀態。
你可能已經註意到,我提到了 Chrome、Firefox 和 Edge,但沒有提到 Safari。 Apple 向世界推出了 Web 應用程序,並對漸進式 Web 應用程序表現出了興趣,但它仍然不支持服務工作者或 Web 應用程序清單。 你能做什麼?
可以使用 AppCache 為 Safari 創建一個離線網站,但這樣做既困難又充滿奇怪的邊緣情況,這些情況可能會破壞頁面或在首次加載後使其永久過期。
相反,構建出色的 Web 應用程序體驗。 您的工作不會被浪費,因為在 Safari 中體驗仍然很棒,這是一個非常好的瀏覽器。 當服務人員確實來到 Safari 時,您將準備好利用他們。
最後,我們可以期待 Web 應用程序世界中許多令人興奮的發展,隨著對它們背後的技術的支持越來越多,以及 Web 平台的新功能,例如用於與硬件交互的 Web 藍牙 API、用於虛擬的 WebVR現實,以及用於高速遊戲的 WebGL 2。 現在是探索網絡應用的可能性並參與塑造網絡未來的大好時機。
鏈接
漸進式 Web 應用程序的其他寫作
- “又一個關於漸進式 Web 應用的狀態和未來的博客,”Ada Rose Edwards
文章中提到的鏈接
- “App Store 的形狀”,查爾斯·佩里
- Service Worker Helpers, Google, GitHub
- Service Worker 工具箱、谷歌、GitHub
- “300 毫秒的點擊延遲和 iOS 8,”TJ VanToll
- “緩存最佳實踐和最大年齡陷阱”,Jake Archibald