前言大多数Vue项目出于SEO的考虑,应该支持SSR。毕竟对于WEB应用来说,搜索引擎是一个很大的流量入口。VueSSR现在已经比较成熟了,但是如果将SPA应用改造为SSR应用,成本还是有点高,工作量和重构前端没什么区别。另外对前端的技术要求比较高,需要熟悉Vue,有Node.js和webpack的应用经验。Vue的引入是一个构建客户端应用的框架,即在浏览器中渲染Vue组件。所谓服务器端渲染,是指在服务器端将Vue组件渲染成组装好的HTML字符串,然后直接发送给浏览器。最后,这些静态标签需要在客户端作为完全交互的应用程序被“激活”。程序。服务器端渲染的优点BetterSEO,搜索引擎爬虫可以抓取渲染的页面Fastercontentarrivaltime(首屏加载速度更快),因为服务器只需要返回渲染的HTML,这部分代码非常小,所以用户体验更好。服务器端渲染的缺点是开发成本比较高。比如一些生命周期钩子函数(比如beforeCreate、created)可以同时运行在服务端和客户端,所以第三方库需要做特殊处理才能在服务端渲染的应用中运行。由于服务端渲染使用Nodejs作为中间层,所以在部署项目时,需要在Node.js服务端运行环境。在大流量环境下,还需要做好服务器负载原理和缓存策略的分析。先附上demo地址:https://github.com/wmui/vue-s...第一步:编写entry-client.js和entry-server.jsentry-client.js只在浏览器环境下执行,所以需要显示并调用$mount方法挂载DOM节点importVuefrom'vue';importAppfrom'./App.vue';importcreateStorefrom'./store/index.js';函数createApp(){conststore=createStore();constapp=newVue({store,render:h=>h(App)});return{app,store}}const{app,store}=createApp();//用window.__INITIAL_STATE__中的数据替换整个state中的数据,这样服务端渲染后,客户端可以自由操作数据在状态if(window.__INITIAL_STATE__){store.replaceState(window.__INITIAL_STATE__);}app.$mount('#app');entry-server.js需要导出一个函数,服务端渲染时会调用该函数importVuefrom'vue';importAppfrom'./App.vue';importcreateStorefrom'./store/index.js';exportdefaultfunction(context){//context是上下文对象conststore=createStore();letapp=newVue({store,render:h=>h(App)});//找到所有的asyncData方法letcomponents=App.components;让asyncDataArr=[];//亲misecollectionfor(letkeyincomponents){if(!components.hasOwnProperty(key))continue;让组件=组件[键];if(component.asyncData){asyncDataArr.push(component.asyncData({store}))//将store传递给asyncData}}//所有请求并行执行returnPromise.all(asyncDataArr).then(()=>{//context.state赋给了什么,window.__INITIAL_STATE__是什么//现在你应该明白entry-client.js中的window.__INITIAL_STATE__是从哪里来的,在服务端渲染context.state的时候添加到context中=store.state;返回应用程序;});};上面asyncData是干什么用的?其实这个函数就是专门用来请求数据的。你可能会问为什么请求数据没有在beforeCreate或者created中完成,还需要专门定义一个函数?虽然beforeCreate和created也会在server端执行(其他周期函数只会在client端执行),但是我们都知道请求是异步的,导致请求完成后还没有返回数据就渲染结束了发送。所以Ajax返回的数据是不能一起渲染的,所以我们需要想办法在所有的数据都返回之后再渲染组件。asyncData需要返回一个promise,这样组件才能在所有请求完成后渲染。下面是在foo组price中使用asyncData的例子,这里数据请求完成exportdefault{asyncData:function({store}){returnstore.dispatch('GET_ARTICLE')//returnpromise},computed:{article(){returnthis.$store.state.article}}}第二步:配置webpackwebpack的配置比较简单,但是也需要针对客户端和服务端分别进行配置。webpack.client.conf.js显然是用来打包客户端应用的module.exports=merge(base,{entry:{client:path.join(__dirname,'../entry-client.js')}});webpack.server.conf.js用于打包服务端应用,这里需要指定节点环境module.exports=merge(base,{target:'node',//指定节点环境entry:{server:path.join(__dirname,'../entry-server.js')},output:{filename:'[name].js',//server.jslibraryTarget:'commonjs2'//必须按照commonjs规范打包到被服务器调用。},插件:[newHtmlWebpackPlugin({template:path.join(__dirname,'../index.ssr.html'),文件名:'index.ssr.html',文件:{js:'client.js'},//client.js需要在html中引入excludeChunks:['server']//server.js只在服务端执行,不能打包成html})]});第三步:打包完成后启动服务即可启动服务。在start.js中,我们需要加载server.js,然后通过renderToString方法将渲染后的html返回给浏览器。constbundle=fs.readFileSync(path.resolve(__dirname,'dist/server.js'),'utf-8');constrenderer=require('vue-server-renderer').createBundleRenderer(bundle,{模板:fs.readFileSync(path.resolve(__dirname,'dist/index.ssr.html'),'utf-8')//服务器端渲染数据});server.get('*',(req,res)=>{renderer.renderToString((err,html)=>{//console.log(html)if(err){console.error(err);res.status(500).end('内部服务器错误');返回;}res.end(html);})});demo已经上传到github:http://github.com/wmui/vue-ss...结语我实践了一段时间的VueSSR,发现搭建一个完整的SSR服务框架还是很有挑战性的,也许Nuxt是一个不错的选择对Nuxt感兴趣的朋友可以参考上面我的一篇开源作品Essay,感谢阅读!
