雖然Angular是一種構建Web應用的強大方式,但是長期以來,開發人員都知道它在SEO和可訪問性方面的限制。當然,Google的爬蟲能夠執行JavaScript,但是它并不是唯一的爬蟲方案。例如,在將一個鏈接提交給Slack之后,它的爬蟲會抓取一個預覽,但是并不會執行JavaScript,所以原始的Angular HTML模板將會顯示在預覽之中。為了消除這種現象所產生的問題,Jeff Whelpley和Patrick Stapleton開發了Angular Universal,它允許在服務端進行渲染。
Universal JavaScript(有時會被誤稱為“isomorphic”)并不是Angular特有的技術。Angular Universal的工作原理是在服務端進行應用的初始化渲染,并將其發送給瀏覽器,用戶就能馬上看到了,然后才發送客戶端的JavaScript。這與Angular應用的典型順序是有所區別的,在典型的順序中會首先發送客戶端JavaScript,然后初始化UI才會在客戶端渲染。
Welpley和Stapleton開發Angular Unversal已經超過一年了,在這個過程中發現了六個經常遇到的模式。在2016 ng-conf的分享中,它們主要關注了其中的三項:
事件脫節(Gap Event) 異步(Async) 依賴(Dependencies)事件脫節是在服務端渲染所造成的副作用,在這種方式下,渲染會在JavaScript客戶端腳本發送到瀏覽器之前執行。根據JavaScript發送和執行的速度不同,用戶在與UI進行交互的時候,可能代碼還沒有為這些交互做好準備。這種脫節可能會導致用戶交互的丟失。
針對該問題的解決方案就是記錄用戶的事件,并在客戶端JS加載完成之后進行重放。如下的樣例展現這種代碼會是什么樣子的:
var myEvents = ;var myInputValue;// 記錄客戶端視圖myInput的所有keyup事件function recordEvents() { var $myInput = document.querySelector('.myInput') $myInput.addEventListener('keyup', function (event) { myEvents.push(event); myInputValue = event.target.value; });}// 在服務器視圖myInput上回放所有的keyup事件function replayEvents() { var $myInput = document.querySelector('.myInput'); myEvents.forEach(function (event) { $myInput.dispatchEvent(event); }); $myInput.value = myInputValue; $myInput.focus();}// 在window加載完成之后,馬上就開始記錄window.addEventListener('load', recordEvents);Angular Universal使用一種名為preboot過程來處理這項任務,而不是要求開發人員手動地做這些事情,可以通過如下的標記啟用該功能:
preboot: trueJavaScript在本質上是異步的,在服務端渲染Angular的時候,這就會產生問題。通常的解決方案是使用鏈(chaining)或回調,但要求開發人員重寫他們的代碼來解決這個問題顯然不是好的可選方案。“我們不能這樣做,而是必須要找到一種方式來處理這些不同的異步事件,并調整它們何時將響應發送回來”,Whelpley這樣說到。
Angular Universal使用另外一個標記來解決這個問題,只需一行就可以了:
async: true將這個標記打開之后,將會使用Angular新的Zones特性,“跟蹤所有的異步調用,并且能夠知道它們何時完成。”
在服務端渲染Angular代碼的第三個主要的問題在于使用平臺特定的依賴。例如,localStorage是瀏覽器的特性,在服務器端根本不存在。Whelpley和Stapleton指出,可以使用依賴注入(Dependency Injection,DI)作為解決方案。他們建議根據代碼所執行的上下文,借助DI來替換實現,而不是使用平臺具體的特性。
對于測試過他們功能的開發人員來說,這應該不足為奇。Whelpley指出,Angular所運行的測試和其他平臺已經證明了這項技術在Angular 2的代碼中將會非常普遍。“平臺相關的依賴基本上已經被我們消除掉了。這個模式是我今天所討論的最強大的模式”,Whelpley說道。
他們ng-conf分享的完整視頻已經可以觀看了。
查看英文原文:3 Development Patterns of Angular Universal