Reactの開発準備をして、styled-componentsでスタイルをあてていく

## 概要
今回はReactの開発環境を作成し、それに対してstyled-componentsでスタイルをあてていきます
開発環境はMacのlocal環境, 利用しているIDEはAtomです

今回のゴールは下記の2点です

- Reactの開発準備 (react-create-appなどのボイラープレートは利用しない)
- styled-componentでスタイルをあてる (静的なものと、動的に変化するもの)

## 開発準備

### プロジェクトを作成する
```bash
$ mkdir -p ~/src/styled-components-test
$ cd ~/src/styled-components-test
$ npm init -y
```

### webpack, babelのinstall
webpackとは? babelとは? ということについては下記の記事を参照してください

- [webpack 4 入門](https://qiita.com/soarflat/items/28bf799f7e0335b68186)
- [【５分でなんとなく理解！】Babel入門](https://qiita.com/Shagamii/items/a87181c22ea777ee2acc)
- [Reactを「webpack + babel-loader」でビルドする方法](https://mae.chab.in/archives/2891)

```bash
$ npm install --save-dev webpack webpack-cli babel-core babel-loader babel-preset-react babel-preset-env
```

### webpackの設定ファイルを作成
```javascript:webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        // 拡張子が.js, .jsxのものをビルド対象とする
        test: /\.(js|jsx)$/,
        // babel-loaderを利用してビルドする
        use: {
          loader: 'babel-loader',
        },
        // /node_modules/配下のファイルは除外する
        exclude: /node_modules/,
      },
      {
        // 拡張子が.gif, .png, .jpeg, .jpg, .svgのものをビルド対象とする
        test: /\.(gif|png|jpe?g|svg)$/,
        // url-loaderを利用してビルドする
        loader: 'url-loader',
      }
    ]
  },
  // importで含めたいファイルの拡張子を指定
  resolve: {
    extensions: ['.js', '.jsx'],
  },
  // ビルドしたファイルを出力する場所を指定
  output: {
    path: __dirname +'/dist',
    filename: 'main.js'
  },
};
```

`./package.json`の"scripts"に`"devel": ~`を追加

```json:./package.json
"scripts": {
    "devel": "webpack --mode development",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

```

### babelの設定ファイルを作成

```config:.babelrc
{
  "presets": [
    "env",
    "react"
  ]
}
```

### reactのインストール
React.jsをインストールする

```bash
$ npm install --save react react-dom
```

## hello worldの表示
上記手順で開発準備ができたので、ここから実際にサンプルコードを書いていきます

### 必要ファイルの作成
下記の3ファイルを作成していく

```bash
$ mkdir dist
$ touch ./dist/index.html
$ touch ./src/index.js
$ touch ./src/App.jsx
```
```html:./dist/index.html
<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale = 1.0, maximum-scale=1.0, user-scalable=no" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
</head>

<body>
  <div id="app"></div>
  <script src="./main.js"></script>
</body>

</html>
```
```js:./src/index.js
import React from 'react';
import ReactDOM from 'react-dom';

import App from './App';

ReactDOM.render(
  <App />,
  document.getElementById('app')
);
```
```jsx:./src/App.jsx
import React, { Component } from 'react';

class App extends Component {
  render() {
    return (
      <div>
        hello world!
      </div>
    );
  }
}

export default App;
```

### ビルドしてhello worldを表示する
```bash
$ npm run devel
$ open ./dist/index.html
```
これでブラウザ上でhello worldの文字が表示されました

## styled-componentsを利用してスタイルをあてていく
次に上記に対してstyled-componentsを利用してCSSをあてていきます

- [styled-components](https://github.com/styled-components/styled-components)

### styled-componentsのinstall
```bash
$ npm install --save styled-components
```

### スタイルをあてて文字を赤くする
`App.jsx`を以下のように変更

```jsx:./src/App.jsx
import React, { Component } from 'react';
import styled from 'styled-components';

class App extends Component {
  render() {
    return (
      <HelloWorld>
        hello world!
      </HelloWorld>
    );
  }
}

const HelloWorld = styled.div`
  color: red;
`;

export default App;
```

これで`index.html`を開くと、"hello world!"の文字が赤くなっています

### 動的にCSSの値を変更する
次に、ブラウザサイズに応じて文字の色を変えるようにしてみます

```jsx:./src/App.jsx
import React, { Component } from 'react';
import styled from 'styled-components';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = { windowWidth: window.innerWidth };
    this.updateWindowWidth = this.updateWindowWidth.bind(this);
  }

  componentWillMount() {
    window.addEventListener('resize', this.updateWindowWidth);
  }

  updateWindowWidth() {
    const windowWidth = window.innerWidth;
    this.setState({ windowWidth });
  }

  render() {
    return (
      <HelloWorld width={this.state.windowWidth}>
        hello world!
      </HelloWorld>
    );
  }
}

const getColor = (width) => width >= 500 ? 'red' : 'blue';

const HelloWorld = styled.div`
  color: ${({ width }) => getColor(width)};
`;

export default App;
```

これでブラウザの幅が500以上の時には文字色が赤、500未満の時には青色になりました

以上で今回やりたい以下の2点ができました:clap::clap:

- Reactの開発準備 (react-create-appなどのボイラープレートは利用しない)
- styled-componentでスタイルをあてる (静的なものと、動的に変化するもの)

## Appendix その1: webpack-dev-serverで実行する
今のままだと、変更を加えて手動でビルドコマンドを実行して...と手間がかかります
なので自動で変更を取り込んでくれるよう、webpack-dev-serverで実行するようにします

```bash
$ npm install --save-dev webpack-dev-server
```

`webpacp.config.js`のファイルに以下のように`devServer`という設定を追加します

```js:webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        use: {
          loader: 'babel-loader',
        },
        exclude: /node_modules/,
      },
      {
        test: /\.(gif|png|jpe?g|svg)$/,
        loader: 'url-loader',
      }
    ]
  },
  resolve: {
    extensions: ['.js', '.jsx'],
  },
  output: {
    path: __dirname +'/dist',
    filename: 'main.js'
  },
  devServer: {
    contentBase: 'dist',
    port: 3000,
  },
};
```

`package.json`のscriptsに以下のように`start`を追加します

```json:package.json
"scripts": {
    "start": "webpack-dev-server --mode development --open",
    "devel": "webpack --mode development",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
```

以上で準備は完了です
次のコマンドを実行するとビルドが実行され、上記hello worldがブラウザで開きます

```bash
$ npm run start
```

また`App.jsx`へと変更を加えると、それが自動でブラウザへと反映されます
なので変更の度に手動でビルドをし直す必要がなくて非常に楽です

## Appendix その2: eslintでコードを綺麗に

eslintはコードのスタイルをチェックしてくれます

これを入れると記述ミスがなくなり、コードが綺麗になってバグも減りますし、コードの可読性が上がります
また複数人で開発する時なども一定のルールが自動で適用されると楽ですよね、ということで入れていきましょう

### Atomに対してeslintのプラグインをインストールする
以下を参考に設定を入れていきます

- [AtomにESLint導入した](https://qiita.com/HisakoIsaka/items/40966a0c78846f4053c9)
- [ESLintをAtomに導入し、Reactの構文にも対応したAirbnbのJSスタイルガイドを使う](https://mae.chab.in/archives/2874#post2874-2)

### プロジェクトに対してeslintの設定をする
eslintをプロジェクトに対してインストール

```bash
$ npm install --save-dev eslint
```

対話形式で必要な設定を行っていく
今回はAirbnbのスタイルを利用していくので、以下のように設定

```bash
$ ./node_modules/eslint/bin/eslint.js --init
? How would you like to configure ESLint? Use a popular style guide
? Which style guide do you want to follow? Airbnb (https://github.com/airbnb/javascript)
? Do you use React? Yes
? What format do you want your config file to be in? JavaScript
Checking peerDependencies of eslint-config-airbnb@latest
The config that you've selected requires the following dependencies:

eslint-config-airbnb@latest eslint@^4.19.1 || ^5.3.0 eslint-plugin-import@^2.14.0 eslint-plugin-jsx-a11y@^6.1.1 eslint-plugin-react@^7.11.0
? Would you like to install them now with npm? Yes
Installing eslint-config-airbnb@latest, eslint@^4.19.1 || ^5.3.0, eslint-plugin-import@^2.14.0, eslint-plugin-jsx-a11y@^6.1.1, eslint-plugin-react@^7.11.0
+ eslint-plugin-import@2.14.0
+ eslint-config-airbnb@17.1.0
+ eslint-plugin-jsx-a11y@6.1.1
+ eslint-plugin-react@7.11.1
+ eslint@5.5.0
updated 5 packages in 5.295s
Successfully created .eslintrc.js file in /Users/naoki/src/styled-components-test
```
これでインストールは完了

これでAtom上でファイルを開いてみてると、色々とエラーが表示されています
試しにエラー文言に沿ってコードを修正してみてください:+1:
(書き直すのが面倒いだけです。こういうことにならないように一番最初にeslint入れて、最初から正しいコード書いてください)


## Appendix その3: giboを利用して.gitignoreのファイル内容を自動で生成

- [gibo](https://github.com/simonwhitaker/gibo)

```bash
$ brew install gibo
```

以下コマンドが出力してくれる`.gitignore`の内容一覧を取得できます

```bash
$ gibo list
=== Languages ===

Actionscript		CUDA			Go			Lithium			Processing		SugarCRM
Ada			D			Godot			Lua			PureScript		Swift
Agda			Dart			Gradle			Magento			Python			Symfony
Android			Delphi			Grails			Maven			Qooxdoo			SymphonyCMS
AppceleratorTitanium	DM			GWT			Mercury			Qt			Terraform
AppEngine		Drupal			Haskell			MetaProgrammingSystem	R			TeX
ArchLinuxPackages	Eagle			Idris			Nanoc			Rails			Textpattern
Autotools		Elisp			IGORPro			Nim			RhodesRhomobile		TurboGears2
C++			Elixir			Java			Node			ROS			Typo3
C			Elm			Jboss			Objective-C		Ruby			Umbraco
CakePHP			EPiServer		Jekyll			OCaml			Rust			Unity
CFWheels		Erlang			Joomla			Opa			Sass			UnrealEngine
ChefCookbook		ExpressionEngine	Julia			OpenCart		Scala			VisualStudio
Clojure			ExtJs			KiCad			OracleForms		Scheme			VVVV
CMake			Fancy			Kohana			Packer			SCons			Waf
CodeIgniter		Finale			Kotlin			Perl			Scrivener		WordPress
CommonLisp		ForceDotCom		LabVIEW			Perl6			Sdcc			Xojo
Composer		Fortran			Laravel			Phalcon			SeamGen			Yeoman
Concrete5		FuelPHP			Leiningen		PlayFramework		SketchUp		Yii
Coq			Gcov			LemonStand		Plone			Smalltalk		ZendFramework
CraftCMS		GitBook			Lilypond		Prestashop		Stella			Zephir

=== Global ===

Anjuta			Diff			JEnv			MicrosoftOffice		SBT			VirtualEnv
Ansible			Dreamweaver		JetBrains		ModelSim		SlickEdit		VisualStudioCode
Archives		Dropbox			Kate			Momentics		Stata			WebMethods
Backup			Eclipse			KDevelop4		MonoDevelop		SublimeText		Windows
Bazaar			EiffelStudio		Lazarus			NetBeans		SVN			Xcode
BricxCC			Emacs			LibreOffice		Ninja			SynopsysVCS		XilinxISE
Calabash		Ensime			Linux			NotepadPP		Tags
Cloud9			Espresso		LyX			Otto			TextMate
CodeKit			FlexBuilder		macOS			Patch			TortoiseGit
CVS			GPG			Matlab			Redcar			Vagrant
DartEditor		JDeveloper		Mercurial		Redis			Vim
```

今回は試しに`Node`を選択してそれを`.gitignore`へと出力していきます

```bash
$ gibo dump Node >> .gitignore 
```

以上で`.gitignore`へと内容が書き込まれました
中身を勝手に生成してくれるので楽ですね :)

## 今回の成果物
- [styled-components-test](https://github.com/naokiegw/styled-components-test)