用于服务器端渲染 JavaScript 视图的服务
首先,与仅客户端渲染相比,服务器端渲染提供更好的用户体验。用户可以更快地获取内容,在 JS 失败或被禁用时网页更易访问,搜索引擎也更容易对其进行索引。
其次,它提供了更好的开发者体验。在服务器上使用你喜欢的模板库和在 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。