dwango.co.jpをReact/TypeScript/Storybookでリメイクしてみた。

# はじめに
この記事は [第2のドワンゴ Advent Calendar 2018](https://qiita.com/advent-calendar/2018/dwango2) の9日目の記事です。

2018年3月にdwangoに内定をもらい、8月からアルバイトとして働かせてもらっている[hiraike32](https://qiita.com/hiraike32)と言います。
2019年4月からは新卒としてお世話になります。

アルバイトの配属はWebフロントエンドで、この4ヶ月間はReact/Reduxをゴリゴリと書いてきました。
今回はアドベントカレンダーの担当をいただいたので、学んできたことを生かしてWebを作ってみます。

# dwango.co.jpをリメイクする
[dwango.co.jp](http://dwango.co.jp/)
![スクリーンショット 2018-12-06 13.04.18.png](https://qiita-image-store.s3.amazonaws.com/0/227196/8aac0724-1796-402b-20d6-b1a09da2d9c0.png)

ちょっと1からWebを作るのは荷が重かったので、dwangoの~~年代を感じる~~伝統のあるHPをReactで作り直してみました。

こんな感じです。
[dwango-remake](https://hiraike32.github.io/dwango-remake/)

[![スクリーンショット 2018-12-09 0.38.19.png](https://qiita-image-store.s3.amazonaws.com/0/227196/09a9f030-1552-5955-3b72-7d30c44cf7bf.png)](https://hiraike32.github.io/dwango-remake/)

まあ、ほとんど同じデザインで作ったので、見た目自体はさほど変わりません。
変わったのは、画像で表現されている部分がcssで書かれていたり、リンクをホバーしたときに表示がわかりやすくなった、くらいですかね。

ただ、設計や開発手法については色々とこだわってみたので、ちょっと紹介していきます。

## 設計について
基本的な設計は、atomicデザインに沿ってコンポーネントを作って、storybookで確認しながら組み立てていきます。

参考：[Atomic Designってデザイナーには難しくない！？という話](https://qiita.com/rhirayamaaan/items/7f990e146ec01f2e7e08)

単一の要素でてきているものはatoms、複数の要素を組み合わせているものはmolecules、意味を持つ集合体をorganismsとしてパーツごとに作りつつ、pagesで1つにまとめています。

実際にstorybookを見てもらったほうが早いかもしれません。
[dwango-remake/storybook](https://hiraike32.github.io/dwango-remake-storybook/)

[<img width="1268" alt="スクリーンショット 2018-12-06 12.40.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/227196/ca2844fb-4fd0-4e25-8d11-e978d34f9cb2.png">](https://hiraike32.github.io/dwango-remake-storybook/)

今回は再利用できるパーツが多くなかったのですが、開発規模が大きくなってくるとコンポーネントごとに取り回しが簡単にできそうです。
文字数の確認もできたりするので、storybookはけっこう気に入っています。

[<img width="513" alt="スクリーンショット 2018-12-06 14.07.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/227196/5a8d4abd-25ff-ecd7-2943-7af2caa6cbaa.png">](https://hiraike32.github.io/dwango-remake-storybook/)

## コードについて

[ソースコード](https://github.com/hiraike32/dwango-remake)

Reactでコードを書いて、TypeScriptで型づけをしています。
cssについては、sassで書いてcss modulesとして扱うことで、全てをローカルクラスとして処理しています。
コードの整形は[Pretiier](https://prettier.io/)にお任せしています。

```
【ファイル構成】
src
 |-components
 ||-atoms
 ||└ HeaderMenu
 ||  |-index.tsx
 ||  |-HeaderMenu.tsx
 ||  |-HeaderMenu.scss
 ||  |-HeaderMenu.stories.tsx
 ||-molecules
 ||-organisms
 ||-pages
 |-img
 |-styles
```

実際のコンポーネントのコードはこんな感じ。

```HeaderMenu.tsx
import React from "react";
// アイコンはfont-awesomeから拝借
import { library } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronCircleRight } from "@fortawesome/free-solid-svg-icons";

// cssはmoduleとして受け取ってクラスを当てていく
import styles from "./HeaderMenu.scss";

library.add(faChevronCircleRight);

// 簡単に型を定義
type Props = {
  text: string;
  href: string;
};

// SFCで簡潔に書く
const HeaderMenu = ({ text, href }: Props) => (
  <li className={styles.item}>
    <FontAwesomeIcon icon="chevron-circle-right" className={styles.icon} />
    <a href={href} className={styles.text} target="_blank">
      {text}
    </a>
  </li>
);

export default HeaderMenu;
```

静的なページなので、ほとんどstateは使わずにSFCで書いています。
中に入れるデータは親コンポーネントから渡してあげることで、汎用性の高い設計に。
Reactを書くまでは、cssのクラスを流用したり、時にはコードをコピペして統一性を保っていたので、今ではReactに心から感謝しています。

最終的に作ったコンポーネントをPageに入れ込んで完成。

```Top.tsx
import React from "react";

import styles from "./Top.scss";
// 片っ端から作ったコンポーネントを読み込む
import {
  Header,
  Navigation,
  LeadingBanner,
  Information,
  ServiceBanner,
  Footer
} from "../../organisms";

const Top = () => (
  // cssのグリッドレイアウトで、それぞれの位置を調整
  <div className={styles.container}>
    <div className={styles.header}>
      <Header />
    </div>
    <div className={styles.navigation}>
      <Navigation />
    </div>
    <div className={styles.leadingBanner}>
      <LeadingBanner />
    </div>
    <div className={styles.information}>
      <Information />
    </div>
    <div className={styles.serviceBanner}>
      <ServiceBanner />
    </div>
    <div className={styles.footer}>
      <Footer />
    </div>
  </div>
);

// このコンポーネントをRoot.tsxで読み込んで完了
export default Top;
```

コンポーネントごとに作るだけなので、作業の見通しを立てやすかったり、修正範囲を特定しやすかったりで、精神の安定も保てました。

## 大変だったこと

### storybookの設定

TypeScriptでstorybookを使うための設定が地味に苦戦しました。
storybookの公式ページ（[TypeScript Config](https://storybook.js.org/configurations/typescript-config/)）に書いてある通りにやればうまくいくはずですが、`awesome-typescript-loader`がうまくいかなかったので、以下のようにやりました。

```sh

// 必要なライブラリをインストール
$ yarn add -D @storybook/react @storybook/addons @storybook/addon-knobs　@storybook/addon-actions　@types/storybook__addon-knobs　@types/storybook__react
```

``` /.storybook/config.js
// storybookファイルを読み込むための設定を記載
import { configure } from "@storybook/react";

const req = require.context("../src", true, /.stories.tsx$/);
function loadStories() {
  req.keys().forEach(filename => req(filename));
}

configure(loadStories, module);
```

``` /.storybook/addons.js
// 設定したいaddonを記載
import "@storybook/addon-actions/register";
import "@storybook/addon-knobs/register";
```

``` /.storybook/webpack.config.js
// プロジェクトのものとは別に、storybook専用のものを作る必要がある
module.exports = config => {
  config.module.rules.push(
    {
      // TypeScriptの設定
      test: /\.tsx$/,
      loader: "ts-loader"
    },
    {
      // scssの設定
      test: /\.s?css$/,
      use: [
        {
          loader: "style-loader",
          options: {
            sourceMap: true
          }
        },
        {
          loader: "css-loader",
          options: {
            root: ".",
            modules: true,
            importLoaders: 1,
            localIdentName: "[path]_[local]_[hash:base64:5]"
          }
        },
        {
          loader: "sass-loader",
          options: { sourceMap: true }
        }
      ]
    },
    {
      // 画像ファイルの設定
      test: /\.(png|jpg|gif)$/,
      use: [
        {
          loader: "file-loader",
          options: {
            name: "[path][name].[ext]"
          }
        }
      ]
    }
  );
  config.resolve.extensions.push(".ts", ".tsx");
  return config;
};
```
これで、src以下の`*.stories.tsx`ファイルはstorybookのファイルとして認識されて、反映されるようになります。

公式ドキュメントを読んで自分のコードに反映するのはけっこう難しいと思うので、参考までに載せておきました。

# 感想
普段は用意されている環境でReactを書いているので、自分で1から環境構築してみるのは良い勉強になりました。
もともとあるデザインをどうやってコンポーネントごとに分解して作っていくかを考えるのも楽しかったです。

初学者のうちは、1からサイトを作っていくのはなかなかにコストが高いですので、既存のサイトを作り直しながら手を動かすというのは、コスパ良く色々なことを学べて良いなと。
そしてTypeScriptの安心感はすごいなと。

フロントエンドの勉強として、自社のサイトをリメイクしてみてはいかがでしょうか？