最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當(dāng)前位置: 首頁 - 科技 - 知識百科 - 正文

vue ssr 指南詳讀

來源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 22:12:15
文檔

vue ssr 指南詳讀

vue ssr 指南詳讀:本帖說明 該貼是對vue SSR Guide解讀和補(bǔ)充,對于官網(wǎng)文檔已有內(nèi)容會以引用方式體現(xiàn)。由于官網(wǎng)demo在國內(nèi)無法運(yùn)行,該貼最后也提供了一個完整的可以運(yùn)行的demo,帖子中提到的代碼均是來自于該demo,供學(xué)習(xí)交流。 介紹 什么是服務(wù)器端渲染(SSR)? Vu
推薦度:
導(dǎo)讀vue ssr 指南詳讀:本帖說明 該貼是對vue SSR Guide解讀和補(bǔ)充,對于官網(wǎng)文檔已有內(nèi)容會以引用方式體現(xiàn)。由于官網(wǎng)demo在國內(nèi)無法運(yùn)行,該貼最后也提供了一個完整的可以運(yùn)行的demo,帖子中提到的代碼均是來自于該demo,供學(xué)習(xí)交流。 介紹 什么是服務(wù)器端渲染(SSR)? Vu

本帖說明

該貼是對vue SSR Guide解讀和補(bǔ)充,對于官網(wǎng)文檔已有內(nèi)容會以引用方式體現(xiàn)。由于官網(wǎng)demo在國內(nèi)無法運(yùn)行,該貼最后也提供了一個完整的可以運(yùn)行的demo,帖子中提到的代碼均是來自于該demo,供學(xué)習(xí)交流。

介紹

什么是服務(wù)器端渲染(SSR)?

Vue.js 是構(gòu)建客戶端應(yīng)用程序的框架。默認(rèn)情況下,可以在瀏覽器中輸出 Vue 組件,進(jìn)行生成 DOM 和操作 DOM。然而,也可以將同一個組件渲染為服務(wù)器端的 HTML 字符串,將它們直接發(fā)送到瀏覽器,最后將靜態(tài)標(biāo)記"混合"為客戶端上完全交互的應(yīng)用程序。

借助vue-server-renderer 將vue實(shí)例渲染為瀏覽器可以識別的html字符串。

為什么使用服務(wù)器端渲染(SSR)?

  1. 更好的 SEO
  2. 更快的內(nèi)容到達(dá)時(shí)間 (白屏)

左側(cè)為瀏覽器渲染,右側(cè)為服務(wù)器渲染,從圖中可以看出服務(wù)端渲染理論上明顯少于瀏覽器渲染。

基本用法

安裝

git clone https://github.com/s249359986/learnssr.git
cd learnssr 
npm install
npm run dev

代碼結(jié)構(gòu)

src
├── components
│ ├── Foo.vue
├── views
│ ├── Home.vue
├── App.vue
├── app.js 
├── client-entry.js
├── server-entry.js

代碼詳解

server.js 是服務(wù)端啟動入口文件,接收客戶端對頁面的所有請求。

if (isProd) {
 /**
 生產(chǎn)環(huán)境,createRenderer將已經(jīng)通過webpack打包好的server-bundle.js轉(zhuǎn)化為一個可以操作的renderer對象。
 **/
 renderer = createRenderer(fs.readFileSync(resolve('./dist/server-bundle.js'), 'utf-8'))
 
 /**
 入口模板文件
 **/
 indexHTML = parseIndex(fs.readFileSync(resolve('./dist/index.html'), 'utf-8'))
} else {
 /**
 開發(fā)環(huán)境,createRenderer將已經(jīng)通過webpack打包好的server-bundle.js轉(zhuǎn)化為一個可以操作的renderer對象。
 **/
 require('./build/setup-dev-server')(app, {
 bundleUpdated: bundle => {
 renderer = createRenderer(bundle)
 },
 indexUpdated: index => {//index為入口文件及index.html
 indexHTML = parseIndex(index)
 }
 })
}

function createRenderer (bundle) {

 return require('vue-server-renderer').createBundleRenderer(bundle, {
 cache: require('lru-cache')({
 max: 1,//1000,
 maxAge: 2000//1000 * 60 * 15
 }),
 runInNewContext: false
 })
}
/*
讀取入口文件
*/
function parseIndex (template) {
 const contentMarker = '<!-- APP -->'
 const i = template.indexOf(contentMarker)
 return {
 head: template.slice(0, i),
 tail: template.slice(i + contentMarker.length)
 }
}

const serve = (path, cache) => express.static(resolve(path), {
 maxAge: cache && isProd ? 60 * 60 * 24 * 30 : 0
})

app.use('/dist', serve('./dist'))

app.get('*', (req, res) => {
 if (!renderer) {
 return res.end('waiting for compilation... refresh in a moment.')
 }

 res.setHeader('Content-Type', 'text/html')
 res.setHeader('Server', serverInfo)

 var s = Date.now()
 const context = { url: req.url }
 /*
 渲染vue實(shí)例,context對象上下文
 */
 const renderStream = renderer.renderToStream(context)

 renderStream.once('data', () => {
 res.write(indexHTML.head)
 })

 renderStream.on('data', chunk => {
 res.write(chunk)
 })

 renderStream.on('end', () => {
 if (context.initialState) {
 res.write(
 `<script>window.__INITIAL_STATE__=${
 serialize(context.initialState, { isJSON: true })
 }</script>`
 )
 }
 res.end(indexHTML.tail)
 console.log(`whole request: ${Date.now() - s}ms`)
 })

 renderStream.on('error', err => {
 if (err && err.code === '404') {
 res.status(404).end('404 | Page Not Found')
 return
 }
 res.status(500).end('Internal Error 500')
 console.error(`error during render : ${req.url}`)
 console.error(err)
 })
})

const port = process.env.PORT || 8080
app.listen(port, () => {
 console.log(`server started at localhost:${port}`)
})

服務(wù)端vue實(shí)例入口文件,通過上下文對象獲取請求的url,映射給對應(yīng)的組件。

export default context => {
 const s = isDev && Date.now()
 router.push(context.url)
 const matchedComponents = router.getMatchedComponents()
 if (!matchedComponents.length) {
 return Promise.reject({ code: '404' })
 }
 return Promise.all(matchedComponents.map(component => {
/*
增加服務(wù)端數(shù)據(jù)預(yù)處理 start

*/
 if (component.asyncData) {
 return component.asyncData({
 store,
 route: router.currentRoute
 })
 }

 /*
 增加服務(wù)端數(shù)據(jù)預(yù)處理 end

 */
 })).then(() => {
 isDev && console.log(`data pre-fetch: ${Date.now() - s}ms`)
 context.initialState = store.state
 return app
 })
}

客戶端vue實(shí)例入口文件.

/*

第一種方式
 */

Vue.mixin({
 beforeMount () {
 const { asyncData } = this.$options
 console.log('beforeMount',this.$store)
 if (asyncData) {

 // 將獲取數(shù)據(jù)操作分配給 promise
 // 以便在組件中,我們可以在數(shù)據(jù)準(zhǔn)備就緒后
 // 通過運(yùn)行 `this.dataPromise.then(...)` 來執(zhí)行其他任務(wù)
 this.dataPromise = asyncData({
 store: this.$store,
 route: this.$route
 })
 }
 },
 beforeRouteUpdate (to, from, next) {
 const { asyncData } = this.$options
 console.log('beforeRouteUpdate',this.$store)
 if (asyncData) {
 asyncData({
 store: this.$store,
 route: to
 }).then(next).catch(next)
 } else {
 next()
 }
}
})

/**
更新客戶端store,與服務(wù)端store同步
**/
// store.replaceState(window.__INITIAL_STATE__)
if (window.__INITIAL_STATE__) {
 store.replaceState(window.__INITIAL_STATE__)
}
// actually mount to DOM


router.onReady(() => {
/**
掛載實(shí)例,客戶端激活,所謂激活,指的是 Vue 在瀏覽器端接管由服務(wù)端發(fā)送的靜態(tài) HTML,使其變?yōu)橛?Vue 管理的動態(tài) DOM 的過程。注釋掉app.$mount('#app') 可以清楚看到<div id="app" data-server-rendered="true"> 客戶端通過data-server-rendered="true"知道該html是vue在服務(wù)端渲染的,并且不會在做多余的渲染。由于在服務(wù)端無法綁定事件,只有通過客戶端vue處理。
**/
 app.$mount('#app')
})

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

vue ssr 指南詳讀

vue ssr 指南詳讀:本帖說明 該貼是對vue SSR Guide解讀和補(bǔ)充,對于官網(wǎng)文檔已有內(nèi)容會以引用方式體現(xiàn)。由于官網(wǎng)demo在國內(nèi)無法運(yùn)行,該貼最后也提供了一個完整的可以運(yùn)行的demo,帖子中提到的代碼均是來自于該demo,供學(xué)習(xí)交流。 介紹 什么是服務(wù)器端渲染(SSR)? Vu
推薦度:
標(biāo)簽: VUE ssr 指南
  • 熱門焦點(diǎn)

最新推薦

猜你喜歡

熱門推薦

專題
Top