Nuxt.js＋Figma＋Storybookでデザイン重視なチーム開発を！

アプリ開発をチームで行う際、エンジニアとデザイナーのコミュニケーション問題はこれまで大きな課題とされてきました。
最近は色々なサービスが出ているため、チーム内コミュニケーションは改善されつつあるものの未だベストな方法を模索している方は少なくないでしょう。
この記事ではデザイナーとエンジニアが仲良く開発できるようになるためのヒントが共有できればと思っています。

# はじめに
NTTドコモの熊川です。
これは[NTTドコモR&D Advent Calendar 2020](https://qiita.com/advent-calendar/2020/nttdocomo)の19日目の記事です。
普段はIoTクラウドの研究開発やその周辺アプリの開発、データ分析、これらのアセットを用いたビジネス化検討を行っています。
今回はWebアプリ開発で人気のフレームワークのNuxt.js、プロトタイプ開発ツールで最近急浮上中のFigma、そしてUIコンポーネントカタログ化ツールのStorybookを用いた開発方法についてご紹介します。

# なぜNuxt.js、Figma、Storybook？
### [Nuxt.js](https://ja.nuxtjs.org/)
Nuxt.jsとはVue.jsのWeb開発フレームワークであり、
- SPA（Single Page Application）
- SSR（Server Side Rendering）
- SSG（Static Site Generation）
をものすごく簡単に構築できる優れものです。
また、デフォルトでフロントサイドはVue.js、サーバサイドがNode.js（Express）で動作するため、Webアプリを開発する上での環境は予め揃っています。
最近ではデータ分析✕Webの界隈でFlaskやDjangoが使われることもありますが、小・中規模の一般的なWebサイトをさくっと開発したいのであればNuxt.jsを使うことをおすすめします。
この理由はいくつかありますが、Nuxt.jsの設計基盤であるMVVMはRailsのMVCやDjangoのMTVに比べて初心者にも扱いやすいことや、SPAやSSRへの対応が非常に簡単であることが挙げられます。
ちなみに東京都の新型コロナ対策サイトもNuxt.jsが使われているようです。
まだ触ったことがない方はこの際に一度試してみてはいかがでしょうか。

### [Figma](https://www.figma.com/)
ここ最近プロトタイピングツールとしてFigmaの人気が上がっています。
その特徴はなんと言ってもクラウド上で同時編集が可能な点です。
またSketchのファイルをインポートできるので、SketchからFigmaに移行するユーザも増えていきそうですね。

### [Storybook](https://storybook.js.org/)
StorybookはReactやVueベースで扱うことのできるUIコンポーネントカタログ化ツールです。
UIコンポーネントカタログ化ツールは作成したUIのコンポーネントのデザインをチーム全体に共有しやすくすることが可能です。
そのためデザイナーとエンジニアの密な情報共有にはもちろん、フロントエンドエンジニアの育成をしたいときにも有用です。
扱い方ですが、Nuxt.js内でStorybookアドオンを追加して使用することになるのでエンジニアサイドで準備する必要があります。

### 上記3つのアセット組合せ時の全体像
![スクリーンショット 2020-12-03 15.45.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697713/882f2a85-2df7-0bf4-a449-b010812b2d7c.png)


# とある日の現場...
えんじにあ「ほれ、これが仕様書、アプリデザイン頼むで」

でざいなー「突然やな。OKやで」

（数分後）

でざいなー「とりあえずFigmaでカンプ作ったわ」
※ 下記デザインはFigmaのデフォルトで用意してあるサンプルです
![スクリーンショット 2020-12-02 22.50.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697713/3fb0c769-765c-1e8d-1f15-9cbcd8a71368.png)

えんじにあ「爆速やな！ええ感じやん！わいもぼちぼち開発始めるか」

えんじにあ「ちなわいの開発環境はこんな感じや」

```
$ npm -v
6.14.4

$ node -v
v12.16.3
```

### Nuxt.jsアプリ作成

えんじにあ「まずはnuxt.jsでさくっとアプリ作るんや！」

```
$ npx create-nuxt-app nuxt-app
```

えんじにあ「色々聞かれるけどこれでええねん、さくっとしたいからLintは外すで！」　※ Lintはぜひ使いましょう

```
create-nuxt-app v3.4.0
✨  Generating Nuxt.js project in nuxt-app
? Project name: nuxt-app
? Programming language: JavaScript
? Package manager: Npm
? UI framework: (Use arrow keys)
? UI framework: 
? UI framework: Vuetify.js
? Nuxt.js modules: Axios
? Linting tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Testing framework: Jest
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Server (Node.js hosting)
? Development tools: jsconfig.json (Recommended for VS Code if you're not using typescript)
? Continuous integration: None
? Version control system: Git
```

えんじにあ「アプリの原型できた〜とりあえず実行してみよか。Nuxt.jsの準備は一旦完了や！」

```
$ npm run dev
```
![スクリーンショット 2020-12-01 19.29.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697713/05d3fa59-ba16-fcc1-d76b-c812d1a3cae7.png)

### Storybookの準備
えんじにあ「次はでざいなーさんとのコミュニケーション円滑化のためにStorybook導入するで」

えんじにあ「Nuxt.jsでStorybook使うなら[nuxt/storybook](https://storybook.nuxtjs.org/)が楽やで」


```
$ npm install --save-dev @nuxtjs/storybook
```

えんじにあ「これだけでStorybookをもう立ち上げられるのが最高や」

```
$ npx nuxt storybook
```

※ 自動でブラウザの`localhost:3003`が立ち上がります
![スクリーンショット 2020-12-01 21.17.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697713/1df3d7bb-e422-ed26-f1c5-9b7b29d7108d.png)

えんじにあ「とりあえずデフォルトで存在する`Logo.vue`コンポーネントのロゴでもStorybookにのっけてみるか」
※ Nuxt.js初期設定でVuetifyを選択すると`Logo.vue`が自動で生成されるので、ここではそれを活用します

えんじにあ「まずはcomponents配下に`Logo.Stories.js`作るんや」

```js:~/components/Logo.stories.js
import Logo from './Logo'

export default {
  title: 'Logo',
}

export const Normal = () => ({
  components: { Logo },
  template: '<logo />',
})
```

えんじにあ「ほれ、これだけでStorybookにコンポーネントを載せられたで」
![スクリーンショット 2020-12-01 22.12.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697713/cd8d1726-9430-2f6b-7741-f2fbeb1a91cd.png)

でざいなー「ほう！便利そうだけどSorybookの良さはまだわからんなぁ。これを導入してわいにはどんな恩恵があるん？」

えんじにあ「Storybookを導入メリットは、わいの作った**コンポーネントをデザイナー皆さんがすぐチェックできる**ところや」

でざいなー「なるほどなるほど。それならわいの作ったデザインカンプも一緒にこの画面で見られんもんかね？デザインカンプとコンポーネントを見比べたくなる時がくると思うんやけど」

えんじにあ「そう言われると思っとったで！そこでFigma連携や！」

えんじにあ「Figma連携すればStorybook上でFigmaが見れるようになるんや！」


### Figma連携

```
$ npm install --save-dev storybook-addon-designs
```
えんじにあ「このコマンドでパッケージを入れたら、configファイルにアドオン使うよって書いておくんや」


```js:nuxt.config.js
export default {
  storybook: {
    addons: [
      'storybook-addon-designs'
    ],
  },
}
```
えんじにあ「おーい、さっき作ってたFigmaのカンプ、共有できるようにしておくれ」

でざいなー「ほいさ、Figmaのカンプを共有するときはメニューバー右上の`Share`ボタンから`Anyone with the link`を設定するんやったな...」
![スクリーンショット 2020-12-01 22.22.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697713/828ad198-e08a-9399-7e75-722a9ddd3cea.png)
でざいなー「できた！リンクは`https://www.figma.com/file/○○○○`やで」

えんじにあ「OKや！これでStorybookからFigmaで作ったカンプ見れるようにするやで！」

```js:~/components/Logo.stries.js
import Logo from './Logo'

export default {
  title: 'Logo',
}

export const Normal = () => ({
  components: { Logo },
  template: '<logo />',
})

// ここから下を追記

Normal.parameters = {
  design: {
    type: 'figma',
    url: 'https://www.figma.com/file/〇〇〇〇',
  },
}
```

![スクリーンショット 2020-12-01 22.30.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697713/51ee7a78-fab9-4563-9e7c-15ee2cb970d3.png)

えんじにあ「これでOKや！」

でざいなー「やったね！これでStorybook上でFigmaのデザインカンプとコンポーネントを見比べることができるようになったな！」

でざいなー「（これで今後は開発中もコンポーネントをしっかりチェックできるな）」

（数分後）

でざいなー「...今回開発のアプリ、ボタンは今回4種類にするつもりや。それぞれ使い回すからコンポーネント化するべきやろね」

でざいなー「色はそれぞれ`#E53935`と`#3949AB`、`#F9A825`、`#AED581`で前3つはテキストを白く、後ろ2つは丸角のボタンにするわ」

でざいなー「そんでそんで、実際開発したボタンに適当なテキスト入れたらどんな感じになるか見てみたいんや。他にも（以下略）」

でざいなー「...Storybookってそういうのも簡単にチェックできるん？」

えんじにあ「...できるっ！！」

### Storybookコントローラ設定
えんじにあ「実はこういうときにStorybookの本当の良さがでるんよ！Storybookのコントローラ機能を作っていくで」

---

#### Storybookコントローラ機能
Storybook上にプルダウンバーやテキストボックス、トグルボタン等を表示させ、それらによりコンポーネントへパラメータを渡すことで条件に応じたコンポーネントデザインを確認することができる機能

---

えんじにあ「まずはButtonのコンポーネント作るか」

えんじにあ「propsでパラメータの受け取り口を先に作っておくんや。こうすることで後々`色・丸角・挿入テキスト`をコントロールできるようなるわけや」

えんじにあ「ちなみに今回の筆者さんはtemplate内の`<v-app>`を付けずに『Vuetifyが効かない！』と長い時間困っていたそうな」

えんじにあ「みんなは気をつけるんやで！」

```js:~/components/Button.vue
<template>
// Vuetifyなら<v-app>で囲うのを忘れないように
  <v-app>
    <v-btn :color="color" :rounded='round'>
      <slot>{{ text }}</slot>
    </v-btn>
  </v-app>
</template>

<script>
export default {
  props: {
    color: {
      type: String,
      default: 'default',
    },
    round: {
      control: Boolean,
    },
    text: {
      control: String,
    }
  },
}
</script>
```
えんじにあ「次に`Button.stories.js`を作って`Button.vue`コンポーネントをStorybookに載っける設定やね」

えんじにあ「Logoの時と違うのは、各設定値をコントロールできるようにしていることや」

```js:~/components/Button.stories.js
export default {
    title: 'Button',
    argTypes: {
        // ここで色選択プルダウン追加
        color: {
          control: {
            type: 'select',
            options: ['red darken-1 white--text',
                      'indigo darken-1 white--text',
                      'yellow darken-3 white--text',
                      'light-green lighten-2'],
          },
          defaultValue: 'primary'
        },
        // ここで丸角の有無を選択するトグルボタン追加
        round: { control: 'boolean' },
        // ここでテキストボックスの追加
        text: {
            control: 'text',
            defaultValue: 'Awesome Button'
        }
    }
}

export const Button = (arg, { argTypes }) => ({
    props: Object.keys(argTypes),
    template: '<Button v-bind="$props" />'
})
```

えんじにあ「こうするとほれ、画面下にコントロールできるところが出てくるんや」
![スクリーンショット 2020-12-04 0.39.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697713/a7981112-db3b-8536-2465-b1a05318be69.png)

えんじにあ「これで好きにパラメータ変えて試してええで。色も変えられるし丸角ボタンも確認できる、テキストを自由に入れてみることだって可能や」

でざいなー「ええやんええやん！」

でざいなー「ええんやけど、、今の状況、、えんじにあさんのローカルでしかStorybook実行できんのは不便すぎません？」

えんじにあ「せやな...。最後にサーバにデプロイしてどっからでも見れるようにしておくか...。」

### Netlifyへデプロイ

---
#### Netlifyとは
静的ホスティングサービスプラットフォームであり、Githubのリポジトリと連携させることが可能である。
Githubへpushすれば自動的にデプロイしてくれる機能もあり、サーバサイドのことを考えず簡単に扱うことができる。

---

えんじにあ「手順としてはgithubにこれまでのコードをアップした後、Netlifyで作った`Site`（プロジェクトにようなもの）に連携させるだけや」

えんじにあ「今回NetlifyのSite設定で気をつけるべきはBuildの設定やね。下のように`Build command`と`Publish directory`を設定するんや」
![スクリーンショット 2020-12-07 11.23.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697713/2b0a1088-344b-807d-12e6-31af5f2a84a4.png)

えんじにあ「設定が完了したらあとはデプロイを待つだけ...」

えんじにあ「でけた！」

![スクリーンショット 2020-12-07 12.36.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697713/ba2bde13-524e-36c3-cbbb-207fb2900d28.png)

えんじにあ「これからは[ここ](https://storybook-ac2020.netlify.app/?path=/story/button--button)（サンプル）でデザイン情報を密に共有していけるで！」
※ 今回作ったサンプルを上記URLで公開しています

でざいなー「ほんと素敵っ！これで仲良く開発できそうやねっ！」

**〜めでたしめでたし〜**

# さいごに
今の御時世、次々に新しいツールが出ては廃れ出ては廃れを繰り返しています。
そのため最適なツールの組み合わせを探すことはもはや、永遠の課題なのかもしれません。
しかし今選択しうる最高の開発環境を、皆さんでこれからも追い続けていきましょう。