郭达峰 Strikingly 联合创始人兼CTO
Strikingly / 上线了
十分钟实现你的互联网+
Server-side Rendering
服务端渲染/同构直出
Browser: React Editor
Node.js: SSR HTML
同构:一份JS代码,前端和后端共享
1. SEO and faster initial load
2. no code duplication
网站数目庞大,每个网站都不同
每次部署都需要短时间内刷新cache
几分钟内爬虫扫描成千上万网站
相比于传统模板渲染,SSR慢很多
import React from 'react'
// <DivTree depth={5} breadth={5} /> => 5^5 = 3125 React components
class DivTree extends React.Component {
render() {
const { depth, breadth } = this.props
if (depth <= 0) {
return <div>{'content'}</div>
}
let children = []
for (let i = 0; i < breadth; i++) {
children.push(<DivTree key={i} depth={depth - 1} breadth={breadth} />)
}
return <div>{children}</div>
}
}
mean: ~400 ms using out of box React 15
use NODE_ENV=production
Mean: 400ms -> 105ms
Babel-transform: transform-react-constant-elements
const Hr = () => {
return <hr className="hr" />;
};
const _ref = <hr className="hr" />;
const Hr = () => {
return _ref;
};
Static component only need to call React.createElment once
Babel-transform: transform-react-inline-elements
<Baz foo="bar" key="1"></Baz>;
babelHelpers.jsx(Baz, {
foo: "bar"
}, "1");
/**
* Instead of
*
* React.createElement(Baz, {
* foo: "bar",
* key: "1",
* });
*/
Tricks #2 and #3 get us to 70ms
NODE_ENV=production
Babel plugins
We cut from 400ms down to 70ms
(state, props) => string
this is essentially what ReactSSR does
(state, props) => string
memoize it!
Typically use LRU cache
https://github.com/electrode-io/electrode-react-ssr-caching
每个网站内容和组件都大有不同
User
Web Server
request
response
SSR
高可用集群是指以减少服务中断时间为目的的服务器集群技术
User
Web Server
request
response
SSR
pm2 and autoscaling
User
Web Server
request
response
SSR
Server
https://github.com/airbnb/hypernova
User
Web Server
request
response
SSR
Server
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)
const Renderer = require('hypernova-client')
const renderer = new Renderer({
url: 'http://localhost:3030/batch',
})
const jobs = {
MyComponent: { name: req.query.name || 'Stranger' },
Component2: { text: 'Hello World' },
}
renderer.render(jobs).then(html => res.send(html))
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,
})
<div data-hypernova-key="MyComponent.js" data-hypernova-id="684d437b-dda0">
<div data-reactroot="" data-reactid="1" data-react-checksum="255991580">
<p data-reactid="2">Hello, FCC Chengdu</p>
</div>
</div>
<script type="application/json" data-hypernova-key="MyComponent.js" data-hypernova-id="684d437b-dda0">
<!--{ name: "FCC Chengdu" }-->
</script>
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)
Component
SSR Succeed HTML
<div data-hypernova-key="MyComponent.js" data-hypernova-id="684d437b-dda0">
<!-- SSR failed -->
</div>
<script type="application/json" data-hypernova-key="MyComponent.js" data-hypernova-id="684d437b-dda0">
<!--{ name: "FCC Chengdu" }-->
</script>
SSR Failure HTML
Cluster of small servers with autoscaling policy
Event triggered serverless computing service
AWS Lambda
Alicloud Function Compute
Event triggered serverless computing service
Serverless
Cluster
with Autoscaling
jobs@strikingly.com