diff --git a/en/SUMMARY.md b/en/SUMMARY.md
index b538ae93..c809a5ff 100644
--- a/en/SUMMARY.md
+++ b/en/SUMMARY.md
@@ -6,7 +6,7 @@
- [Hydratation côté client](hydration.md)
- [Introduction au moteur de dépaquetage](bundle-renderer.md)
- [Configuration de pré-compilation](build-config.md)
-- [Gestion des CSS (En)](css.md)
+- [Gestion des CSS](css.md)
- [Gestion des entêtes (En)](head.md)
- [Mise en cache (En)](caching.md)
- [Envoi par flux (En)](streaming.md)
diff --git a/en/css.md b/en/css.md
index f909efcb..9e2c6f3b 100644
--- a/en/css.md
+++ b/en/css.md
@@ -1,35 +1,35 @@
-# Gestion des CSS (En)
*Cette page est en cours de traduction française. Revenez une autre fois pour lire une traduction achevée ou [participez à la traduction française ici](https://github.com/vuejs-fr/vue-ssr-docs).*
+# Gestion des CSS
-The recommended way to manage CSS is to simply use ``태그가 반환됩니다. 자세한 내용은 [CSS 관리](./css.md)를 참조하십시오.
+
+`clientManifest`가 제공되면 반환되는 문자열에는 webpack에서 생성한 CSS파일 (예: `extract-text-webpack-plugin` 또는 `file-loader`로 추가된)에 대한 `` 태그가 포함됩니다.
+
+- `context.renderState(options?: Object)`
+
+이 메소드는 `context.state`를 직렬화하고 state(상태)를 `window.__INITIAL_STATE__`로 포함하는 인라인 스크립트를 리턴합니다.
+
+컨텍스트 state(상태) 키와 윈도우 state(상태) 키는 옵션 객체를 전달하여 사용자 정의할 수 있습니다.
+
+```js
+ context.renderState({
+ contextKey: 'myCustomState',
+ windowKey: '__MY_STATE__'
+ })
+ // ->
+```
+
+- `context.renderScripts()`
+ - `clientManifest`를 필요로 합니다.
+
+이 메소드는 클라이언트 애플리케이션이 시작하는데 필요한 ``태그를 반환합니다. 애플리케이션 코드에서 비동기 코드 분할을 사용하는 경우 이 메소드는 포함할 올바른 비동기 청크를 지능적으로 유추합니다.
+
+- `context.renderResourceHints()`
+ - `clientManifest`를 필요로 합니다.
+
+이 메소드는 현재 렌더링된 페이지에 필요한 `` 리소스 힌트를 반환합니다. 기본적으로 다음과 같습니다.
+
+- 페이지에 필요한 JavaScript 및 CSS 파일을 미리 로드
+- 나중에 필요할 수 있는 비동기 JavaScript 청크 프리페치
+
+미리 로드된 파일은 [`shouldPreload`](./api.md#shouldpreload)옵션을 사용해 추가로 사용자 정의할 수 있습니다.
+
+- `context.getPreloadFiles()`
+ - `clientManifest`를 필요로 합니다.
+
+이 메소드는 문자열을 반환하지 않는 대신 미리 로드해야 할 에셋을 나타내는 파일 객체의 배열을 반환합니다. 이는 프로그래밍 방식으로 HTTP/2 서버 푸시를 하는데 사용할 수 있습니다.
+
+`createBundleRenderer`에 전달된 `template`은 `context`를 사용하여 보간되므로 템플릿안에서 이러한 메소드를 사용할 수 있습니다.(`inject: false` 옵션과 함께)
+
+```html
+
+
+
+ {{{ renderResourceHints() }}}
+ {{{ renderStyles() }}}
+
+
+
+ {{{ renderState() }}}
+ {{{ renderScripts() }}}
+
+
+```
+
+`template`을 사용하지 않으면 문자열을 직접 연결할 수 있습니다.
diff --git a/ko/bundle-renderer.md b/ko/bundle-renderer.md
new file mode 100644
index 00000000..2c764a60
--- /dev/null
+++ b/ko/bundle-renderer.md
@@ -0,0 +1,47 @@
+# 번들 렌더러 소개
+
+## 기본적인 SSR의 문제
+
+지금까지 번들된 서버측 코드는 `require`를 직접 사용한다고 가정했습니다.
+
+```js
+const createApp = require('/path/to/built-server-bundle.js')
+```
+
+이는 간단하지만 앱에서 소스코드를 수정할때마다 서버를 중지했다가 다시 시작해야합니다. 이렇게 되면 개발하는 과정에서 생산성이 매우 떨어집니다. 또한 Node.js는 소스맵을 지원하지 않습니다.
+
+## BundleRenderer 시작하기
+
+`vue-server-renderer`는 이 문제를 해결하기 위해 `createBundleRenderer` API를 제공합니다. 사용자 정의 webpack 플러그인을 사용하면 서버측 번들이 번들 렌더러에 전달할 수 있는 특수한 JSON파일로 생성됩니다. 번들 렌더러가 생성되면 사용법은 일반적인 렌더러와 동일하지만 다음과 같은 이점이 있습니다.
+
+- 빌트인 소스 맵 지원 (webpack 설정에서 `devtool: 'source-map'` 사용)
+- 개발 및 배포 중 핫 리로드 (업데이트된 번들을 읽고 렌더러 인스턴스를 다시 만들기만 하면 됩니다.)
+- `*.vue`파일 사용시 CSS 주입 : 렌더링 중 사용하는 컴포넌트에 필요한 CSS를 자동으로 인라인으로 삽입합니다. [CSS](./css.md)섹션에서 자세히 다룹니다.
+- [clientManifest](./api.md#clientmanifest)를 이용해 에셋 주입 : 최적의 프리로드 및 프리페치 디렉티브와 초기 렌더링에 필요한 코드 분할 덩어리를 자동으로 유추합니다.
+
+---
+
+다음 섹션에서 번들 렌더러에 필요한 빌드 아티팩트를 생성하도록 webpack을 구성하는 방법을 설명합니다. 하지만 여기서는 이미 필요한 부분이 있다고 가정하고 번들렌더러를 만드는 방법을 설명합니다.
+
+```js
+const { createBundleRenderer } = require('vue-server-renderer')
+const renderer = createBundleRenderer(serverBundle, {
+ runInNewContext: false, // recommended
+ template, // (optional) page template
+ clientManifest // (optional) client build manifest
+})
+// inside a server handler...
+server.get('*', (req, res) => {
+ const context = { url: req.url }
+ // No need to pass an app here because it is auto-created by
+ // executing the bundle. Now our server is decoupled from our Vue app!
+ renderer.renderToString(context, (err, html) => {
+ // handle error...
+ res.end(html)
+ })
+})
+```
+
+`renderToString`이 번들 렌더러에서 호출되면 번들에 의해 내보내진 함수를 자동으로 실행하여 (속성을 `context`로 전달인자로 전달) 앱 인스턴스를 만든 다음 렌더링합니다.
+
+`runInNewContext` 옵션을 `false` 또는 `'once'`로 설정하는 것이 좋습니다. 자세한 내용은 [API 레퍼런스](./api.md#runinnewcontext)를 참조하십시오
diff --git a/ko/caching.md b/ko/caching.md
new file mode 100644
index 00000000..110bf82d
--- /dev/null
+++ b/ko/caching.md
@@ -0,0 +1,83 @@
+# 캐싱
+
+Vue의 SSR은 매우 빠르지만 컴포넌트 인스턴스 및 가상 DOM 노드를 만드는 비용때문에 순수 문자열 기반 템플릿 성능과 같지는 않습니다. SSR성능이 중요한 경우 캐싱 전략을 현명하게 활용하면 응답 시간을 크게 향상시키고 서버 부하를 줄일 수 있습니다.
+
+## 페이지 레벨 캐싱
+
+서버에서 렌더링된 앱은 외부 데이터를 사용하므로 본질적인 내용은 동적이기 때문에 오랫동안 캐시할 수 없습니다. 그러나 컨텐츠가 사용자별로 다르면(즉, 동일한 URL의 경우 항상 모든 사용자에게 동일한 컨텐츠가 렌더링 됨) [micro-caching](https://www.nginx.com/blog/benefits-of-microcaching-nginx/)이라고 부르는 방식을 활용하여 높은 트래픽을 처리하는 앱의 성능을 대폭 향상시킬 수 있습니다.
+
+이것은 일반적으로 Nginx 레이어에서 이루어지지만 Node.js에서도 구현할 수 있습니다.
+
+```js
+const microCache = LRU({
+ max: 100,
+ maxAge: 1000 // Important: entries expires after 1 second.
+})
+const isCacheable = req => {
+ // implement logic to check if the request is user-specific.
+ // only non-user-specific pages are cache-able
+}
+server.get('*', (req, res) => {
+ const cacheable = isCacheable(req)
+ if (cacheable) {
+ const hit = microCache.get(req.url)
+ if (hit) {
+ return res.end(hit)
+ }
+ }
+ renderer.renderToString((err, html) => {
+ res.end(html)
+ if (cacheable) {
+ microCache.set(req.url, html)
+ }
+ })
+})
+```
+
+컨텐츠는 단 1초 동안만 캐시되므로 사용자는 이전 컨텐츠를 볼 수 없습니다. 그러나 이는 서버가 각 캐시된 페이지에 대해 초당 최대 하나의 렌더링만 수행하면 된다는 것만 의미합니다.
+
+## 컴포넌트 레벨 캐싱
+
+`vue-server-renderer`에는 컴포넌트 수준의 [cache implementation](./api.md#cache)이 있습니다. 이를 사용하려면 렌더러를 만들 때 캐시 구현을 제공해야 합니다. 일반적인 사용법은 [lru-cache](https://github.com/isaacs/node-lru-cache)로 전달됩니다.
+
+```js
+const LRU = require('lru-cache')
+const renderer = createRenderer({
+ cache: LRU({
+ max: 10000,
+ maxAge: ...
+ })
+})
+```
+
+그런 다음 `serverCacheKey`함수를 구현하여 컴포넌트를 캐시할 수 있습니다.
+
+```js
+export default {
+ name: 'item', // required
+ props: ['item'],
+ serverCacheKey: props => props.item.id,
+ render (h) {
+ return h('div', this.item.id)
+ }
+}
+```
+
+캐시 가능한 컴포넌트는 **반드시 고유한 "name" 옵션을 가져야합니다.** 고유한 캐시 키는 컴포넌트마다 가지고 있으므로 동일한 키를 반환하는 두 컴포넌트를 걱정할 필요가 없습니다.
+
+`serverCacheKey`로부터 받은 키에는 렌더링 결과를 나타내는 충분한 정보가 포함될 필요가 있습니다. 위 결과는 렌더링 결과가 `props.item.id`에 의해 결정되는 경우 좋은 구현입니다. 그러나 동일한 ID를 가진 항목이 시간이 지남에 따라 변경되거나 렌더링된 결과가 다른 속성에 의존하는 경우 다른 변수를 고려하여 `getCacheKey`구현을 수정해야합니다.
+
+상수를 반환하면 컴포넌트가 항상 캐시되며 이는 순수한 정적 컴포넌트에 유용합니다.
+
+### 컴포넌트 캐싱을 사용하는 경우
+
+렌더링하는 동안 렌더러가 컴포넌트의 캐시에 도달하면 전체 하위 트리에 대해 캐시된 결과를 직접 다시 사용합니다. 다음과 같은 경우에 컴포넌트를 **캐시하지 않아야 합니다.**
+
+- 전역 상태에 의존하는 하위 컴포넌트를 가지고 있는 경우
+- 렌더링 `context`에 사이드이펙트를 발생시키는 하위 컴포넌트가 있는 경우
+
+따라서 성능상의 병목을 해결하려면 컴포넌트 캐싱을 신중하게 적용해야합니다. 대부분의 경우 단일 인스턴스 컴포넌트를 캐시하지 않아도 됩니다. 캐싱에 적합한 가장 일반적인 유형의 컴포넌트는 거대한 `v-for` 리스트에서 반복되는 컴포넌트입니다. 이러한 컴포넌트는 대개 데이터베이스 모음의 객체에 의해 구동되기 때문에 고유한 ID와 최종 업데이트된 타임스탬프를 사용하여 캐시키를 생성하는 간단한 캐싱 전략을 사용할 수 있습니다,
+
+```js
+serverCacheKey: props => props.item.id + '::' + props.item.last_updated
+```
diff --git a/ko/head.md b/ko/head.md
new file mode 100644
index 00000000..dfc0ef6e
--- /dev/null
+++ b/ko/head.md
@@ -0,0 +1,83 @@
+# Head 태그 관리
+
+에셋 인젝션과 마찬가지로 Head 관리도 동일한 아이디어를 사용합니다. 즉 컴포넌트의 라이프사이클에서 렌더링 `context`에 데이터를 동적으로 추가한 다음 `template`에서 해당 데이터를 보간할 수 있습니다.
+
+> 2.3.2 버전 이후에서 컴포넌트의 SSR 컨텍스트에 `this.$ssrContext`로 직접 액세스할 수 있습니다. 이전 버전에서는 `createApp()`에 SSR 컨텍스트를 전달하고 이를 루트 인스턴스의 `$options`에 노출시켜 수동으로 SSR 컨텍스트를 주입해야합니다. 그러면 자식 컴포넌트가 `this.$root.$options.ssrContext`를 통해 액세스할 수 있습니다.
+
+타이틀 관리를 위해 간단한 mixin을 작성합니다.
+
+```js
+// title-mixin.js
+function getTitle (vm) {
+ // components can simply provide a `title` option
+ // which can be either a string or a function
+ const { title } = vm.$options
+ if (title) {
+ return typeof title === 'function'
+ ? title.call(vm)
+ : title
+ }
+}
+const serverTitleMixin = {
+ created () {
+ const title = getTitle(this)
+ if (title) {
+ this.$ssrContext.title = title
+ }
+ }
+}
+const clientTitleMixin = {
+ mounted () {
+ const title = getTitle(this)
+ if (title) {
+ document.title = title
+ }
+ }
+}
+// VUE_ENV can be injected with webpack.DefinePlugin
+export default process.env.VUE_ENV === 'server'
+ ? serverTitleMixin
+ : clientTitleMixin
+```
+
+이제 라우트 컴포넌트를 사용하여 document의 title을 제어할 수 있습니다.
+
+```js
+// Item.vue
+export default {
+ mixins: [titleMixin],
+ title () {
+ return this.item.title
+ }
+ asyncData ({ store, route }) {
+ return store.dispatch('fetchItem', route.params.id)
+ },
+ computed: {
+ item () {
+ return this.$store.state.items[this.$route.params.id]
+ }
+ }
+}
+```
+
+번들 렌더러에 전달된 `template` 내부입니다
+
+```html
+
+
+
{{ title }}
+
+
+ ...
+
+
+```
+
+**참고**
+
+- 두개의 mustache(HTML 이스케이프된 보간)를 사용해 XSS 공격을 피해야 합니다.
+- 렌더링하는 동안 컴포넌트에 title을 설정하지 않은 경우 `context` 객체를 만들 때 기본 title을 제공해야합니다.
+
+---
+
+동일한 방법을 사용하면 이 mixin을 일반 Head 관리 유틸리티로 만들 수 있습니다.
diff --git a/ko/hydration.md b/ko/hydration.md
new file mode 100644
index 00000000..21d9021e
--- /dev/null
+++ b/ko/hydration.md
@@ -0,0 +1,31 @@
+# 클라이언트 사이드 하이드레이션
+
+`entry-client.js`에서 단순히 아래 라인을 통해 애플리케이션을 마운트 합니다.
+
+```js
+// this assumes App.vue template root element has `id="app"`
+app.$mount('#app')
+```
+
+서버가 이미 마크업을 렌더링 했으므로, 이를 버리고 모든 DOM 요소를 다시 만들 필요는 없습니다. 대신 정적 마크 업을 "수화 (hydrate)"하여 상호작용하게 만들고 싶습니다.
+
+서버에서 렌더링 한 결과를 검사하면 앱의 루트 엘리먼트에 특수 속성을 확인할 수 있습니다.
+
+```js
+
+```
+
+특수 속성 `data-server-rendered`은 클라이언트 측 Vue가 마크업이 서버에 의해 렌더링 되고 하이드레이션 모드로 마운트되어야한다고 알립니다.
+개발 모드에서 Vue는 클라이언트 측에서 만들어진 가상 DOM 트리가 서버에서 렌더링된 DOM구조와 일치함을 나타냅니다. 일치하지 않는 부분이 있으면 하이드레이션을 중단하고 기존 DOM을 삭제한 후 처음부터 렌더링 합니다. **배포 모드에서는 최대 성능을 위해 assert를 하지 않습니다.**
+
+### 하이드레이션 주의사항
+
+SSR + 클라이언트 하이드레이션을 사용할 때 주의해야하는 것들 중 하나는 브라우저에서 변경할 수 있는 특수한 HTML 구조입니다. 예를 들어 Vue 템플릿을 다음과 같이 작성한 경우입니다.
+
+```html
+
+
hi
+
+```
+
+브라우저는 자동으로 ``를 `
` 안에 자동으로 주입합니다. 하지만 Vue가 생성한 가상 DOM에 ``을 주입하면 불일치가 발생합니다. 그러므로 동일하도록 만들기 위해 템플릿에 유효한 HTML을 작성해야합니다.
diff --git a/ko/routing.md b/ko/routing.md
new file mode 100644
index 00000000..b6d62a2d
--- /dev/null
+++ b/ko/routing.md
@@ -0,0 +1,136 @@
+# 라우팅과 코드 분할
+
+## `vue-router`를 이용한 라우팅
+
+서버 코드가 임의의 URL을 처리하는 `*` 핸들러를 사용하는 것을 알 수 있습니다. 이렇게 하면 방문한 URL을 Vue앱에 전달하고 클라이언트와 서버 모두에 동일한 라우팅 구성을 재사용할 수 있습니다.
+
+이를 위해서는 공식 `vue-router`를 사용하는 것이 좋습니다. 먼저 라우터를 생성하는 파일을 만듭니다. `createApp`과 비슷하게 각 요청에 대해 새로운 라우터 인스턴스가 필요하므로 파일에서 `createRouter` 함수를 export 합니다.
+
+```js
+// router.js
+import Vue from 'vue'
+import Router from 'vue-router'
+Vue.use(Router)
+export function createRouter () {
+ return new Router({
+ mode: 'history',
+ routes: [
+ // ...
+ ]
+ })
+}
+```
+
+그리고 `app.js`파일을 수정합니다
+
+```js
+// app.js
+import Vue from 'vue'
+import App from './App.vue'
+import { createRouter } from './router'
+export function createApp () {
+ // create router instance
+ const router = createRouter()
+ const app = new Vue({
+ // inject router into root Vue instance
+ router,
+ render: h => h(App)
+ })
+ // return both the app and the router
+ return { app, router }
+}
+```
+
+이제 `entry-server.js`에 서버측 라우팅 로직을 작성합니다.
+
+```js
+// entry-server.js
+import { createApp } from './app'
+export default context => {
+ // since there could potentially be asynchronous route hooks or components,
+ // we will be returning a Promise so that the server can wait until
+ // everything is ready before rendering.
+ return new Promise((resolve, reject) => {
+ const { app, router } = createApp()
+ // set server-side router's location
+ router.push(context.url)
+ // wait until router has resolved possible async components and hooks
+ router.onReady(() => {
+ const matchedComponents = router.getMatchedComponents()
+ // no matched routes, reject with 404
+ if (!matchedComponents.length) {
+ return reject({ code: 404 })
+ }
+ // the Promise should resolve to the app instance so it can be rendered
+ resolve(app)
+ }, reject)
+ })
+}
+```
+
+이미 서버 번들이 빌드되었다고 가정하면 (빌드 설정은 이 단계에서는 무시합니다.) 서버 코드는 다음과 같습니다.
+
+```js
+// server.js
+const createApp = require('/path/to/built-server-bundle.js')
+server.get('*', (req, res) => {
+ const context = { url: req.url }
+ createApp(context).then(app => {
+ renderer.renderToString(app, (err, html) => {
+ if (err) {
+ if (err.code === 404) {
+ res.status(404).end('Page not found')
+ } else {
+ res.status(500).end('Internal Server Error')
+ }
+ } else {
+ res.end(html)
+ }
+ })
+ })
+})
+```
+
+## 코드 분할
+
+코드 분할 또는 지연된 로딩은 초기 렌더링을 위해 브라우저에서 다운로드할 에셋의 양을 줄이는데 도움이 되며 큰 규모의 번들을 가지는 앱의 경우 TTI (time-to-interactive)를 크게 향상시킬 수 있습니다. 핵심은 초기 화면에서 "필요한 것을 로드하는 것"입니다.
+
+Vue는 비동기 컴포넌트를 일급 클래스 컨셉으로 제공하며 [webpack 2에서 지원하는 코드 분할](https://webpack.js.org/guides/code-splitting-async/)과 결합할 수 있습니다.
+
+```js
+// changing this...
+import Foo from './Foo.vue'
+// to this:
+const Foo = () => import('./Foo.vue')
+```
+
+이는 순수 클라이언트 측 Vue 앱을 만드는 어떠한 시나리오에서도 작동합니다. 그러나 SSR을 사용할 때 몇가지 제한 사항이 있습니다. 먼저 렌더링을 시작하기 전에 서버에서 모든 비동기 컴포넌트를 처리해야합니다. 그렇지 않으면 마크업에 미처 불러오지 못한 부분들이 생깁니다. 클라이언트에서 처리하기 전에 이를 마무리해야합니다. 그렇지 않으면 클라이언트와의 컨텐츠가 일치하지 않는 에러가 발생할 수 있습니다.
+
+이로 인해 앱의 임의의 위치에서 비동기 컴포넌트를 사용하는 것이 약간 까다로울 수 있습니다.(향후 이 기능이 향상됩니다.) 그러나 **라우트 레벨에서 수행하는 경우**(라우트 컴포넌트에서 비동기 컴포넌트 사용) 원할히 작동합니다. 라우트를 해석할 때 (vue-router와 일치하는 비동기 컴포넌트를 자동으로 분석할 때) 해야할 일은 서버와 클라이언트 모두에서 `router.onReady`를 사용해야 합니다.
+
+```js
+// entry-client.js
+import { createApp } from './app'
+const { app, router } = createApp()
+router.onReady(() => {
+ app.$mount('#app')
+})
+```
+
+비동기 라우트 컴포넌트를 사용하는 예입니다.
+
+```js
+// router.js
+import Vue from 'vue'
+import Router from 'vue-router'
+Vue.use(Router)
+export function createRouter () {
+ return new Router({
+ mode: 'history',
+ routes: [
+ { path: '/', component: () => import('./components/Home.vue') },
+ { path: '/item/:id', component: () => import('./components/Item.vue') }
+ ]
+ })
+}
+```
diff --git a/ko/streaming.md b/ko/streaming.md
new file mode 100644
index 00000000..f4369782
--- /dev/null
+++ b/ko/streaming.md
@@ -0,0 +1,30 @@
+# 스트리밍
+
+`vue-server-renderer`는 기본 렌더러와 번들 렌더러 모두 스트림 렌더링을 지원합니다. `renderToString`대신 `renderToStream` 사용하면 됩니다.
+
+```js
+const stream = renderer.renderToStream(context)
+```
+
+반환 값은 [Node.js stream](https://nodejs.org/api/stream.html)입니다.
+
+```js
+let html = ''
+stream.on('data', data => {
+ html += data.toString()
+})
+stream.on('end', () => {
+ console.log(html) // render complete
+})
+stream.on('error', err => {
+ // handle error...
+})
+```
+
+## 스트리밍 주의사항
+
+스트림 렌더링 모드에서 렌더러는 가상 DOM 트리를 탐색할 때 가능한 한 빠르게 데이터를 출력합니다. 즉, "첫번째 청크"를 가져와 클라이언트로 더 빠르게 보냅니다.
+
+그러나 첫번째 청크가 만들어질 때 하위 컴포넌트는 아직 인스턴스화 되지 않고 라이프사이클 훅도 호출되지 않은 상태입니다. 그러므로 자식 컴포넌트가 라이프사이클 훅의 렌더링 컨텍스트에 데이터가 필요한 경우 스트림을 시작할 때 데이터를 사용할 수 없습니다. 애플리케이션 마크업 전에 많은 컨텍스트 정보(Head 정보 또는 인라인으로 추가되는 CSS)가 표시되어야 하므로 컨텍스트 데이터를 사용하기 전에 스트림이 완료될 때까지 기다려야 합니다.
+
+따라서 컴포넌트 수명주기 훅의 컨텍스트 데이터에 의존하는 경우 스트리밍 모드를 **사용하지 않는 것이 좋습니다.**
diff --git a/ko/structure.md b/ko/structure.md
new file mode 100644
index 00000000..04a51d9d
--- /dev/null
+++ b/ko/structure.md
@@ -0,0 +1,114 @@
+# 소스 코드 구조
+
+## 상태를 보존하는 싱글톤을 피하세요
+
+클라이언트 전용 코드를 작성할 때 코드가 항상 새로운 컨텍스트에서 구동된다는 것에 익숙할 것입니다. 그러나 Node.js 서버는 오랫동안 실행되는 프로세스입니다. 프로세스에 코드가 필요한 경우 한번 계산되어 메모리에 남아있게 됩니다. 즉, 싱글톤 객체를 만들면 들어오는 모든 요청간에 공유될 수 있습니다.
+
+기본 예제에서 보듯이, 각 요청에 따라 **새로운 루트 Vue인스턴스를 생성**합니다. 이는 각 사용자가 브라우저에서 앱의 새로운 인스턴스를 사용하는 것과 유사합니다. 서로 다른 요청에서 공유된 인스턴스를 사용하면 상호 요청 상태 오염을 일으킬 수 있습니다.
+
+따라서 앱 인스턴스를 직접 생성하는 대신 반복적으로 실행할 수 있는 팩토리 함수를 노출하고 각 요청에 따라 새로운 앱 인스턴스를 만들어야 합니다.
+
+```js
+// app.js
+const Vue = require('vue')
+module.exports = function createApp (context) {
+ return new Vue({
+ data: {
+ url: context.url
+ },
+ template: `
방문한 URL은 : {{ url }}
`
+ })
+}
+```
+
+이제 서버 측 코드는 아래와 같이 변경합니다.
+
+```js
+// 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)
+ })
+})
+```
+
+동일한 규칙이 라우터, store(저장소) 및 이벤트 버스 인스턴스에도 적용됩니다. 모듈에서 직접 export하고 앱에서 import 하는 대신 `createApp`에 새 인스턴스를 만들고 루트 Vue인스턴스에서 이를 주입해야합니다.
+
+> 이러한 제약 조건은 번들 렌더러를 `{ runInNewContext: true }`와 함께 사용할 때 제거할 수 있지만 각 요청에 대해 새로운 vm context를 만들어야하기 때문에 성능에 상당한 비용이 발생합니다.
+
+## 빌드 순서 소개
+
+지금까지 클라이언트에 동일한 Vue 앱을 전달하는 방법을 다루지 않았습니다. 이를 위해 webpack을 사용해 Vue 앱을 번들링해야합니다. 사실, webpack을 사용해 서버에 Vue 앱을 번들링해야합니다. 이유는 아래와 같습니다.
+
+- 일반적으로 Vue 앱은 webpack과 `vue-loader`로 구성되어 있으며 `file-loader`를 통해 파일을 가져오는 것, `css-loader`를 통해 CSS를 가져오는 것과 같은 많은 webpack 관련 기능은 Node.js에서 직접 작동하지 않습니다.
+- Node.js 최신 버전은 ES2015를 완벽히 지원하지만 이전 버전의 브라우저에서 작동할 수 있도록 만들기 위해 클라이언트 측 코드를 변환해야합니다. 이 때문에 빌드 단계가 필요합니다.
+
+따라서 webpack을 사용하여 클라이언트와 서버 모두를 번들로 제공할 것입니다. 서버 번들은 서버에서 필요하며 SSR에 사용되며, 클라이언트 번들은 정적 마크업을 위해 브라우저로 전송됩니다.
+
+
+
+이후 섹션에서 설정의 세부 사항을 논의 할 것입니다. 이제 빌드 설정을 이해한다고 가정하고 webpack을 사용하여 Vue 앱 코드를 작성할 수 있습니다.
+
+## Webpack을 이용한 코드 구조
+
+webpack을 이용해 서버와 클라이언트 모두에서 애플리케이션을 처리하므로 대부분의 소스 코드를 모든 webpack 기반으로 작성할 수 있습니다. 범용적인 코드를 작성할 때 주의해야할 [몇가지 사항](./universal.md)들이 있습니다.
+
+간단한 프로젝트는 아래와 같을 것 입니다.
+
+```bash
+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`는 앱의 범용적인 시작 지점입니다. 클라이언트 전용 애플리케이션에서는 이 파일에 루트 Vue 인스턴스를 만들고 DOM에 직접 마운트합니다. 그러나 SSR의 경우에는 책임이 클라이언트 전용 엔트리 파일로 옮겨갑니다.
+
+```js
+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`:
+
+클라이언트 엔트리는 단순히 앱을 생성하고 DOM에 마운트하는 역할만 합니다.
+
+```js
+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`:
+
+서버 항목은 각 렌더링마다 반복적으로 호출할 수있는 함수인 export default를 사용합니다. 현재 이 인스턴스는 앱 인스턴스를 생성하고 반환하는 것 이외에는 하지 않지만 나중에 서버 측 라우트 매칭 및 데이터 프리-페칭 로직(pre-fetching logic)을 다룹니다.
+
+```js
+import { createApp } from './app'
+export default context => {
+ const { app } = createApp()
+ return app
+}
+```
diff --git a/ko/universal.md b/ko/universal.md
new file mode 100644
index 00000000..97a68b25
--- /dev/null
+++ b/ko/universal.md
@@ -0,0 +1,32 @@
+# 유니버설 코드 작성하기
+
+자세히 살펴보기 전에 잠시 "유니버설" 코드, 즉 서버와 클라이언트 모두에서 실행가능한 코드를 작성하는 경우의 제약사항에 관하여 살펴봅니다. 유즈케이스 및 플랫폼 API의 차이에 따라 서로 다른 환경에서 실행할 때 코드의 동작이 정확히 동일할 수는 없습니다. 여기서는 꼭 알아야할 중요한 것들을 다룹니다.
+
+## 서버에서의 데이터 반응성
+
+클라이언트만 존재하는 앱에서는 모든 사용자가 브라우저에서 앱의 새로운 인스턴스를 사용하게됩니다. 서버 측 렌더링의 경우에도 동일한 요청이 필요합니다. 각 요청에는 교차 요청 상태(Cross Request State) 오염이 없도록 격리 된 새 앱 인스턴스가 있어야합니다.
+
+실제 렌더링 프로세스는 결정적이어야하므로 서버에서 데이터를 "미리 가져(pre-fetching)"옵니다. 렌더링을 시작할 때 애플리케이션 상태는 이미 완료되어 있어야 합니다. 즉, 서버에서 데이터 반응성이 필요하지 않으므로 기본적으로 비활성화 되어 있습니다. 데이터 반응성을 비활성화하면 데이터를 반응형 객체로 변환하는 성능 비용을 피할 수 있습니다.
+
+## 컴포넌트 라이프사이클 훅
+
+동적인 갱신이 없으므로 모든 라이프사이클 훅 중 `beforeCreate` 및 `created`만 SSR 중에 호출됩니다. 즉, `beforeMount` 또는 `mounted`와 같은 다른 라이프사이클 훅 안의 모든 코드는 클라이언트에서만 실행됩니다.
+
+또 다른 주의 사항은 `beforeCreate`와 `created`에서 전역적인 사이드이펙트를 만드는 코드 (예: `setInterval`로 타이머 설정) 클라이언트 측 코드에서만 타이머를 설정한 다음 `beforeDestroy` 또는 `destroyed`에서 제거할 수 있습니다. 그러나 SSR 중 destroy 훅이 호출되지 않기 때문에 타이머가 영원히 계속 살아있습니다. 이를 피하려면 사이드이펙트를 발생하는 코드를 `beforeMount` 뚀는`mounted`로 옮겨야 합니다.
+
+## 플랫폼에 의존하는 API에 접근하기
+
+유니버설 코드는 특정 플랫폼의 API 접근을 가정할 수 없으므로 코드가 `window` 또는 `document`와 같은 브라우저 전용 전역 변수를 직접 사용하면 Node.js에서 실행할 때 오류가 발생합니다. 이 반대의 경우도 마찬가지 입니다.
+
+서버와 클라이언트간 공유되지만 다른 플랫폼 API를 사용하는 경우 플랫폼 별 구현을 범용적인 API로 래핑하거나 이를 위해 라이브러리를 사용하는 것이 좋습니다. 예를 들어 [axios](https://github.com/mzabriskie/axios)는 서버와 클라이언트 모두에서 동일한 API를 제공하는 HTTP 클라이언트 입니다.
+
+브라우저 전용 API의 경우 일반적인 방법은 클라이언트 전용 라이프사이클 훅에 게으른 접근(Lazyily Access)을 하는 것 입니다.
+
+써드파티 라이브러리가 범용적인 사용을 고려하지 않고 작성된 경우 서버에서 렌더링 된 애플리케이션과 통합하는 것이 까다로울 수 있습니다. 일부 전역 변수를 가짜로 만들어(mocking) *작동시킬 수 있으나* 이는 편법이며 다른 라이브러리의 환경설정 감지 코드를 건드릴 수 있습니다.
+
+## 사용자 정의 디렉티브
+
+대부분의 사용자 정의 디렉티브는 DOM을 직접 조작하므로 SSR중 오류가 발생합니다. 이 문제를 해결하는 방법은 두가지 입니다.
+
+1. 추상화 메커니즘으로 컴포넌트를 사용하고 가상 DOM 수준에서 작업해야합니다. (예 : 렌더링 기능 사용)
+2. 컴포넌트로 쉽게 바꿀 수 없는 사용자 정의 디렉티브가 있는 경우 서버 렌더러를 만들 때 [`directives`](./api.md#directives)옵션을 사용해 "서버용 버전"을 제공할 수 있습니다.
diff --git a/zh/api.md b/zh/api.md
new file mode 100644
index 00000000..af05ee57
--- /dev/null
+++ b/zh/api.md
@@ -0,0 +1,233 @@
+# API 参考
+
+## `createRenderer([options])`
+
+使用(可选的)[选项](#renderer-options)创建一个 [`Renderer`](#class-renderer) 实例。
+
+```js
+const { createRenderer } = require('vue-server-renderer')
+const renderer = createRenderer({ ... })
+```
+
+## `createBundleRenderer(bundle[, options])`
+
+使用 server bundle 和(可选的)[选项](#renderer-options)创建一个 [`BundleRenderer`](#class-bundlerenderer) 实例。
+
+```js
+const { createBundleRenderer } = require('vue-server-renderer')
+const renderer = createBundleRenderer(serverBundle, { ... })
+```
+
+`serverBundle` 参数可以是以下之一:
+
+- 绝对路径,指向一个已经构建好的 bundle 文件(`.js` 或 `.json`)。必须以 `/` 开头才会被识别为文件路径。
+- 由 webpack + `vue-server-renderer/server-plugin` 生成的 bundle 对象。
+- JavaScript 代码字符串(不推荐)。
+
+更多细节请查看 [Server Bundle 指引](./bundle-renderer.md) 和 [构建配置](./build-config.md)。
+
+## `Class: Renderer`
+
+- #### `renderer.renderToString(vm[, context], callback)`
+
+ 将 Vue 实例渲染为字符串。上下文对象 (context object) 可选。回调函数是典型的 Node.js 风格回调,其中第一个参数是可能抛出的错误,第二个参数是渲染完毕的字符串。
+
+- #### `renderer.renderToStream(vm[, context])`
+
+ 将 Vue 实例渲染为一个 Node.js 流 (stream)。上下文对象 (context object) 可选。更多细节请查看[流式渲染](./streaming.md)。
+
+## `Class: BundleRenderer`
+
+- #### `bundleRenderer.renderToString([context, ]callback)`
+
+将 bundle 渲染为字符串。上下文对象 (context object) 可选。回调是一个典型的 Node.js 风格回调,其中第一个参数是可能抛出的错误,第二个参数是渲染完毕的字符串。
+
+- #### `bundleRenderer.renderToStream([context])`
+
+ 将 bundle 渲染为一个 Node.js 流 (stream). 上下文对象 (context object) 可选。更多细节请查看[流式渲染](./streaming.md)。
+
+## Renderer 选项
+
+- #### `template`
+
+ 为整个页面的 HTML 提供一个模板。此模板应包含注释 ``,作为渲染应用内容的占位符。
+
+模板还支持使用渲染上下文 (render context) 进行基本插值:
+
+- 使用双花括号 (double-mustache) 进行 HTML 转义插值 (HTML-escaped interpolation);
+- 使用三花括号 (triple-mustache) 进行 HTML 不转义插值 (non-HTML-escaped interpolation)。
+
+当在渲染上下文 (render context) 上存在一些特定属性时,模板会自动注入对应的内容:
+
+- `context.head`:(字符串)将会被作为 HTML 注入到页面的头部 (head) 里。
+- `context.styles`:(字符串)内联 CSS,将以 style 标签的形式注入到页面头部。注意,如过你使用了 `vue-loader` + `vue-style-loader` 来处理组件 CSS,此属性会在构建过程中被自动生成。
+- `context.state`:(对象)初始 Vuex store 状态,将以 `window.__INITIAL_STATE__` 的形式内联到页面。内联的 JSON 将使用 [serialize-javascript](https://github.com/yahoo/serialize-javascript) 自动清理,以防止 XSS 攻击。
+
+ 此外,当提供 `clientManifest` 时,模板会自动注入以下内容:
+
+- 渲染当前页面所需的最优客户端 JavaScript 和 CSS 资源(支持自动推导异步代码分割所需的文件)
+- 为要渲染页面提供最佳的 `` 资源提示(resource hints)。
+
+ 你也可以通过将 `inject: false` 传递给 renderer,来禁用所有自动注入。
+
+具体查看:
+
+- [使用一个页面模板](./basic.md#using-a-page-template)
+- [手动资源注入(Manual Asset Injection)](./build-config.md#manual-asset-injection)
+ - #### `clientManifest`
+- 2.3.0+
+
+ 通过此选项提供一个由 `vue-server-renderer/client-plugin` 生成的客户端构建 manifest 对象 (client build manifest object)。此对象包含了 webpack 整个构建过程的信息,从而可以让 bundle renderer 自动推导需要在 HTML 模板中注入的内容。更多详细信息,请查看[生成 clientManifest](./build-config.md#generating-clientmanifest)。
+
+-
+#### `inject`
+
+ - 2.3.0+
+
+ 控制使用 `template` 时是否执行自动注入。默认是 `true`。
+
+ 参考:[手动资源注入(Manual Asset Injection)](./build-config.md#manual-asset-injection)。
+
+-
+#### `shouldPreload`
+
+ - 2.3.0+
+
+ 一个函数,用来控制什么文件应该生成 `` 资源预加载提示 (resource hints)。
+
+默认情况下,只有 JavaScript 和 CSS 文件会被预加载,因为它们是启动应用时所必需的。
+
+ 对于其他类型的资源(如图像或字体),预加载过多可能会浪费带宽,甚至损害性能,因此预加载什么资源具体依赖于场景。你可以使用 `shouldPreload` 选项精确控制预加载资源:
+
+```js
+ const renderer = createBundleRenderer(bundle, {
+ template,
+ clientManifest,
+ shouldPreload: (file, type) => {
+ // 基于文件扩展名的类型推断。
+ // https://fetch.spec.whatwg.org/#concept-request-destination
+ if (type === 'script' || type === 'style') {
+ return true
+ }
+ if (type === 'font') {
+ // only preload woff2 fonts
+ return /\.woff2$/.test(file)
+ }
+ if (type === 'image') {
+ // only preload important images
+ return file === 'hero.jpg'
+ }
+ }
+ })
+```
+
+-
+#### `runInNewContext`
+
+ - 2.3.0+
+ - 只用于 `createBundleRenderer`
+ - Expects: `boolean | 'once'` (`'once'` 仅在 2.3.1+ 中支持)
+
+ 默认情况下,对于每次渲染,bundle renderer 将创建一个新的 V8 上下文并重新执行整个 bundle。这具有一些好处 - 例如,应用程序代码与服务器进程隔离,我们无需担心文档中提到的[状态单例问题](./structure.md#avoid-stateful-singletons)。然而,这种模式有一些相当大的性能开销,因为重新创建上下文并执行整个 bundle 还是相当昂贵的,特别是当应用很大的时候。
+
+ 出于向后兼容的考虑,此选项默认为 `true`,但建议你尽可能使用 `runInNewContext: false` 或 `runInNewContext: 'once'`。
+
+> 在 2.3.0 中,此选项有一个 bug,其中 `runInNewContext: false` 仍然使用独立的全局上下文(separate global context)执行 bundle。以下信息假定版本为 2.3.1+。
+
+ 使用 `runInNewContext: false`,bundle 代码将与服务器进程在同一个 `global` 上下文中运行,所以请留意在应用程序代码中尽量避免修改 `global`。
+
+ 使用 `runInNewContext: 'once'` (2.3.1+),bundle 将在独立的`全局`上下文 (separate global context) 取值,然而只在启动时取值一次。这提供了一定程度的应用程序代码隔离,因为它能够防止 bundle 中的代码意外污染服务器进程的 `global` 对象。注意事项如下:
+
+1. 在此模式下,修改 `global`(例如,polyfill)的依赖模块必须被打包进 bundle,不能被外部化 (externalize);
+2. 从 bundle 执行返回的值将使用不同的全局构造函数,例如,在服务器进程中捕获到 bundle 内部抛出的错误,使用的是 bundle 上下文中的 Error 构造函数,所以它不会是服务器进程中 `Error` 的一个实例。
+
+ 参考:[源码结构](./structure.md)
+
+-
+#### `basedir`
+
+ - 2.2.0+
+ - 只用于 `createBundleRenderer`
+
+ 显式地声明 server bundle 的运行目录。运行时将会以此目录为基准来解析 `node_modules` 中的依赖模块。只有在所生成的 bundle 文件与外部的 NPM 依赖模块放置在不同位置,或者 `vue-server-renderer` 是通过 npm link 链接到当前项目中时,才需要配置此选项。
+
+- #### `cache`
+
+ 提供[组件缓存](./caching.md#component-level-caching)具体实现。缓存对象必须实现以下接口(使用 Flow 语法表示):
+
+```js
+ type RenderCache = {
+ get: (key: string, cb?: Function) => string | void;
+ set: (key: string, val: string) => void;
+ has?: (key: string, cb?: Function) => boolean | void;
+ };
+```
+
+ 典型用法是传入 [lru-cache](https://github.com/isaacs/node-lru-cache):
+
+```js
+ const LRU = require('lru-cache')
+ const renderer = createRenderer({
+ cache: LRU({
+ max: 10000
+ })
+ })
+```
+
+ 请注意,缓存对象应至少要实现 `get` 和 `set`。此外,如果 `get` 和 `has` 接收第二个参数作为回调,那 get 和 has 也可以是可选的异步函数。这允许缓存使用异步 API,例如,一个 redis 客户端:
+
+```js
+ const renderer = createRenderer({
+ cache: {
+ get: (key, cb) => {
+ redisClient.get(key, (err, res) => {
+ // 处理任何错误
+ cb(res)
+ })
+ },
+ set: (key, val) => {
+ redisClient.set(key, val)
+ }
+ }
+ })
+```
+
+- #### `directives`
+
+对于自定义指令,允许提供服务器端实现:
+
+```js
+ const renderer = createRenderer({
+ directives: {
+ example (vnode, directiveMeta) {
+ // 基于指令绑定元数据(metadata)转换 vnode
+ }
+ }
+ })
+```
+
+ 例如,请查看 [`v-show` 的服务器端实现](https://github.com/vuejs/vue/blob/dev/src/platforms/web/server/directives/show.js)。
+
+## webpack 插件
+
+webpack 插件作为独立文件提供,并且应当直接 require:
+
+```js
+const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
+const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')
+```
+
+生成的默认文件是:
+
+- `vue-ssr-server-bundle.json` 用于服务器端插件;
+- `vue-ssr-client-manifest.json` 用于客户端插件。
+
+创建插件实例时可以自定义文件名:
+
+```js
+const plugin = new VueSSRServerPlugin({
+ filename: 'my-server-bundle.json'
+})
+```
+
+更多信息请查看[构建配置](./build-config.md)。