vue 서버 렌 더 링 인 스 턴 스 코드

1.서버 렌 더 링 이 무엇 입 니까?
클 라 이언 트 요청 서버,서버 는 요청 주소 에 따라 일치 하 는 구성 요 소 를 얻 고 일치 하 는 구성 요 소 를 호출 하여 Promise(공식 은 asyncData 방법)로 돌아 가 필요 한 데 이 터 를 가 져 옵 니 다.마지막 으로 윈도 우즈 를 통 해서.initial_state=data 는 웹 페이지 에 기록 하고 마지막 으로 서버 에서 보 여 준 웹 페이지 를 되 돌려 줍 니 다.다음 클 라 이언 트 는 새로운 store 상태 로 원래 의 store 상 태 를 교체 하여 클 라 이언 트 와 서버 의 데이터 가 동기 화 되도록 합 니 다.서버 에 렌 더 링 되 지 않 은 구성 요 소 를 만 나 비동기 로 데 이 터 를 가 져 오 라 고 요청 합 니 다.
서버 렌 더 링 환경 구축

이것 은 vue 홈 페이지 의 서버 렌 더 링 설명도 입 니 다.ssr 는 두 개의 입구 파일 이 있 는데 그것 이 바로 클 라 이언 트 의 입 후 파일 과 서버 의 입 구 파일 입 니 다.웹 팩 은 두 개의 입구 파일 을 통 해 각각 서버 에 사용 할 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}
}
서버 렌 더 링 을 해 야 하기 때문에 엘 로 마 운 트 할 필요 가 없습니다.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 는 접근 과 자원 요청 을 차단 하고 수정 하 며 자원 을 세밀 하 게 캐 시 하 는 데 사 용 됩 니 다.브 라 우 저 를 배경 에서 실행 합 니 다.실행 환경 은 일반 페이지 스 크 립 트 와 다 르 기 때문에 페이지 상호작용 에 직접 참여 할 수 없습니다.서 비 스 워 커 는 보안 차원 에서 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;

6.그 해 에 만난 구덩이 들
문제 1、window is not defined
정 답 1:브 라 우 저 대상 을 사용 하 는 곳 에 if(type:of window!=='undefined'){},일부 플러그 인 에서 도 브 라 우 저 대상 을 사 용 했 습 니 다.사용 하 는 곳 에 도 조건 판단 을 추가 합 니 다.

if (typeofwindow !== 'undefined') {
Vue.use(VueAnalytics, {
id: process.env.UA_TRACKING_ID,
router
})
}
문제 2:hello.all.js(3 자 로그 인 플러그 인)와 같은 Vue 시리즈 가 아 닌 플러그 인 을 사용 합 니 다.필요 한 곳 에서 만 참조 할 수 있 습 니 다.잘못된 것 은 문제 1 과 같 습 니 다.
정 답 2:이 럴 때 import 로 가 져 올 수 없습니다.require 를 사용 해 야 합 니 다.
let hello

if (typeof window !== 'undefined') {
hello = require('hello')
}
질문 3:boottstrap 참조
정 답 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"
})
일곱,예
4.567915.이것 은 서버 렌 더 링 의 예 이다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기