前段时间公司要开发官网,而公司这边一直是用vue开发,所以很自然就想着用vue的服务器端渲染的方案;如果用vue-server-render插件然后自己搭建node服务,这听起来就有很多事情,不过放心,nuxt框架就是已经帮你做了这些事情,也帮我们踩了很多坑,所以就直接采用nuxt来开发服务器端渲染;
本次小结主要是记录当时开发工程中很纠结的两个方面:
1、nuxt的渲染过程;
2、数据应该在哪获取?
nuxt的渲染过程
服务器端渲染,本质上就是在服务器端上就拿到要展示的数据,然后生成好对应的html返回给web,这样很便于做seo;
渲染的流程图如下:
上面的流程,每个具体的用法可以参考nuxt文档,我想强调的是:
1)nuxtServerInit,这个是在store/index.js中定义的,nuxt会在服务器渲染的时候第一个调用,所以可以把用户信息这类全局的不经常变的信息在这里获取;
export const actions = {
async nuxtServerInit ({ commit }, { req }) {
let {data} = await getUserInfo() commit('setUserInfo', data)
},
}
2)nuxt中组件可分为页面组件(pages目录下的组件)和非页面组件(components下的各个组件);
asyncData,这个方法的返回值会赋值给data中的对应属性;仅限于页面组件
async asyncData(context){
let {id} = context.params
let prdList = await getPrdList(id)
return {prdList}
}
fetch,这个方法可以操作store,可以用来提前设置好vuex中的状态;
fetch ({ store, params }) {
store.commit('setCurrentPage', Pages.About)
}
3)nuxt中组件的生命周期,
在服务器端渲染的时候,只有beforeCreate和created才会被调用;(很明显mounted那些在服务器端也没必须要调用)
在web端渲染的时候,生命周期是正常的;
现在,我们需要梳理下关心的两件事情:
1)第一次打开网页时,是怎么渲染的?
对应流程图中IncomingRequest开始的从上到下的流程;
在服务器端渲染的时候,会调用页面组件的asyncData/beforeCreate/created/fetch,以及非页面组件的beforeCreate/created/fetch,渲染完成后,传递给web;
page, asyncData
page, beforeCreate
page, created
page, fetch
component, beforeCreate
component, created
component, fetch
在web端会进行渲染,会调用组件的正常的生命周期:
page, beforeCreate
page, created
page, beforeMount
component, beforeCreate
component, created
component, beforeMount
component, mounted
page, mounted
2)web端渲染后,在网页上点击跳转又是怎么渲染的?
对应流程图中Navigate开始的流程;注意这是在web端渲染的,这时会调用页面组件的asyncData/beforeCreate/created/beforeMount/fetch/mounted,以及非页面组件的beforeCreate/created/beforeMount/fetch/mounted
page, asyncData
page, beforeCreate
page, created
page, beforeMount
page, fetch
component, beforeCreate
component, created
component, beforeMount
component, fetch
component, mounted
page, mounted
数据应该在哪获取?
我们一般会在created中获取数据,而在nuxt中,对于服务器端渲染的情况这会有两个问题:
1)created会被调用两次,导致获取两次数据;
2)更严重的问题是,nuxt并不会等created中的数据返回后才将渲染结果返回给web,导致虽然去获取数据了,但提交给web的依然是未更新的值,ssr也就没起作用;
很明显,我们就应该在asyncData中获取数据,因为nuxt会等待asyncData中的数据返回并融入到data属性中;
如果数据都在asyncData中获取,而这个方法只能在页面组件中使用,那非页面组件中要获取数据怎么办?
当然是正常获取咯,因为我们在created中获取都是初始数据,这个我们可以在页面组件中通过asyncData方法获取到后传入到非页面组件中;页面已经打开后的数据获取,我们正常调用方法获取就行;