半熟前端

軟體工程師 / 台灣人 / 在前端的路上一邊探索其他領域的可能性

前端

Hotwire 與 Turbolinks

Hotwire 與 Turbolinks

前言

DHH (Ruby on Rails 的作者)發了一則推特,在講他的新作 Hotwire。DHH 是個 SPA 黑粉(從推文上可以略知一二),因此他極力避免在開發上加入太多 JavaScript。這則推文在推特上引起熱烈討論,在這邊稍微做個整理。

關於 Hotwire 的介紹在這邊直接引用官方上面的說明:

Hotwire is an alternative approach to building modern web applications without using much JavaScript by sending HTML instead of JSON over the wire

這個說明有兩個重點:

  • 不需要使用 JavaScript
  • 直接傳送 HTML 而非 JSON

這個概念其實不是最近才有,早在好幾年前 Ruby on Rails 就是採用類似的手法,叫做 Turbolink

Turbolinks 是一個 JavaScript 套件,通常會搭配 Ruby on Rails 一起使用(單獨當作函式庫使用也可以),主要是透過 fetch HTML 直接抽換的方式來避免直接換頁要重新發送請求、CSS 的成本。其實說「不需要使用 JavaScript」不完全正確,JavaScript 還是在,只是在函式庫那邊已經幫你處理好,所以開發上可以不用寫 JavaScript 而已。

舉例來說,當頁面上有這樣一個 tag:

<a href="/articles/1" data-remote="true">link</a>

如果 Ruby on Rails 有啟用 Turbolinks 的功能,那麼當使用者點擊連結時,實際上並不是重新發送請求,而是 turbolinks 會做類似這樣的事情:

fetch('/index.html').then(res => res.html())
	.then((html) => $page.html(html))

這樣一來當使用者點擊按鈕時,不會重新渲染 HTML,而是先 fetch 那一頁的 HTML 檔案(透過 ajax),然後再透過 JavaScript 直接渲染出來。Ruby on Rails 本身跟 turbolinks 有高度整合,所以有時候幾乎感覺不到 turbolinks 的存在,只會覺得「哇嗚怎麼換頁好像變快了」。

當 HTML 越大效果應該會越來越不明顯,不過 HTML 本身不大的話是可以達到比較好的使用者體驗的。

為什麼這種方式有用?

  • 不需要換頁重新請求 CSS 與 JavaScript,使用者體驗較佳
  • head 的部分 turbolinks 會幫你做處理
  • 幾乎不需要撰寫額外的 JavaScript
  • 後端工程師可以用最小的力氣達到比較好的體驗

需要注意的地方

  • 像是 load 之類的 event,因為 turbolinks 的機制並沒有重新載入整個頁面,所以只有第一次載入會觸發。要記得切換成 turbolinks:load 之類的方式來監聽事件
  • 當 JavaScript 互動越來越多,事件綁定容易彼此衝突。
  • 狀態在換頁不會被消除,所以 JavaScript 沒寫好容易造成記憶體洩漏

當 JavaScript 的互動越來越多的時候,搭配 turbolinks 有時會出現奇怪的現象,像是重複執行造成的錯誤等等。

一些想法

其實身為開發者多少都有寫過 SPA 的經驗,因此大家都知道要寫出一個堪用、好用的 SPA 並不容易,狀態管理沒寫好狂吃記憶體、狀態不同步、錯誤處理沒寫好、動不動就載入一大坨 JavaScript bundle 等等,反而乾脆一些直接用純 SSR 渲染的方式還比較好一些,然後透過 turbolinks 這種方式來增強體驗或許是個不錯的方法。

後記

有人認為 JSON 會比 HTML 小,所以傳輸上會比較有效率,但是 gzipped 過後其實兩者是差不多的,而且 HTML 有時候甚至會比較小。所以直接渲染 HTML 感覺不是那麼罪不可赦的事。

只是目前 Turbolink 整合最好的恐怕也只有 Ruby on Rails,Hotwire 還相對比較新可能部分開發者還在觀望中。