# ES2015, React HMR

*ОБНОВЛЕНИЕ 2018: Вышло* [*второе издание*](https://maxfarseer.gitbooks.io/redux-course-ru-v2/content/) *(современный код и версии пакетов, данное издание УСТАРЕЛО)*

*На* [*канале*](http://bit.ly/2IqH74P) *так же проводятся бесплатные вебинары, публикуются переводы и авторские материалы,* [*присоединяйтесь*](http://bit.ly/2IqH74P)*!*

## ES2015, React HMR

Для использования возможностей ES6(2015) и ES7 будем использовать babel. С выходом 6й версии, он стал очень модульным, поэтому не пугайтесь большому количеству зависимостей.

### Babel 6

Все начинается с

```
npm install babel-core babel-loader --save-dev
```

Далее нужно поставить пресеты (*предустановки*), которые нам нужны.

```
# Для поддержки ES6/ES2015
npm install babel-preset-es2015 --save-dev

# Для поддержки JSX
npm install babel-preset-react --save-dev

# Для поддержки ES7
npm install babel-preset-stage-0 --save-dev
```

Нам однозначно нужен полифил, чтобы все фичи работали в браузере

```
npm install babel-polyfill --save
```

И немного улучшим время сборки, добавив следующие пакеты

```
npm install babel-runtime --save
npm install babel-plugin-transform-runtime --save-dev
```

\*Для написания этого небольшого текста про babel 6, я использовал статью [Using ES6 and ES7 in the Browser, with Babel 6 and Webpack](http://jamesknelson.com/using-es6-in-the-browser-with-babel-6-and-webpack/)\*

В данный момент, у нас достаточно "пакетов", чтобы писать "современный" код и использовать JSX. Давайте в этом убедимся.

Во-первых, подправим конфиг для webpack'а:

*webpack.config.js*

```javascript
var path = require('path')
var webpack = require('webpack')

module.exports = {
  devtool: 'cheap-module-eval-source-map',
  entry: [
    'webpack-hot-middleware/client',
    'babel-polyfill',
    './src/index'
  ],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: '/static/'
  },
  plugins: [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ],
  module: { //Обновлено
    loaders: [ //добавили babel-loader
      {
        loaders: ['babel-loader'],
        include: [
          path.resolve(__dirname, "src"),
        ],
        test: /\.js$/,
        plugins: ['transform-runtime'],
      }
    ]
  }
}
```

Добавилась запись в секции loaders. Теперь все js файлы в *src* директории будут обрабатываться *babel-loader*'ом, которому мы в свою очередь тоже должны указать настройки. Для этого, нужно создать файл .babelrc со следующим содержимым:

```javascript
{
  "presets": ["es2015", "stage-0", "react"] //поддержка ES2015, ES7 и JSX
}
```

Если вы знакомы с *gulp*, то можно провести некую аналогию, между плагинами gulp и лоадерами (loaders) webpack'a. Если мы хотим делать какие-то преобразования с кодом внутри файла, будь то css, js или картинки - мы используем соответсвующий *loader*. Причем создавать дополнительные файлы настроек, как в случае с babel, обычно не нужно.

Ок, создадим React компонент, не забыв при этом скачать нужные пакеты:

```
npm i react react-dom --save
```

*src/index.js*

```javascript
import 'babel-polyfill'
import React from 'react'
import { render } from 'react-dom'
import App from './containers/App'


render(
  <App />,
  document.getElementById('root')
)
```

*src/containers/App.js*

```javascript
import React, { Component, PropTypes } from 'react'

export default class App extends Component {
  render() {
    return <div>Привет из App</div>
  }
}
```

Перезапускаем сборку (`npm start`).

Весь код на текущий момент выложен в [специальную ветку на Github](https://github.com/maxfarseer/redux-ru-tutorial/tree/config_babel-6_with_React). Можете сверится, если что-то не работает.

### React + Hot Reload

Возможно, вам встретится аббревиатура HMR ([hot module replacement](https://webpack.github.io/docs/hot-module-replacement.html)), что в принципе более правильно отражает суть, поэтому под hot-reload я подразумеваю именно HMR ;)

Как вы помните из прошлой главы - мы добавили `module.hot.accept()`, для того, чтобы webpack обновлял код из файла *index.js* в сборке без перезагрузки страницы в браузере. Если сейчас попробовать изменить что-то в App.js - то в результате ничего не случится, ровно по тем же причинам, что и в предыдушем случае. Что ж, это поправимо и благодаря добрым людям, нам не нужно самим вписывать *accept* функцию. Итак, встречайте (и устанавливайте):

```
npm install react-hot-loader --save-dev
```

Достаточно добавить еще один loader в конфиг и мы получим hot-reload для React компонентов.

```javascript
var path = require('path')
var webpack = require('webpack')

module.exports = {
  devtool: 'cheap-module-eval-source-map',
  entry: [
    'webpack-hot-middleware/client',
    'babel-polyfill',
    './src/index'
  ],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: '/static/'
  },
  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ],
  module: {
    loaders: [
      {
        loaders: ['react-hot', 'babel-loader'], //добавили loader 'react-hot'
        include: [
          path.resolve(__dirname, "src"),
        ],
        test: /\.js$/,
        plugins: ['transform-runtime'],
      }
    ]
  }
}
```

Перезапускаем сборку и проверяем. Теперь HMR работает и для React компонентов, если же нет - сверьтесь [с исходным кодом данного раздела](https://github.com/maxfarseer/redux-ru-tutorial/tree/configure_babel6_react_hmr).

Для того, чтобы начать писать код redux-приложения, я основательно рекомендую настроить ESLint, чтобы быстро решать синтаксические ошибки и повысить производительность. Этим мы займемся на следующем шаге.

P.S. В официальном репозитории [React-hot-reloader](https://github.com/gaearon/react-hot-loader)'a говорится о том, что готовится к выходу [React Transform](https://github.com/gaearon/react-transform-boilerplate), который станет логическим продолжением текущих решений. (31.01.2015)

P.P.S. [Как говорит](https://github.com/gaearon/react-hot-boilerplate/commit/79c05c82875ae9f6133e337b06066049e209a675) создатель библиотеки react-hot-reload, нам больше не нужно использовать `webpack.NoErrorsPlugin`, который ранее выполнял следующее: если в сборке были ошибки, он не обновлял файл сборки. Поэтому просто удалите соответствующую строку из секции plugins внутри *webpack.config.js*
