iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > node.js >vue中怎么实现服务端渲染
  • 212
分享到

vue中怎么实现服务端渲染

2024-04-02 19:04:59 212人浏览 独家记忆
摘要

本篇文章为大家展示了Vue中怎么实现服务端渲染,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、什么是服务端渲染客户端请求服务器,服务器根据请求地址获得匹配的组件,

本篇文章为大家展示了Vue中怎么实现服务端渲染,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

一、什么是服务端渲染

客户端请求服务器,服务器根据请求地址获得匹配的组件,在调用匹配到的组件返回Promise (官方是asyncData方法)来将需要的数据拿到。最后再通过window.__initial_state=data将其写入网页,最后将服务端渲染好的网页返回回去。接下来客户端将用新的store状态把原来的store状态替换掉,保证客户端和服务端的数据同步。遇到没被服务端渲染的组件,再去发异步请求拿数据。

服务端渲染的环境搭建

vue中怎么实现服务端渲染

这是vue官网的服务端渲染的示意图,ssr有两个入口文件,分别是客户端的入后文件和服务端的入口文件,webpack通过两个入口文件分别打包成给服务端用的server bundle和给客户端用的client bundle.当服务器接收到了来自客户端的请求之后,会创建一个渲染器bundleRenderer,这个bundleRenderer会读取上面生成的server bundle文件,并且执行它的代码, 然后发送一个生成好的html到浏览器,等到客户端加载了client bundle之后,会和服务端生成的DOM进行Hydration(判断这个DOM和自己即将生成的DOM是否相同,如果相同就将客户端的vue实例挂载到这个DOM上)

实现步骤:

1、创建vue实例(main.js

importVuefrom'vue'
importAppfrom'./App.vue'
importiViewfrom'iview';
import{createStore}from'./store'
import{createRouter}from'./router'
import{sync}from'vuex-router-sync'
Vue.use(iView);
export functioncreateApp() {
conststore = createStore()
constrouter = createRouter()
sync(store,router)
constapp =newVue({
router,
store,
render: h => h(App)
})
return{app,router,store}
}

因为要做服务端渲染,所以这里不需要再用el去挂载,现将app、router、store导出

2、服务端入口文件(entry-server.js)

import{ createApp }from'./main'
constisDev = process.env.node_ENV !=='production'
const{ app,router,store } = createApp()
constgetAllAsyncData=function(component){
letstores = []
functionloopComponent(component) {
if(typeofcomponent.asyncData !=='undefined') {
for(letaofcomponent.asyncData({store,route: router.currentRoute})) {
stores.push(a)
}
}
if(typeofcomponent.components !=='undefined') {
for(letcincomponent.components){
loopComponent(component.components[c])
}
}
}
loopComponent(component)
returnstores
}
export defaultcontext => {
return newPromise((resolve,reject) => {
consts = isDev && Date.now()
const{url} = context
constfullPath = router.resolve(url).route.fullPath
if(fullPath !== url) {
reject({url: fullPath })
}
router.push(url)
router.onReady(() => {
constmatchedComponents = router.getMatchedComponents()
if(!matchedComponents.length) {
reject({code:404})
}
letallAsyncData = getAllAsyncData(matchedComponents[0])
Promise.all(allAsyncData).then(() => {
isDev && console.log(`data pre-fetch:${Date.now() - s}ms`)
context.state = store.state
resolve(app)
}).catch(reject)
},reject)
})
}

这个文件的主要工作是接受从服务端传递过来的context参数,context包含当前页面的url,用getMatchedComponents方法获取当前url下的组件,返回一个数组,遍历这个数组中的组件,如果组件有asyncData钩子函数,则传递store获取数据,最后返回一个promise对象。

store.state的作用是将服务端获取到的数据挂载到context对象上,后面在server.js文件里会把这些数据直接发送到浏览器端与客户端的vue实例进行数据(状态)同步。

3、客户端入口文件(entry-client.js)

importVuefrom'vue'
import'es6-promise/auto'
import{ createApp }from'./main'
importProgressBarfrom'./components/ProgressBar.vue'
// global progress bar
constbar = Vue.prototype.$bar =newVue(ProgressBar).$mount()
document.body.appendChild(bar.$el)
Vue.mixin({
beforeRouteUpdate(to,from,next) {
const{ asyncData } =this.$options
if(asyncData) {
Promise.all(asyncData({
store:this.$store,
route: to
})).then(next).catch(next)
}else{
next()
}
}
})
const{ app,router,store } = createApp()
if(window.__INITIAL_STATE__) {
store.replaceState(window.__INITIAL_STATE__)
}
router.onReady(() => {
router.beforeResolve((to,from,next) => {
constmatched = router.getMatchedComponents(to)
constprevMatched = router.getMatchedComponents(from)
letdiffed =false
constactivated = matched.filter((c,i) => {
returndiffed || (diffed = (prevMatched[i] !== c))
})
constasyncDataHooks = activated.map(c => c.asyncData).filter(_ => _)
if(!asyncDataHooks.length) {
returnnext()
}
bar.start()
Promise.all(asyncDataHooks.map(hook => hook({ store,route: to })))
.then(() => {
bar.finish()
next()
})
.catch(next)
})
app.$mount('#app')
})
if('https:'=== location.protocol && navigator.serviceWorker) {
navigator.serviceWorker.reGISter('/service-worker.js')
}
if(window.INITIAL_STATE) {
store.replaceState(window.INITIAL_STATE)
}

这句的作用是如果服务端的vuex数据发生改变,就将客户端的数据替换掉,保证客户端和服务端的数据同步

Service Worker主要用于拦截并修改访问和资源请求,细粒度地缓存资源。它运行浏览器在后台,运行环境与普通页面脚本不同,所以不能直接参与页面交互。出于安全考虑,service worker只能运行在HttpS上,防止被人从中攻击。

4、创建服务端渲染器(server.js)

constfs = require('fs')
constpath = require('path')
constLRU = require('lru-cache')
constexpress = require('express')
constcompression = require('compression')
constresolve= file => path.resolve(__dirname,file)
const{ createBundleRenderer } = require('vue-server-renderer')
constisProd = process.env.NODE_ENV ==='production'|| process.env.NODE_ENV ==='beta'
constuseMicroCache = process.env.MICRO_CACHE !=='false'
constserverInfo =
`express/${require('express/package.JSON').version}`+
`vue-server-renderer/${require('vue-server-renderer/package.json').version}`
constapp = express()
consttemplate = fs.readFileSync(resolve('./src/index.template.html'),'utf-8')
functioncreateRenderer(bundle,options) {
returncreateBundleRenderer(bundle,Object.assign(options,{
template,
cache: LRU({
max:1000,
maxAge:1000*60*15
}),
basedir: resolve('./dist'),
runInNewContext:false
}))
}
letrenderer
letreadyPromise
if(isProd) {
constbundle = require('./dist/vue-ssr-server-bundle.json')
constclientManifest = require('./dist/vue-ssr-client-manifest.json')
renderer = createRenderer(bundle,{
clientManifest
})
}else{
readyPromise = require('./build/setup-dev-server')(app,(bundle,options) => {
renderer = createRenderer(bundle,options)
})
}
constserve= (path,cache) => express.static(resolve(path),{
maxAge: cache && isProd ?1000*60*60*24*30:0
})
app.use(compression({threshold:0}))
app.use('/dist',serve('./dist',true))
app.use('/static',serve('./static',true))
app.use('/service-worker.js',serve('./dist/service-worker.js'))
constmicroCache = LRU({
max:100,
maxAge:1000
})
constisCacheable= req => useMicroCache
functionrender(req,res) {
consts = Date.now()
res.setHeader("Content-Type","text/html")
res.setHeader("Server",serverInfo)
consthandleError= err => {
if(err.url) {
res.redirect(err.url)
}else if(err.code ===404) {
res.status(404).end('404 | Page Not Found')
}else{
// Render Error Page or Redirect
res.status(500).end('500 | Internal Server Error')
console.error(`error during render :${req.url}`)
console.error(err.stack)
}
}
constcacheable = isCacheable(req)
if(cacheable) {
consthit = microCache.get(req.url)
if(hit) {
if(!isProd) {
console.log(`cache hit!`)
}
returnres.end(hit)
}
}
constcontext = {
title:'Vue DB',// default title
url: req.url
}
renderer.renderToString(context,(err,html) => {
if(err) {
returnhandleError(err)
}
res.end(html)
if(cacheable) {
microCache.set(req.url,html)
}
if(!isProd) {
console.log(`whole request:${Date.now() - s}ms`)
}
})
}
app.get('*',isProd ? render : (req,res) => {
readyPromise.then(() => render(req,res))
})
constport = process.env.PORT ||8888
app.listen(port,() => {
console.log(`server started at localhost:${port}`)
})

5、客户端api文件create-api-client.js



import axiOS from 'axios';
let api;

axios.defaults.baseURL = process.env.API_URL;
axios.defaults.timeout = 10000;

axios.interceptors.response.use((res) => {
 if (res.status >= 200 && res.status < 300) {
  return res;
 }
 return Promise.reject(res);
}, (error) => {
 return Promise.reject({message: '网络异常,请刷新重试', err: error});
});

if (process.__API__) {
 api = process.__API__;
} else {
 api = {
  get: function(url) {
   return new Promise((resolve, reject) => {
    axios.get(url).then(res => {
     resolve(res);
    }).catch((error) => {
     reject(error);
    });
   });
  },
  post: function(target, options = {}) {
   return new Promise((resolve, reject) => {
    axios.post(target, options).then(res => {
     resolve(res);
    }).catch((error) => {
     reject(error);
    });
   });
  }
 };
}

export default api;

6、服务端api文件create-api-server.js



import axios from 'axios';
let cook = process.__COOKIE__ || '';
let api;

axios.defaults.baseURL = 'https://api.douban.com/v2/';
axios.defaults.timeout = 10000;

axios.interceptors.response.use((res) => {
 if (res.status >= 200 && res.status < 300) {
  return Promise.resolve(res);
 }
 return Promise.reject(res);
}, (error) => {
 // 网络异常
 return Promise.reject({message: '网络异常,请刷新重试', err: error, type: 1});
});

if (process.__API__) {
 api = process.__API__;
} else {
 api = {
  get: function(target) {
   return new Promise((resolve, reject) => {
    axios.request({
     url: encodeURI(target),
     method: 'get',
     headers: {
      'Cookie': cook
     }
    }).then(res => {
     resolve(res);
    }).catch((error) => {
     reject(error);
    });
   });
  },
  post: function(target, options = {}) {
   return new Promise((resolve, reject) => {
    axios.request({
     url: target,
     method: 'post',
     headers: {
      'Cookie': cook
     },
     params: options
    }).then(res => {
     resolve(res);
    }).catch((error) => {
     reject(error);
    });
   });
  }
 };
}

export default api;

六、那些年遇到的那些坑

问题1、window is not defined

答案1:给用到浏览器对象的地方加if (typeof window !== 'undefined') {},有一些插件里也用到了浏览器对象,在使用的地方也加一个条件判断:

if (typeofwindow !== 'undefined') {
Vue.use(VueAnalytics, {
id: process.env.UA_TRACKING_ID,
router
})
}

问题2:用到非Vue系列的插件,如hello.all.js(三方登录的插件),需要用的地方才引用,报的错和问题1一样。

答案2:这个时候不能再用import导入,需要使用require,

let hello

if (typeof window !== 'undefined') {
hello = require('hello')
}

问题3:引用bootstrap

答案3:将bootstrap.CSS和bootstrap.js加入WEBpack.base.config.js的entry中的vendor中

问题6:bootstap需要Jquery,此时把jQuery加在vendor中没用。

答案6:给webpack.base.config.js的plugins添加一个插件,如:

newwebpack.ProvidePlugin({
$ : "jquery",
jQuery : "jquery",
"window.jQuery" :"jquery"
})

上述内容就是vue中怎么实现服务端渲染,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注编程网node.js频道。

--结束END--

本文标题: vue中怎么实现服务端渲染

本文链接: https://www.lsjlt.com/news/72192.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • vue中怎么实现服务端渲染
    本篇文章为大家展示了vue中怎么实现服务端渲染,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、什么是服务端渲染客户端请求服务器,服务器根据请求地址获得匹配的组件,...
    99+
    2024-04-02
  • vue中如何实现SSR服务端渲染
    本篇内容主要讲解“vue中如何实现SSR服务端渲染”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vue中如何实现SSR服务端渲染”吧!一、SSR是什么Server-Side Rendering ...
    99+
    2023-06-29
  • Vue项目中如何实现服务器端渲染
    本篇内容介绍了“Vue项目中如何实现服务器端渲染”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!vue-ssr在项目中的实践写在文前由于前端脚...
    99+
    2023-06-04
  • Vue怎么实现条件渲染与列表渲染
    本文小编为大家详细介绍“Vue怎么实现条件渲染与列表渲染”,内容详细,步骤清晰,细节处理妥当,希望这篇“Vue怎么实现条件渲染与列表渲染”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。一、Vue条件渲染v-show...
    99+
    2023-06-30
  • 怎么改造Vue SSR服务端渲染
    本篇内容介绍了“怎么改造Vue SSR服务端渲染”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Vue的SS...
    99+
    2024-04-02
  • Vue中怎么实现列表渲染
    这期内容当中小编将会给大家带来有关Vue中怎么实现列表渲染,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。<!DOCTYPE html> <ht...
    99+
    2024-04-02
  • Angular中如何实现服务端渲染
    这篇文章主要介绍Angular中如何实现服务端渲染,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Angular UniversalAngular在服务端渲染方面提供一套前后端同构解决...
    99+
    2024-04-02
  • Angular4+server render服务端渲染怎么实现
    这篇文章将为大家详细讲解有关Angular4+server render服务端渲染怎么实现,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。目标:1.更好的 SEO,方便搜索...
    99+
    2024-04-02
  • React服务端渲染和同构怎么实现
    这篇文章主要讲解了“React服务端渲染和同构怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“React服务端渲染和同构怎么实现”吧!背景第一阶段很久以前, 一个网站的开发还是前端和服...
    99+
    2023-06-30
  • Vue服务端如何渲染SSR
    这篇文章主要介绍“Vue服务端如何渲染SSR”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Vue服务端如何渲染SSR”文章能帮助大家解决问题。手写Vue服务端渲染概念:放在浏览器进行就是浏览器渲染,...
    99+
    2023-07-02
  • vue服务端渲染和客户端渲染的区别有哪些
    本文小编为大家详细介绍“vue服务端渲染和客户端渲染的区别有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue服务端渲染和客户端渲染的区别有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,...
    99+
    2024-04-02
  • Vue中怎么搭建一个服务端渲染项目
    这篇文章给大家介绍Vue中怎么搭建一个服务端渲染项目,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。客户端渲染过程 访问客户端渲染的网站。 服务器返回一个包含了引入资...
    99+
    2024-04-02
  • Vue跨端渲染实现多端无缝衔接
    Vue 内部的组件是以虚拟 dom 形式存在的。下面的代码就是一个很常见的虚拟 Dom,用对象的方式去描述一个项目。相比 dom 标签相比,这种形式可以让整个 Vue 项目脱离浏览器...
    99+
    2023-05-19
    Vue跨端渲染 Vue渲染机制
  • Vue服务端渲染和Vue浏览器端渲染性能对比的示例分析
    Vue服务端渲染和Vue浏览器端渲染性能对比的示例分析,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。本人在做Vue项目的时候,一直苦于产品...
    99+
    2024-04-02
  • Vue中的动态组件怎么实现渲染
    本篇内容介绍了“Vue中的动态组件怎么实现渲染”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、什么是动态组件动态组件指的是动态切换组件的显...
    99+
    2023-06-30
  • React服务器端渲染怎么用
    这篇文章给大家分享的是有关React服务器端渲染怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。React 提供了两个方法 renderToString 和 renderTo...
    99+
    2024-04-02
  • Vue 服务端渲染SSR示例详解
    目录手写Vue服务端渲染一.开始vue-ssr之旅二.采用模板渲染三.ssr目录创建四.通过webpack实现编译vue项目app.jsclient-entry.jsserver-e...
    99+
    2024-04-02
  • React服务端渲染和同构的实现
    目录背景第一阶段第二阶段第三阶段创建一个服务端渲染应用同构流程总结路由路由同构背景 第一阶段 很久以前, 一个网站的开发还是前端和服务端在一个项目来维护, 可能是用php+jquer...
    99+
    2024-04-02
  • nestjs搭配nestjs实现react服务端渲染
    nestjs作为nodejs的服务端框架,底层是基于express的,但是功能更加完善,使用方式也是很贴近spring的。而nextjs官方的demo又没有基于nestjs的所以,就自己来写一个吧。 1.安装nest-cli npm i -...
    99+
    2024-04-02
  • Vue服务端渲染框架Nuxt的步骤
    本篇内容介绍了“Vue服务端渲染框架Nuxt的步骤”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Vue因其...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作