Nuxt.js × Composition API セットアップ

## Prologue

Nuxt.jsとCompositionAPIを使うことが多いのですが、結局最低限必要な設定とは？と毎回なるので、設定周りをまとめました。  
基本はDocument通りになるため、自身で設定する場合には都度公式を確認することをお勧めします。

- [Nuxt.js](https://ja.nuxtjs.org/)
- [CompositionAPI](https://composition-api.vuejs.org/)

Nuxt.js の初期設定周りは別記事にまとめているので、そちらも参考にしてください。
[Nuxt.js × TypeScript セットアップ](https://qiita.com/miiiii/items/7d79f4f02303e8e486e3)


## 環境

- macOS: v10.15.5
- node.js: v12.18.0
- terminal: iTerm
- エディタ: VS Code
- パッケージマネージャ: `yarn`
- Composition API: v1.0.0-beta.1

## Nuxt.js セットアップ

今回は `nuxt-sample` をプロジェクト名として作成します。

``` 
yarn create nuxt-app nuxt-sample

create-nuxt-app v3.1.0
✨  Generating Nuxt.js project in nuxt-sample
? Project name: nuxt-sample
? Programming language: TypeScript
? Package manager: Yarn
? UI framework: Buefy
? Nuxt.js modules: Axios
? Linting tools: Prettier
? Testing framework: Jest
? Rendering mode: Single Page App
? Deployment target: Server (Node.js hosting)
? Development tools: (Press <space> to select, <a> to toggle all, <i> to invert
```

インストールが終わったら作成したプロジェクトに移動して、起動し、成功しているか念のため確認します。

```
cd nuxt-sample
yarn dev
```

## Composition API のインストール

1. Composition API をインストールします。

```
yarn add @vue/composition-api
```

2\. Vue の Component で使えるように `plugins` に追加します。

plugins/CompositionApi.ts

``` JS
import Vue from 'vue';
import VueCompositionApi from '@vue/composition-api';

Vue.use(VueCompositionApi)
```

3\. `nuxt.config.ts` に作成した plugins を追記します。

``` JS
  plugins: [
    '~/plugins/CompositionApi'
  ],
```

以上で最低限のセットアップは完了しました。

## `create nuxt-app` で作成したデフォルトのプロジェクトを書き換えてみる

今回 `Buefy` を UI Framework で組みこんだので、そのプロジェクトを Composition API で書き換えてみます。ファイル数も少ないので、お時間ある方は是非試してみてください。

- pages/index.vue

Before:

``` JS
<script>
import Card from '~/components/Card'

export default {
  name: 'HomePage',

  components: {
    Card
  }
}
</script>
```

After: Composition API

``` JS
<script lang="ts">
import { defineComponent } from "@vue/composition-api";
import Card from '@/components/Card.vue'

export default defineComponent({
   name: 'HomePage',
   components: {
     Card
   }
})
</script>
```

- components/Card.vue

Before:

``` JS
<script>
export default {
  props: {
    title: {
      type: String,
      required: true
    },
    icon: {
      type: String,
      required: true
    }
  }
}
</script>
```

After: Composition API

``` JS
<script lang="ts">
import { defineComponent } from "@vue/composition-api";

export default defineComponent({
  props: {
    title: {
      type: String,
      required: true
    },
    icon: {
      type: String,
      required: true
    }
  }
})
</script>
```

- layouts/default.vue

Before:

``` JS
<script>
export default {
  data () {
    return {
      items: [
        {
          title: 'Home',
          icon: 'home',
          to: { name: 'index' }
        },
        {
          title: 'Inspire',
          icon: 'lightbulb',
          to: { name: 'inspire' }
        }
      ]
    }
  }
}
</script>
```

After: Composition API
template 部分も一部書き換えたので、こちらは全コード載せます。

``` JS
<template>
  <div>
    <nav class="navbar header has-shadow is-primary" role="navigation" aria-label="main navigation">
      <div class="navbar-brand">
        <a class="navbar-item" href="/">
          <img src="~assets/buefy.png" alt="Buefy" height="28" />
        </a>

        <div class="navbar-burger">
          <span />
          <span />
          <span />
        </div>
      </div>
    </nav>

    <section class="main-content columns">
      <aside class="column is-2 section">
        <p class="menu-label is-hidden-touch">General</p>
        <ul class="menu-list">
          <li v-for="(item, key) of state.items" :key="key">
            <nuxt-link :to="item.to" exact-active-class="is-active">
              <b-icon :icon="item.icon" />
              {{ item.title }}
            </nuxt-link>
          </li>
        </ul>
      </aside>

      <div class="container column is-10">
        <nuxt />
      </div>
    </section>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive } from '@vue/composition-api'

interface Menu {
  title: string
  icon: string
  to: {
    name: string
  }
}

export default defineComponent({
  name: 'default',
  setup() {
    const items: Menu[] = [
      {
        title: 'Home',
        icon: 'home',
        to: {
          name: 'index',
        },
      },
      {
        title: 'Inspire',
        icon: 'lightbulb',
        to: {
          name: 'inspire',
        },
      },
    ]

    const state = reactive({
      items: items,
    })

    return {
      state,
    }
  },
})
</script>
```

以上です。

## Epilogue

今回は props, data を同時に記載する箇所がなかったのであまり実感がないかもしれませんが、 Composition API は、props と data, method 等 を分けて書けるので、よりわかりやすく、かなり可読性が高まったな、と感じています。
また、v0.4.x くらいから使い始めていましたが、この記事の直前に `v1.0.0-beta.1` も出ていて、 どんどん使いやすくなっている印象を受けています。

これから Vue のプロジェクトに TypeScript を導入するのであれば、ぜひ検討してみてください^^