<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答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服務端渲染的實例代碼

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

        vue服務端渲染的實例代碼

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

        一、什么是服務端渲染

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

        服務端渲染的環(huán)境搭建

        這是vue官網(wǎng)的服務端渲染的示意圖,ssr有兩個入口文件,分別是客戶端的入后文件和服務端的入口文件,webpack通過兩個入口文件分別打包成給服務端用的server bundle和給客戶端用的client bundle.當服務器接收到了來自客戶端的請求之后,會創(chuàng)建一個渲染器bundleRenderer,這個bundleRenderer會讀取上面生成的server bundle文件,并且執(zhí)行它的代碼, 然后發(fā)送一個生成好的html到瀏覽器,等到客戶端加載了client bundle之后,會和服務端生成的DOM進行Hydration(判斷這個DOM和自己即將生成的DOM是否相同,如果相同就將客戶端的vue實例掛載到這個DOM上)

        實現(xiàn)步驟:

        1、創(chuàng)建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去掛載,現(xiàn)將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參數(shù),context包含當前頁面的url,用getMatchedComponents方法獲取當前url下的組件,返回一個數(shù)組,遍歷這個數(shù)組中的組件,如果組件有asyncData鉤子函數(shù),則傳遞store獲取數(shù)據(jù),最后返回一個promise對象。

        store.state的作用是將服務端獲取到的數(shù)據(jù)掛載到context對象上,后面在server.js文件里會把這些數(shù)據(jù)直接發(fā)送到瀏覽器端與客戶端的vue實例進行數(shù)據(jù)(狀態(tài))同步。

        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數(shù)據(jù)發(fā)生改變,就將客戶端的數(shù)據(jù)替換掉,保證客戶端和服務端的數(shù)據(jù)同步

        Service Worker主要用于攔截并修改訪問和資源請求,細粒度地緩存資源。它運行瀏覽器在后臺,運行環(huán)境與普通頁面腳本不同,所以不能直接參與頁面交互。出于安全考慮,service worker只能運行在HTTPS上,防止被人從中攻擊。

        4、創(chuàng)建服務端渲染器(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: '網(wǎng)絡異常,請刷新重試', 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) => {
         // 網(wǎng)絡異常
         return Promise.reject({message: '網(wǎng)絡異常,請刷新重試', 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這是一個服務端渲的例子

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

        文檔

        vue服務端渲染的實例代碼

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

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲午夜国产片在线观看| 夜夜嘿视频免费看| 国产黄色一级毛片亚洲黄片大全| 亚洲一区二区三区免费观看| 久久久久久国产精品免费免费男同| 全亚洲最新黄色特级网站 | 日韩电影免费在线观看视频| 亚洲精品美女在线观看播放| 久久青草精品38国产免费| 成人午夜亚洲精品无码网站| caoporn成人免费公开| 超清首页国产亚洲丝袜| h片在线观看免费| 中文字幕亚洲电影| 岛国岛国免费V片在线观看| 亚洲熟妇无码八AV在线播放| 成人免费一区二区三区| 亚洲成AV人片在| 99国产精品免费视频观看| 亚洲福利秒拍一区二区| 久久久久国产精品免费免费搜索| avtt天堂网手机版亚洲| 午夜a级成人免费毛片| 日韩国产欧美亚洲v片| 亚洲精品成人片在线观看| 和老外3p爽粗大免费视频| 亚洲色中文字幕无码AV| 日韩精品极品视频在线观看免费| 亚洲第一成年人网站| 成人五级毛片免费播放| 免费人成视频在线观看免费| 亚洲天堂在线视频| 无码专区AAAAAA免费视频| 亚洲综合色区中文字幕| 小小影视日本动漫观看免费| h片在线观看免费| 亚洲日韩乱码中文无码蜜桃臀| 天天操夜夜操免费视频| 国产高潮流白浆喷水免费A片 | 亚洲人成亚洲精品| 免费鲁丝片一级在线观看|