Skip to content

Latest commit

 

History

History
100 lines (86 loc) · 3.11 KB

head.md

File metadata and controls

100 lines (86 loc) · 3.11 KB

ヘッドの管理

アセットの挿入と同様に、ヘッドの管理も同じ考えに追従しています。つまり、コンポーネントのライフサイクルのレンダリング context に動的にデータを付随させ、そして template 内にデータを挿入できるという考えです。

そうするためには、ネストしたコンポーネントの内側で SSR コンテキストへアクセスできる必要があります。単純に contextcreateApp() へ渡し、これをルートインスタンスの $options で公開することができます。

// app.js
export function createApp (ssrContext) {
  // ...
  const app = new Vue({
    router,
    store,
    // this.$root.$options.ssrContext というように、すべての子コンポーネントは this にアクセスできます
    ssrContext,
    render: h => h(App)
  })
  // ...
}

これと同様のことが provide/inject 経由でも可能ですが、そうすると context が $root 上に存在することになるため、インジェクションを解決するコストを避けたほうが良いでしょう。

インジェクトされた context を用いて、タイトルを管理する単純な mixin を書くことができます:

// 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.$root.$options.ssrContext.title = title
    }
  }
}
const clientTitleMixin = {
  mounted () {
    const title = getTitle(this)
    if (title) {
      document.title = title
    }
  }
}
// VUE_ENV は webpack.DefinePlugin を使って挿入できます
export default process.env.VUE_ENV === 'server'
  ? serverTitleMixin
  : clientTitleMixin

このようにすれば、ルートコンポーネントはドキュメントのタイトルをコントロールするために context を利用することができます。

// 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>
  <head>
    <title>{{ title }}</title>
  </head>
  <body>
    ...
  </body>
</html>

メモ:

  • XSS 攻撃を防ぐために double-mustache(HTML エスケープした挿入)を使うこと。
  • レンダリング中にタイトルをセットするコンポーネントがない場合に備えて、context オブジェクトを作成する際にはデフォルトのタイトルをセットするようにすべきです。

同様のやり方で、この mixin を包括的にヘッドを管理するユーティリティに容易に拡張できます。