avalon2為了提高性能,采用全新的架構,四層架構,其中一層為虛擬DOM。
虛擬DOM的一個好處是能大大提高性能,另一個好處是能過錯整描述我們的頁面結構。因此在非瀏覽器環境下,虛擬DOM也能正常運行。並且avalon2自一開始,就努力隔離DOM API。基於這兩點,avalon2可以原封不動地運行於nodejs中,進行定義VM,渲染視圖等操作。
-
客戶端上,虛擬DOM通過
vm.$render
方法渲染到頁面中 -
服務端上,虛擬DOM使用
serveRender
生成HTML字符串
與react的后端渲染相比,它的使用是非常簡單的。React的渲染單位是組件,組件有生命周期,我們在添加一些處理時,都是放在生命周期鈎子中(getDefaultProps,getInitialState,componentWillMount,componentDidMount,componentWillUpdate。。。。),而在nodejs,生命周期只能走到componentDidMount之前。用戶想后端渲染,需要有針對性地寫代碼。而avalon2則不需要懂這些,只要保證所有DOM操作在回調中就行了。
react的后端渲染有兩個方法,ReactDOMServer.renderToString 和 ReactDOMServer.renderToStaticMarkup。renderToString帶着uuid,為了前端只進行綁定事件,不再生成DOM,但缺點是讓頁面體積變大很多。而renderToStaticMarkup只能輸入不帶交互的靜態頁面。
而avalon只有一個方法,它輸出的頁面沒有ms-xxx,:xxx這些綁定屬性,因此相當於輸出靜態頁面。為了實現綁定屬性功能,如果將模板函數或已經生成好的事件傳過去,想必體積太大。因此avalon將原始頁面的很少一部分壓縮傳過去。即便你沒有用html-minify這些工具,avalon也會做去空白節點處理!
因此從生成頁面速度,與傳輸體積上,avalon的后端渲染都比react優秀不少。
與傳統后端渲染相比,即JSP,PHP方案,主要好處是,模板的控制台掌握在我們前端手中。不要痛苦成為套頁面的工具。avalon對切圖人員交給我們的頁面,所做修改是很少的,就是加一些綁定屬性。
與近年流行前端模板渲染方案相比,即后端出數據,前端在script標簽,textarea標簽里寫模板,主要好處是SEO!前端模板是無法搞定SEO,並且還有"首屏亂碼"問題,這些在ng, avalon1, vue1 也有這問題,需要ng-cloak 等東西做遮丑布! 有了后端渲染就沒有這問題了。
好了,我們看如何做。為簡單起見,本文使用koa2做后端框架。koa2是使用es7的async function處理異步,從此告別異步地獄與那些深澀難懂的generators。
但就算最新的nodejs6也不支持async function,不過沒關系,我們可以使用babel。至於如何用,后面直接給出一個例子。現在我們看一下一些通用的步驟,熟悉了它,你可以將avalon用於koa1, express及其他nodejs框架。
-
引入最新版 avalon 這里用avalon.modern體積少些
-
引入avalon倉庫下的serve下的文件serveRender.js
-
引入你定義VM的文件 (所有DOM操作要在回調里進行,不要出現 window, document, 方便能在nodejs環境中運行) 對你的VM使用webpack進行打包 (目的是處理module.exports, require)
var vm = avalon.define({
$id: "test",
aaa: '222'
})
module.exports = vm //這里必須使用module.exports,而不是es6 module
-
引入你該頁面的模板(就是一個普通的HTML文件片段,里面需要用ms-controller,指向你剛才的VM.$id)
-
將VM與模板放進serveRender方法,得到一個對象,里面包含渲染好的HTML(A) 及 一個包括所有模板的對象(B)
-
創建一個script標簽, 里面定義一個avalon.serverTemplates對象, 將B對象賦給它
-
將上面的標簽與A頁面, 賦給ctx.body發往前端(或其他可以放送到前端的方法里面去)
//1. 引入avalon
var vm = require('./src/avalon')
//2. 引入avalon的后端渲染器
var serveRender = require('./dist/serverRender')
//3. 當前頁面VM
var vm = require('./src/vm')
//4. 當前頁面模板
var test = fs.readFileSync('./src/aaa.html', 'utf-8');
//5.
var obj = serveRender(vm, test)
//6.
var files = JSON.stringify(obj.templates)
var script = '<script src="./avalon.js"><\/script>' +
'<script> avalon.serverTemplates= ' + files + '<\/script>' +
'<script src="./test.js"><\/script>'
//7. render
app.use(async function(ctx){
await (ctx.body = script + obj.html)
})
這些我已經做成一個例子,放到GITHUB中,大家可以下回來看。
這是后端返回前端的源碼,大家可以做得更漂亮些,把head, body, html等標簽補上。不過就算你不寫,瀏覽器也會幫你補上的。
這是效果圖!
有了后端渲染,我們就可以加快首屏的渲染速度與SEO。 並且我們可以實現前后同構, 前后端共用一套模型(VM),一套驗證代碼,一套模板!!!做ABTest,埋點等也測試了!后端的一些部分也掌握在我們前端手中,我們的價值就越來越大,工資自然也上去了!
有關后端渲染的話題,大家也可以看一下react的方案及早期百度,騰訊基於它們的私有框架的實踐。