一個用於伺服器端渲染 JavaScript 視圖的服務
首先,與僅客戶端渲染相比,伺服器端渲染可以提供更好的使用者體驗。使用者可以更快地取得內容,當 JavaScript 失敗或被禁用時,網頁更易於存取,並且搜尋引擎更容易為其建立索引。
其次,它提供了更好的開發人員體驗。在伺服器端使用你偏好的樣板庫,以及在 JavaScript 中重複撰寫相同的標記可能會很繁瑣且難以維護。Hypernova 讓你可以在單一位置撰寫所有視圖程式碼,而無需犧牲使用者體驗。
hypernova-ruby
或 hypernova-node
之類的東西。它是客戶端,為你的應用程式提供查詢 Hypernova 的超能力,並了解在發生故障時如何回退到客戶端渲染。首先,你需要安裝幾個套件:伺服器、瀏覽器元件和客戶端。為了開發目的,建議將其安裝在你希望伺服器端渲染的程式碼旁邊或在同一個應用程式中。
從這裡開始,我們將假設你使用 hypernova-ruby
和具有 hypernova-react
的 React
。
npm install hypernova --save
此套件包含伺服器和客戶端。
接下來,讓我們設定開發伺服器。為了簡單起見,我們可以將設定放在你的根資料夾中,它可以命名為類似 hypernova.js
的名稱。
var hypernova = require('hypernova/server');
hypernova({
devMode: true,
getComponent(name) {
if (name === 'MyComponent.js') {
return require('./app/assets/javascripts/MyComponent.js');
}
return null;
},
port: 3030,
});
Hypernova 僅需要 getComponent
函數。所有其他設定選項都是可選的。有關 getComponent
的注意事項可以在下面找到。
我們可以透過使用 node 啟動它來執行此伺服器。
node hypernova.js
如果一切順利,你會看到一條訊息顯示「已連線」。如果出現問題,堆疊追蹤應該會出現在 stderr
中。
如果你的伺服器程式碼是用 Ruby 以外的語言撰寫的,那麼你可以為 Hypernova 建立自己的客戶端。存在一個 規格,其中詳細說明了客戶端應如何運作,以及在發生故障時如何回退。
bundle install hypernova
現在,讓我們在 Rails 端新增對 Hypernova 的支援。首先,我們需要建立一個初始化程式。
config/initializers/hypernova_initializer.rb
Hypernova.configure do |config|
config.host = "localhost"
config.port = 3030 # The port where the node service is listening
end
在你的控制器中,你需要一個 :around_filter
,以便你可以選擇加入 Hypernova 的視圖部分渲染。
class SampleController < ApplicationController
around_filter :hypernova_render_support
end
然後在你的視圖中,我們使用 render_react_component
。
<%= render_react_component('MyComponent.js', :name => 'Hypernova The Renderer') %>
最後,讓我們設定 MyComponent.js
以進行伺服器端渲染。我們將使用 React 進行渲染。
const React = require('react');
const renderReact = require('hypernova-react').renderReact;
function MyComponent(props) {
return <div>Hello, {props.name}!</div>;
}
module.exports = renderReact('MyComponent.js', MyComponent);
造訪該頁面,你會看到你的 React 元件已進行伺服器端渲染。如果你想確認,可以查看頁面的來源並尋找 data-hypernova-key
。如果你看到一個充滿 HTML 的 div
,則表示你的元件已進行伺服器端渲染;如果 div
是空的,則表示出現了問題,並且你的元件已作為回退策略進行客戶端渲染。
如果 div
是空的,你可以檢查執行 node 服務的 stderr
。
開發人員外掛程式,適用於 hypernova-ruby
,可用於偵錯 Hypernova 的問題,以及它為何回退到客戶端渲染。每當元件無法在伺服器端渲染時,它會在頁面上顯示警告以及堆疊追蹤。
你可以在 examples/simple/config/environments/development.rb
中安裝開發人員外掛程式
require 'hypernova'
require 'hypernova/plugins/development_mode_plugin'
Hypernova.add_plugin!(DevelopmentModePlugin.new)
你也可以檢查伺服器的輸出。伺服器會輸出到 stdout
和 stderr
,因此如果出現錯誤,請檢查你執行 node hypernova.js
的程序,你會看到錯誤。
建議的方法是執行兩個獨立的伺服器,一個包含你的伺服器程式碼,另一個包含 Hypernova 服務。你也需要將 JavaScript 程式碼部署到包含 Hypernova 服務的伺服器。
根據你設定 getComponent
的方式,你可能需要在每次部署時重新啟動你的 Hypernova 服務。如果 getComponent
快取任何程式碼,則重新啟動至關重要,以便 Hypernova 接收新的變更。建議使用快取,因為它可以協助加速服務。
傳送 HTTP 請求不是會很慢嗎?
開銷或延遲並不大,尤其是當你將伺服器保持在彼此接近的位置時。它與編譯許多 ERB 範本一樣快,並能讓你統一視圖程式碼。
為什麼不使用記憶體中的 JS VM?
這是一個有效的選項。如果你正在尋找隔離體驗,其中 JS 服務保持獨立,那麼 Hypernova 非常適合你。此方法也更適合於尚未提供 JS VM 的環境。
如果伺服器崩潰了怎麼辦?
如果 Hypernova 嘗試伺服器端渲染你的元件時發生任何不好的事情,它會預設為失敗模式,你的頁面會改為在客戶端渲染。雖然這是一個舒適的安全網,但目標是伺服器端渲染每個請求。
這些是伺服器端渲染 JavaScript 程式碼的缺點,並非 Hypernova 特有。
你會希望在 componentDidMount
中執行任何與 DOM 相關的操作。componentDidMount
在瀏覽器上執行,但不在伺服器上執行,這表示可以安全地將 DOM 邏輯放在那裡。將邏輯放在元件外部、建構子中或 componentWillMount
中會導致程式碼失敗,因為 DOM 不存在於伺服器上。
建議你在 VM 沙箱中執行程式碼,以便請求取得全新的 JavaScript 環境。如果你決定不使用 VM,則應注意單例模式和全域變數有在請求之間洩漏記憶體和/或洩漏資料的風險。如果你使用 createGetComponent
,你將預設取得 VM。