写这篇文章, Vue 2 还在 Beta 呢...vue
官方文档写得很清楚node
彷佛 Vue 1 有看到过经过 jsdom 作后端渲染的例子, 性能不佳.
Vue 2 开始将 Virtual DOM 做为底层实现, 因而模块分离开始支持 SSR.git
文档 https://github.com/vuejs/vue/...github
官方例子 https://github.com/vuejs/vue-...vue-router
官方例子(过期) https://github.com/yyx990803/...后端
4 步走战略~缓存
安装 hackernews 的例子, 完整的 app 渲染的例子包括:app
用 Webpack 的 node
模式把整个应用单独打一个包
Node 环境经过 API 将这个包加载到 vm
环境当中
应用在 vm
内部启动 HTTP 请求抓取当前路由依赖的数据
生成网页模板, 将 HTML 和初始数据嵌在中间
若是网页依赖的数据少或者不依赖, 能够简化一点,
好比中间抓取 HTTP 的步骤去掉, 能够简化很多,
也许还能够去掉 vm
那步, 直接经过引用文件来生成 HTML.
两套 API 哦... 好像只用带 bundle 那套...
https://github.com/vuejs/vue/...
createRenderer([rendererOptions])
renderer.renderToString(vm, cb)
renderer.renderToStream(vm)
createBundleRenderer(code, [rendererOptions])
bundleRenderer.renderToString([context], cb)
bundleRenderer.renderToStream([context])
后面三个 API 都带上了 bundle
, 此外看上去和前面的同样,bundle
是经过 Node.js 的 vm
模块运行的, 每次的都从新启动一遍代码,
做者解释这样能清空整个 app 的状态,
我推测这是由于用了 Vuex 以后, 数据会被缓存在内部没法清理,
若是是单纯经过 props 传递数据, 应该是能够用前一套 API.
有了 Virtual DOM 就好办了
VNode 定义 https://github.com/vuejs/vue/...
HTML 渲染的代码, 经过 write
同时支持到了 Stream 输出:
https://github.com/vuejs/vue/...
https://github.com/vuejs/vue/...
若是用 bundle 模式, 注意每次都会运行 vm.runInNewContext
新建环境.
https://github.com/vuejs/vue/...
https://github.com/vuejs/vue/...
最后返回用户的 HTML 实际上是拼接出来的,
注意首屏的动态数据, 也经过 window.__INITIAL_STATE__
发送到浏览器,
https://github.com/vuejs/vue-...
速度快是由于缓存呢吧...
文档 https://github.com/vuejs/vue/...
大体就是若是组件能够根据一个 key 来肯定, 就能够进行缓存,
静态的组件固然是有固定的 key, 动态的组件根据 id 等数据生成 key,
serverCacheKey: props => props.item.id + '::' + props.item.last_updated
若是组件能够找到缓存, 就直接返回缓存内容:
https://github.com/vuejs/vue/...
这也就意味着顶层的组件总之就是不能缓存的, 性能开销免不了.
hackernews 的例子本地用 ab
压了一下, Mac Pro 到 130+qps 了,
Concurrency Level: 100 Time taken for tests: 3.013 seconds Complete requests: 400 Failed requests: 0 Total transferred: 11545200 bytes HTML transferred: 11506000 bytes Requests per second: 132.77 [#/sec] (mean) Time per request: 753.205 [ms] (mean) Time per request: 7.532 [ms] (mean, across all concurrent requests) Transfer rate: 3742.21 [Kbytes/sec] received
可是这个 Demo 是用了缓存的, 破坏掉缓存性能落差很大,
我本身作的 Demo, 实际上加上缓存性能还不到这个一半...
看来跟应用的类型是有关的, 特别是节点偏多的应用影响更大.
想象一下后端有个浏览器...
对于依赖数据, 目前的方案是在组件定义上提供 preFetch
函数,
服务端渲染时会主动查找挂载的部分, 调用进行数据抓取:
https://github.com/vuejs/vue-...
https://github.com/vuejs/vue-...
官方的例子当中 App 是带了 Vuex 跟 vue-router 的,
因此 preFetch 方案整个集成在这些库当中.
从实验看, 内部嵌套的 preFetch
是不会被调用的, 只能从路由开始,
同时中间要用到 Promise.all
合并请求, 脑补一下.
好吧我以为这是一个至关简单粗暴的获取数据的办法,
但其实也很难解耦, 否则就要从路由直接推算数据才行,
主要以为仍是不够清晰, 限制挺多, 实际操做能犯错的地方很多.
反正比不上模板引擎
编译后大体还能看到 Virtual DOM 的影子, 会有一些性能开销,
不过话说回来 Virtual DOM 原本就很慢, 能优化一点已经不容易了...
module.exports={render:function(){with(this) { return _h('li', { staticClass: "news-item" }, [_h('span', { staticClass: "score" }, [_s(item.score)]), " ", _h('span', { staticClass: "title" }, [(item.url) ? [_h('a', { attrs: { "href": item.url, "target": "_blank" } }, [_s(item.title)]), " ", _h('span', { staticClass: "host" }, ["(" + _s(_f("host")(item.url)) + ")"])] : [_h('router-link', { attrs: { "to": '/item/' + item.id }
另外 vm.runInNewContext
有潜在的性能问题,
http://stackoverflow.com/q/98...
不清楚用在生产环境是怎样, 我我的对此没有多少经验..
愈来愈像 React...
Vue 2 算是把这么多内容整合在一块儿至关不容易,
不过服务端渲染 React 那么久了, 仍是没普及开, 性能是大问题,
相比较而言, Vue 2 增长了 cache 机制, 这能够提升性能,
可是依赖数据时会带来启动 vm
开销, 要是代码量不小在么办?
具体效果仍是要等正式发布后, 等有权威的评测...
此外服务端抓取数据的策略须要挖一挖, 找找更漂亮的策略,我我的但愿能更好地解耦, 梳理出更加清晰的依赖,那样也能够适应更多的场景, 灵活地使用, 而不是限定死了这样用.固然也是由于服务端渲染, 这个原本存在的问题显得更明确了.