Nuxt.js の context をおさらいする

こんにちは、 ROXX の匠平@show60です。

Nuxt.js の context は色々な機能を内包してくれているためそれとなく使えている感覚でしたが、そもそも中身どうなってんの?と気になったので調べてみることにしました。

そもそも context とは

JavaScript では this という呼び名の context ですが、直訳すると 文脈、脈絡、前後関係 という意味となります。

日常では曖昧な使い方をされてしまうため一層理解に戸惑いますが、 MdN では outside of any function (どの関数の外側にもある) と説明されています。

Global context

In the global execution context (outside of any function), this refers to the global object whether in strict mode or not.

this - JavaScript | MDN

global object とありますが、つまるところグローバルで定義したオブジェクトであり、文脈という言葉を使うとすれば、「すでに定義したという文脈があるんだよー。知っておいてね。」という解釈になるでしょうか。

Nuxt.js の context

Nuxt.js の公式ドキュメントには context で使用可能なキーのリストが載っています。

API: コンテキスト - Nuxt.js

このリストを見ていくと、例えば routefrom といったものは Vue Router Route のインスタンスの型をとっています。 Nuxt.js のアプリ内の適当な箇所で context を呼び出し、 console.log(route) を行ってみると以下のような内容が表示されます。

{
  fullPath: "xxx",
  hash: "",
  params: {},
  path: "xxx",
  query: {}
  ...
}

これは Vue Router のルートオブジェクトプロパティがそのまま含まれているということが分かります。

API Reference | Vue Router

つまり context にはVue Router が定義してあり、 route などの名前で呼び出すことによってどこでも使えますよ、というのが context です。

上記のドキュメント内のキーのリストに app という項目が含まれているのですが、 NuxtAppOptions の型を持っていると説明してあります。

これはどのように使うのでしょうか。

Nuxt.js の context の app

物は試しで、 context の app を呼び出したところで console.log(app) してみましょう。

{
  $axios: ƒ wrap(),
  beforeCreate: ƒ beforeCreate()
  components: {NuxtLoading: {}}
  computed: {isOffline: ƒ}
  context: {isStatic: false, isDev: true, isHMR: true, app: {}, store: Store, …}
  ...
  store: Store {_committing: false, _actions: {}, _actionSubscribers: 
Array(0), _mutations: {}, _wrappedGetters: {}, …}
  watch: {nuxt.err: "errorChanged"}
}

コンポーネント内で使用するオブジェクトなども並んでいます。

この中の context を開いて見てみると、先程の routefrom も存在しており内容も同一となっています。

この context 内の app について、先程のリスト内では すべてのプラグインを含むルートの Vue インスタンス と説明されています。つまり、 app には Vue RouterVue Store など context に含まれるオブジェクトがすべて参照できるというわけです。

context の定義

念のために Nuxt.js の Github 上でコードも確認してみましょう。

GitHub - nuxt/nuxt.js: The Vue.js Framework

Nuxt.js の package/vue-app/template/index.js 、 58 行目あたりに async function createApp とあります。この処理内で const app = { してある箇所があり、どうやらここで app を定義しているようですね。

async function createApp(ssrContext) {
  const router = await createRouter(ssrContext)
  ...
  const app = {
    router,
    <% if (store) { %>store,<%  } %>
    nuxt: {
      defaultTransition,
      transitions: [ defaultTransition ],
      setTransitions(transitions) {...},
      err: null,
      dateErr: null,
      error(err) {...}
    },
    ...App
  }
  ...
  await setContext(app, {
    route,
    next,
    ...
  })

router はここで注入されているようです。setContext で context を定義しているようですのでこちらも見てみましょう。

nuxt.js/utils.js at dev · nuxt/nuxt.js · GitHub

export async function setContext(app, context) {
  // If context not defined, create it
  if (!app.context) {
    app.context = {
      isStatic: process.static,
      isDev: <%= isDev %>,
      isHMR: false,
      app,
      <%= (store ? 'store: app.store,' : '') %>
      payload: context.payload,
      error: context.error,
      base: '<%= router.base %>',
      env: <%= JSON.stringify(env) %><%= isTest ? '// eslint-disable-line' : '' %>
    }
    ...
  }
  ...
  app.context.params = app.context.route.params || {}
  app.context.query = app.context.route.query || {}
}

index.js が起動し、そこで context の中身を諸々注入していることが分かりました。この app がどこでも参照できる状態にあることで各コンポーネントから context 内のオブジェクトを扱うことができるわけですね。

実務では storeerror あたりを使うことが多いでしょうか。ページから store に保管してあるデータを参照したり、 API へのリクエストが失敗したときのエラーハンドリングを行うため自ずと頻度が上がります。

プラグインの注入

新たに context にプラグインを注入したい場合は、上記の Nuxt.js の utils をわざわざ編集するのではなく plugins ディレクトリと nuxt.config.js に記述するだけです。

プラグイン - Nuxt.js

プラグインではないですが、 app にテキストを入れて表示してみたいと思います。

plugins/sample.js

export default ({ app }) => {
  app.sample = 'sample'
}

nuxt.config.js

plugins: [
  '~/plugins/sample'
]

npm installyarn 等をして config.js を再読み込みすると、先程の console.log(app) の結果に sample が追加され、テキストが表示されました。

f:id:show-hei:20190729132411p:plain
plugins/sample の注入

とても簡単に扱えるようにしてくれてますね。

まとめ

外部プラグインは context だけでなく Vue インスタンスに注入しても使用することができます。

どちらもコンポーネント内で呼び出すことができるのですが、どちらの使用を選択するべきかについて、また改めて調べてみたいと思います。

最後に、私たち ROXX では一緒に開発を進めていただける仲間を募集しています。 ご興味お持ちいただいた方はぜひご応募ください!

www.wantedly.com

www.wantedly.com