简单的Vue SSR的示例代码

2020-06-16 06:24:29易采站长站整理

// context 是 vue-server-render 注入的参数
const store = createStore();
let app = new Vue({
store,
render: h => h(App)
});

// 找到所有 asyncData 方法
let components = App.components;
let prefetchFns = [];
for (let key in components) {
if (!components.hasOwnProperty(key)) continue;
let component = components[key];
if(component.asyncData) {
prefetchFns.push(component.asyncData({
store
}))
}
}

return Promise.all(prefetchFns).then((res) => {
// 在所有组件的 Ajax 都返回之后,才最终返回 app 进行渲染
context.state = store.state;
// context.state 赋值成什么,window.__INITIAL_STATE__ 就是什么
return app;
});
};

还有几个问题比较有意思:

1、是否必须使用 vue-router?→ 不是。虽然官方给出的 Demo 里面用到了 vue-router,那只不过是因为官方 Demo 是包含多个页面的 SPA 罢了。一般情况下,是需要用 vue-router 的,因为不同路由对应不同的组件,并非每次都把所有组件的 asyncData 都执行的。但是有例外,比如我的这个老项目,就只有一个页面(一个页面中包含很多的组件),所以根本不需要用到 vue-router,也照样能做 SSR。主要的区别就是如何找到那些该被执行的 asyncData 方法:官方 Demo 通过 vue-router,而我通过直接解析 components 字段,仅此而已。

2、是否必须使用 Vuex? → 是,但也不是,请看尤大的回答。为什么必须要有类似 Vuex 的存在?我们来分析一下。

2.1. 当预先获取到的 Ajax 数据返回之后,Vue 组件还没开始渲染。所以,我们得把 Ajax 先存在某个地方。

2.2. 当 Vue 组件开始渲染的时候,还得把 Ajax 数据拿出来,正确地传递到各个组件中。

2.3. 在浏览器渲染的时候,需要正确解析 window.INITIAL_STATE ,并传递给各个组件。

因此,我们得有这么一个独立于视图以外的地方,用来存储、管理和传递数据,这就是 Vuex 存在的理由。

3、后端已经把 Ajax 数据转化为 HTML 了,为什么还需要把 Ajax 数据通过 window.INITIAL_STATE 传递到前端? → 因为前端渲染的时候仍然需要知道这些数据。举个例子,你写了一个组件,给它绑定了一个点击事件,点击的时候打印出 this.msg 字段值。现在后端是把组件 HTML 渲染出来了,但是事件的绑定肯定得由浏览器来完成啊,如果浏览器拿不到跟服务器端同样的数据的话,在触发组件的点击事件的时候,又上哪儿去找 msg 字段呢?

至此,我们已经完成了带 Ajax 数据的后端渲染了。这一步最为复杂,也最为关键,需要反复思考和尝试。具体渲染效果图如下所示,源码请参考这里。