国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題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關鍵字專題關鍵字專題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
當前位置: 首頁 - 科技 - 知識百科 - 正文

vue服務端渲染的實例代碼

來源:懂視網 責編:小采 時間:2020-11-27 22:31:36
文檔

vue服務端渲染的實例代碼

vue服務端渲染的實例代碼:一、什么是服務端渲染 客戶端請求服務器,服務器根據請求地址獲得匹配的組件,在調用匹配到的組件返回Promise (官方是asyncData方法)來將需要的數據拿到。最后再通過window.__initial_state=data將其寫入網頁,最后將服務端渲染好的網頁返回回去。接下來客戶
推薦度:
導讀vue服務端渲染的實例代碼:一、什么是服務端渲染 客戶端請求服務器,服務器根據請求地址獲得匹配的組件,在調用匹配到的組件返回Promise (官方是asyncData方法)來將需要的數據拿到。最后再通過window.__initial_state=data將其寫入網頁,最后將服務端渲染好的網頁返回回去。接下來客戶

一、什么是服務端渲染

客戶端請求服務器,服務器根據請求地址獲得匹配的組件,在調用匹配到的組件返回Promise (官方是asyncData方法)來將需要的數據拿到。最后再通過window.__initial_state=data將其寫入網頁,最后將服務端渲染好的網頁返回回去。接下來客戶端將用新的store狀態把原來的store狀態替換掉,保證客戶端和服務端的數據同步。遇到沒被服務端渲染的組件,再去發異步請求拿數據。

服務端渲染的環境搭建

這是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

/**
 * Created by lin on 2017/8/25.
 */

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

/**
 * Created by lin on 2017/8/25.
 */

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"
})

七、例子

https://github.com/linmoer/ssr-vue這是一個服務端渲的例子

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

vue服務端渲染的實例代碼

vue服務端渲染的實例代碼:一、什么是服務端渲染 客戶端請求服務器,服務器根據請求地址獲得匹配的組件,在調用匹配到的組件返回Promise (官方是asyncData方法)來將需要的數據拿到。最后再通過window.__initial_state=data將其寫入網頁,最后將服務端渲染好的網頁返回回去。接下來客戶
推薦度:
標簽: VUE 代碼 示例
  • 熱門焦點

最新推薦

猜你喜歡

熱門推薦

專題
Top
主站蜘蛛池模板: 午夜又黄又爽 | 国产v欧美v日韩在线观看 | 久久久视 | 天天色啪 | 91精品专区 | 黄网站色视频免费观看 | 欧美色人| 欧美a在线播放 | 国产二区精品 | 欧美另类图片亚洲偷 | 亚洲 欧美 中文 日韩欧美 | 亚洲高清在线观看视频 | 亚洲欧美自拍一区 | 亚洲欧美字幕 | 另类专区 亚洲 | 国产99久久九九精品免费 | 欧美日韩国产一区 | 日本三级成人中文字幕乱码 | 日本不卡视频一区二区三区 | 国产一区二区日韩欧美在线 | 欧美极品第1页专区 | 欧美在线 | 亚洲 | 国产欧美日韩视频在线观看 | 麻豆成人在线 | 一区二区三区网站 | 国产视频高清 | 色yeye在线观看 | 国产在线观看入口 | 精品日韩一区二区 | 99久久精品国产亚洲 | 九九热这里有精品 | 精品视频一区二区 | 国产亚洲婷婷香蕉久久精品 | 国内视频一区二区三区 | 波多野结衣网站 | 毛片一区 | 在线精品欧美日韩 | 国产成人精品一区二三区在线观看 | 久久久久久久久久久9精品视频 | 在线观看网站国产 | 国产精品成人一区二区 |