vue-server-rendererでSSRしてみる

2020/01/05 21:46#js#ts

vue-server-renderer使ってSSRしてみます。

Webpack

クライアントサイドとサーバーサイドそれぞれWebpack設定します。
module.rulesほとんど共通なので共通ファイルにします。

// webpack.common.js
module.exports = {
    module: {
        rules: [
            // ルール
        ]
    }
}

クライアントサイド

// webpack.client.js
const common = require('./webpack.common')
module.exports = {
    ...common,
    // いつもの設定
}

サーバーサイド

modenode
output.libraryTargetcommonjs2

// webpack.server.js
const common = require('./webpack.common')
module.exports = {
    ...common,
    mode: 'node',
    output: {
        // いつもの設定
        libraryTarget: 'commonjs2'
    },
    // いつもの設定
}

SSRしてみる

ここからVueです。
サーバーサイドレンダリングガイド一通り把握しておきます。

ファクトリ関数

Vueインスタンスのファクトリ関数を作成します。
ルーターもファクトリ関数で都度作成します。

// app.ts
import Vue from 'vue'
import App from './components/app'
import { createRouter } from './router'

export const createApp = (props?: any) => new Vue({
    router: createRouter(),
    render: h => h(App, {
        props
    })
})

クライアントサイドでのインスタンス作成

URLからパスを取得してルーターに渡します。

import { createApp } from './app'

const path = location.pathname
const vm = createApp(<any>window[<any>'__INITIAL_STATE__'])
vm.$router.push(path)
vm.$router.onReady(() => {
    vm.$mount('#app')
})

レンダリングする

Vueインスタンスを受け取ってHTMLを出力する関数を作成します。

import Vue from 'vue'
import { join } from 'path'
import { readFileSync } from 'fs'
import { createRenderer } from 'vue-server-renderer'

interface Route {
    title: string
    path: string
    props?: any
}

const renderer = createRenderer({
    template: readFileSync(join(__dirname, '../src/app.html')).toString()
})

interface VM2HTML {
    (vm: Vue, route: Route): Promise<string>
}

export const vm2html: VM2HTML = (vm, route) => {
    return new Promise(resolve => {
        vm.$router.push(route.path)
        vm.$router.onReady(() => {
            renderer.renderToString(vm, {
                title: route.title ,
                state: route.props || {}
            }).then(html => {
                resolve(html)
            })
        })
    })
}