【自分専用】よく使うReact開発環境をコピペで構築

ローカル環境を構築したいときに考えながら環境作りたくないけどgithubに上げるほどでもないものをまとめました。
`npm`で引っ張れるやつはいいけど、フォルダやファイルをひとつひとつ作るの面倒なので、コピペで作ります。


## React + BABEL + Webpack

### ライブラリ

#### React

```
- react
- react-dom
- react-router-dom
```

```
yarn add react react-dom react-router-dom
```

#### Redux + React-Redux

```
- redux
- react-redux
- redux-actions
```

```
yarn add redux react-redux redux-actions
```


### 開発環境

#### build

package.json

```
"scripts": {
  "start": "webpack && webpack-dev-server"
}
```
#### Webpack
```
webpack
webpack-cli
webpack-dev-server
```
```
yarn add --dev webpack webpack-cli webpack-dev-server
```

#### BABEL

```
- babel-loader
- babel-core
- babel-preset-env
- babel-plugin-transform-runtime
```

```
yarn add --dev babel-loader babel-core babel-preset-env babel-plugin-transform-runtime 
```

#### React plugin
```
- babel-plugin-transform-react-jsx
- babel-preset-react
```

```
yarn add --dev babel-preset-react babel-plugin-transform-react-jsx
```

#### Redux-devtools

```
- redux-logger
```

```
yarn add --dev redux-logger
```

#### ディレクトリの作成

JavaScript

```
mkdir -p src/js/actions src/js/components src/js/containers src/js/reducers src/js/configureStore
```

Sass

```
mkdir -p src/sass/base src/sass/layout src/sass/module src/sass/state
```

#### ファイルの作成

JavaScript

```
touch src/js/app.js src/js/actions/index.js src/js/components/index.js src/js/configureStore/index.js src/js/containers/index.js src/js/reducers/index.js index.html webpack.config.js
```

Sass

```
touch src/sass/base/base.scss src/sass/layout/layout.scss src/sass/module/module.scss src/sass/state/state.scss src/sass/style.scss
```

### ファイルにコピペ

#### webpack.config.js

```webpack.config.js
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');

const paths = {
  entry: path.join(process.cwd(), 'src', 'js'),
  output: path.join(process.cwd(), 'dist', 'js'),
};

const entry = {
  app: path.join(paths.entry, 'app.js'),
};

module.exports = {
  mode: 'development',
  entry,
  output: {
    path: paths.output,
    filename: '[name].js',
    publicPath: './',
  },
  module: {
    rules: [
      {
        test: /\.jsx$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
        query: {
          plugins: ['transform-react-jsx', 'transform-runtime'],
          presets: [
            ['env', {'modules': false}],
            'react',
          ]
        }
      }
    ]
  },
  resolve: {
    modules: [
      'node_modules',
    ],
    extensions: ['json', '.jsx', '.js'],
  }
};
```

#### index.html

```index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>
    <title>any title</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
  </head>
  <body>
    <div id='content'></div>
  </body>
  <script src='./dist/js/app.js'></script>
</html>
```

#### app.js

```app.js
import React from 'react'
import { render } from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import Router from './router'
import configureStore from './configureStore'

const preloadedState = {}
const store = configureStore(preloadedState)

render(
  <Provider store={store}>
    <BrowserRouter>
      <Router />
    </BrowserRouter>
  </Provider>,
  document.getElementById('content')
)
```

#### router.js

```router.js
import React from 'react'
import { Route } from 'react-router-dom'
import Awesome from './containers'

const router = () => {
  return (
    <div>
      <Route exact={true} path="/" component={Awesome}/>
    </div>
  )
}

export default router
```

#### actions

```index.js
import { createAction } from 'redux-actions';

export const AWESOME_EVENT = 'AWESOME_EVENT';
export const awesomeEvent = createAction(AWESOME_EVENT);
```

#### components

```index.js
import React, { Component } from 'react'

class AwesomeComponent extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div onClick={this.props.onClickHandler}>Awesome Project</div>
    )
  }
}

export default AwesomeComponent

```

#### configureStores

```index.js
import { createStore, applyMiddleware } from 'redux'
import { createLogger } from 'redux-logger'
import reducers from '../reducers'

export default function configureStore(initialState) {
  const store = createStore(
    reducers,
    initialState,
    applyMiddleware(
      createLogger()
    )
  )
  return store
}
```

#### containers

```index.js
import React from 'react'
import { connect } from 'react-redux'
import AwesomeComponent from '../components'
import { awesomeEvent } from '../actions'

const mapStateToProps = (state) => {
  return state
}

const mapDispatchToProps = (dispatch) => {
  return {
    onClickHandler: () => {
      dispatch(awesomeEvent())
    }
  }
}

const AwesomeContainer = connect(
  mapStateToProps,
  mapDispatchToProps
)(AwesomeComponent)

export default AwesomeContainer
```

#### reducers

```index.js
import { combineReducers } from 'redux'
import { AWESOME_EVENT } from '../actions/'

const sampleReducer = (state = false, action) => {
  switch (action.type) {
    case AWESOME_EVENT:
      return state = !state
      break;
    default:
      return state
  }
};

const reducers = combineReducers({
  sampleReducer
});

export default reducers
```


### Result

```
├── index.html
├── package.json
├── node_modules
├── src
│   └── js
│       ├── app.js
│       ├── actions
│       │   └── index.js
│       ├── components
│       │   └── index.js
│       ├── configureStore
│       │   └── index.js
│       ├── containers
│       │   └── index.js
│       └── reducers
│           └── index.js
└── webpack.config.js
```

## build

```
npm start
```

## まとめ

demoやtestしたいときにサクッと試せるので以外と便利だったりします。
あと動く最低限なので、勉強したい人にもオススメです！