Vue SRR 잘라먹기 - 소스 코드 구조
Stateful Singletons 피하기
우리가 클라이언트 코드를 쓸 때, 우리는 우리의 코드가 매번 새로운 context로 evalutated될 것이라 기대한다. 그러나 node.js 서버는 긴- 작동의- 프로세스이다. 우리의 코드가 프로세스에서 요구도면, 그것은 메모리에 남아 evaluated 된다. 이는 네가 singleton object를 만들면, 모든 request에 사이에서 이 object가 공유될 것이란 거다.
우리는 새로운 루트 Vue 인스턴스를 각각의 요청에 대해 만들어야 한다. 이건 각각의 브라우저에서 유저가 새로운 인스턴스를 사용하는 것과 비슷하다. 우리가 다중의 request에서 교차해서 인스턴스를 공유하면 cross-request state pollution을 피할 수 없다.
그렇기에, 직접적으로 앱 인스턴스를 만드는 것 대신, 우리는 각 request를 위한 신선한 앱 인스턴스를 만드는 반복적인 작업을 하는 factory function을 노출 시켜야 한다.
// app.js
const Vue = require('vue')
module.exports = function createApp (context) {
return new Vue({
data: {
url: context.url
},
template: `<div>The visited URL is: {{ url }}</div>`
})
}
// server.js
const createApp = require('./app')
server.get('*', (req, res) => {
const context = { url: req.url }
const app = createApp(context)
renderer.renderToString(app, (err, html) => {
// handle error...
res.end(html)
})
})
( 이 제약 조건은 번들 렌더러를 {runInNewContext : true}와 함께 사용할 때 제거 할 수 있지만 각 요청에 대해 새 VM 컨텍스트를 만들어야하기 때문에 상당한 성능 비용이 발생합니다. )
빌딩 스텝 소개하기
아직 우리는 같은 vue app을 클라이언트로 전달할지 이야기 하지 않았다. 이를 위해, 우리는 웹팩을 앱을 번들링하기 위해 사용한다. 사실은, 우리는 서버위의 vue app을 번들링 하는데 웹팩을 사용하길 원한다. 왜냐면:
* 일반적인 Vue 앱은 webpack 및 vue-loader로 제작되며 file-loader를 통해 파일을 가져 오는 것과 css-loader를 통해 CSS를 가져 오는 것과 같은 많은 webpack 관련 기능은 Node.js에서 직접 작동하지 않습니다.
* 최신 Node.js 버전은 ES2015 기능을 완벽하게 지원하지만 이전 버전의 브라우저를 수용하기 위해 클라이언트 측 코드를 필요로합니다. 이것은 다시 빌드 단계를 포함합니다.
따라서 우리는 webpack을 사용하여 클라이언트와 서버 모두에 대해 응용 프로그램을 번들로 제공 할 예정입니다. 서버 번들은 서버에서 필요하며 SSR에 사용되며 클라이언트 번들은 정적 마크 업을 hydration하기 위해 브라우저로 전송됩니다.
이후 섹션에서 설정의 세부 사항을 논의 할 것입니다 - 이제는 빌드 설정을 알아 냈다고 가정하고 webpack을 활성화하여 Vue 앱 코드를 작성할 수 있습니다.
웹팩과 코드 구조
이제는 webpack을 사용하여 서버와 클라이언트 모두에서 응용 프로그램을 처리하므로 대부분의 소스 코드는 모든 웹팩 기반 기능에 액세스 할 수있는 보편적 인 방식으로 작성 될 수 있습니다. 동시에 범용 코드를 작성할 때 명심해야 할 몇 가지 사항이 있습니다.
간단한 프로젝트 구조는 다음과 같습니다:
src
├── components
│ ├── Foo.vue
│ ├── Bar.vue
│ └── Baz.vue
├── App.vue
├── app.js # universal entry
├── entry-client.js # runs in browser only
└── entry-server.js # runs on server only
app.js
app.js는 우리 앱의 universal entry이다. 클라이언트 only app이라면, 우리는 root vue instatnce를 파일에서 바로 만들고 DOM에 바로 마운트 할 것이다. 그러나 SSR의 경우 책임은 클라이언트 only app 파일로 이동됩니다. app.js는 단순히 createApp 함수를 내보냅니다.import Vue from 'vue'
import App from './App.vue'
// export a factory function for creating fresh app, router and store
// instances
export function createApp () {
const app = new Vue({
// the root instance simply renders the App component.
render: h => h(App)
})
return { app }
}
entry-client.js
클라이언트 entry는 간단히 app을 만들고 DOM에 마운트한다.import { createApp } from './app'
// client-specific bootstrapping logic...
const { app } = createApp()
// this assumes App.vue template root element has `id="app"`
app.$mount('#app')
entry-server.js
서버 entry는 각 렌더에 반복적으로 불릴 수 있는 함수를 default export로 사용한다. AT THIS MOMENT, 함수는 앱 인스턴스를 생성하고 출력만 한다. 그러나 나중에 우리는 이 부분에서 서버-사이드 루트(라우트) 매칭과 데이터 pre-fetching logic의 perform할 것 이다.import { createApp } from './app'
export default context => {
const { app } = createApp()
return app
}
댓글
댓글 쓰기