-
Notifications
You must be signed in to change notification settings - Fork 384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vue SSR Demo #112
Labels
Comments
很收益 |
理解很透彻! |
thx |
f
At 2018-02-28 17:43:10, "不一样的doger" <[email protected]> wrote:
thx
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
不错的Vue SSR入门级指南 |
好在 2018年2月28日,下午5:50,胖木 <[email protected]> 写道:f
At 2018-02-28 17:43:10, "不一样的doger" <[email protected]> wrote:
thx
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.
—You are receiving this because you are subscribed to this thread.Reply to this email directly, view it on GitHub, or mute the thread.
|
@youngwind 想请教一下作者,我在你的例子上加入了vue-router,使用lazy router的时候,webpack会进行代码分割。但是实际上生成的文件,node跑server.js的时候,会报组件js文件未找到,请问这是什么原因? |
我想咨询下,首屏的概念是怎么定义的,是人眼看到的部分还是首次请求的完整页面? |
首屏的定义这两种都有可能,得结合上下文判断。本文的首屏指的是“首次请求的完整页面” @cuiyongjian |
mark |
棒棒哒 |
第一步不是前端渲染吗?怎么就有client.conf和server.conf了? |
thx!!! |
感谢分享,收益于你的这篇博文,我加强了下,高级版 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
前言
最近接手一个老项目,典型的 Vue 组件化前端渲染,后续业务优化可能会朝 SSR 方向走,因此,就先做些技术储备。如果对 Vue SSR 完全不了解,请先阅读官方文档。
思路
Vue 提供了一个官方 Demo,该 Demo 优点是功能大而全,缺点是对新手不友好,容易让人看蒙。因此,今天我们来写一个更加容易上手的 Demo。总共分三步走,循序渐进。
第一步:前端渲染 Demo
这部分比较简单,就是一个页面中包含两个组件:Foo 和 Bar。
最终渲染结果如下图所示,源码请参考这里。

第二步:后端渲染(不包含 Ajax 数据)
第一步的 Demo 虽不包含任何 Ajax 数据,但即便如此,要把它改造成后端渲染,亦非易事。该从哪几个方面着手呢?
1. 拆分 JS 入口
在前端渲染的时候,只需要一个入口
app.js
。现在要做后端渲染,就得有两个 JS 文件:entry-client.js
和entry-server.js
分别作为浏览器和服务器的入口。先看
entry-client.js
,它跟第一步的app.js
有什么区别吗? → 没有区别,只是换了个名字而已,内容都一样。再看
entry-server.js
,它只需返回 App.vue 的实例。entry-server.js
与entry-client.js
这两个入口主要区别如下:entry-client.js
在浏览器端执行,所以需要指定 el 并且显式调用 $mount 方法,以启动浏览器的渲染。entry-server.js
在服务端被调用,因此需要导出为一个函数。2. 拆分 Webpack 打包配置
在第一步中,由于只有
app.js
一个入口,只需要一份 Webpack 配置文件。现在有两个入口了,自然就需要两份 Webpack 配置文件:webpack.server.conf.js
和webpack.client.conf.js
,它们的公共部分抽象成webpack.base.conf.js
。关于
webpack.server.conf.js
,有两个注意点:libraryTarget: 'commonjs2'
→ 因为服务器是 Node,所以必须按照 commonjs 规范打包才能被服务器调用。target: 'node'
→ 指定 Node 环境,避免非 Node 环境特定 API 报错,如 document 等。3. 编写服务端渲染主体逻辑
Vue SSR 依赖于包 vue-server-render,它的调用支持两种入口格式:createRenderer 和 createBundleRenderer,前者以 Vue 组件为入口,后者以打包后的 JS 文件为入口,本文采取后者。
这一步的最终渲染效果如下图所示,从图中我们可以看到,组件已经被后端成功渲染了。源码请参考这里。

第三步:后端渲染(预获取 Ajax 数据)
这是关键的一步,也是最难的一步。
假如第二步的组件各自都需要请求 Ajax 数据的话,该怎么处理呢?官方文档给我们指出了思路,我简要概括如下:
下面谈几个重点。
我们知道,在常规的 Vue 前端渲染中,组件请求 Ajax 一般是这么写的:“在 mounted 中调用
this.fetchData
,然后在回调里面把返回数据写到实例的 data 中,这就 ok 了。”在 SSR 中,这是不行的,因为服务器并不会执行 mounted 周期。那么我们是否可以把
this.fetchData
提前到 created 或者 beforeCreate 这两个生命周期中执行?同样不行。原因是:
this.fetchData
是异步请求,请求发出去之后,没等数据返回呢,后端就已经渲染完了,无法把 Ajax 返回的数据也一并渲染出来。所以,我们得提前知道都有哪些组件有 Ajax 请求,等把这些 Ajax 请求都返回了数据之后,才开始组件的渲染。
组件的 asyncData 方法已经定义好了,但是怎么索引到这个 asyncData 方法呢?先看我的根组件 App.vue 是怎么写的。
从根组件 App.vue 我们可以看到,只需要解析其 components 字段,便能依次找到各个组件的 asyncData 方法了。
还有几个问题比较有意思:
2.1. 当预先获取到的 Ajax 数据返回之后,Vue 组件还没开始渲染。所以,我们无法把 Ajax 数据直接挂载到组件实例上,只能把 Ajax 数据 先放在单独的某个地方。
2.2. 当 Vue 组件开始渲染的时候,还得把 Ajax 数据拿出来,正确地传递给各个组件。
2.3. 在浏览器渲染的时候,需要正确解析 window.INITIAL_STATE ,并传递给各个组件。
因此,我们得有这么一个独立于视图以外的地方,用来存储、管理和传递数据,这就是 Vuex 存在的理由。
this.msg
字段值。现在后端是把组件 HTML 渲染出来了,但是事件的绑定和触发肯定得由浏览器来完成啊,如果浏览器拿不到跟服务器端同样的数据的话,在触发组件点击事件的时候,又上哪儿去找 msg 字段呢?至此,我们已经完成了带 Ajax 数据的后端渲染了。这一步最为复杂,也最为关键,需要反复思考和尝试。具体渲染效果图如下所示,源码请参考这里。

首屏渲染速度对比
大功告成了吗?还没。人们都说 SSR 能提升首屏渲染速度,下面我们真实对比一下,看看到底是不是真的。(同样在 Fast 3G 网络条件下)。


官方思路的变形
行文至此,关于 Vue SSR Demo 便已经结束了。后面是我结合自身项目特点的一些变形,不感兴趣的读者可以不看。
第三步官方思路有什么缺点吗?我认为是有的:对老项目来说,改造成本比较大。需要显式的引入 vuex,就得走 action、mutations 那一套,无论是代码改动量还是新人学习成本,都不低。
有什么办法能减少对旧项目的改动量的吗?我是这么做的。
至此,我们就便得到了 Vue SSR 的一种变形。对于组件开发者而言,只需要把原来的
this.fetchData
方法抽象到 prefetchData 方法,然后就可以在 DOM 中使用{{prefetchData}}
拿到到数据了。这部分的代码请参考这里。总结
Vue SSR 确实是个有趣的东西,关键在于灵活运用。此 Demo 还有一个遗留问题没有解决:当把 Ajax 抽象到 prefetchData,做成 SSR 之后,原先的前端渲染就失效了。能不能同一份代码同时支持前端渲染和后端渲染呢?这样当后端渲染出问题的时候,我就可以随时切回前端渲染,也算是兜底的方案。
参考资料
----- 完 ------
The text was updated successfully, but these errors were encountered: