ES2015, React HMR

ОБНОВЛЕНИЕ 2018: Вышло второе издание (современный код и версии пакетов, данное издание УСТАРЕЛО)

На канале так же проводятся бесплатные вебинары, публикуются переводы и авторские материалы, присоединяйтесь!

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*

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

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

webpack.config.js

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 со следующим содержимым:

{
  "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

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

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

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

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

Весь код на текущий момент выложен в специальную ветку на Github. Можете сверится, если что-то не работает.

React + Hot Reload

Возможно, вам встретится аббревиатура HMR (hot module replacement), что в принципе более правильно отражает суть, поэтому под hot-reload я подразумеваю именно HMR ;)

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

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

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

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 компонентов, если же нет - сверьтесь с исходным кодом данного раздела.

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

P.S. В официальном репозитории React-hot-reloader'a говорится о том, что готовится к выходу React Transform, который станет логическим продолжением текущих решений. (31.01.2015)

P.P.S. Как говорит создатель библиотеки react-hot-reload, нам больше не нужно использовать webpack.NoErrorsPlugin, который ранее выполнял следующее: если в сборке были ошибки, он не обновлял файл сборки. Поэтому просто удалите соответствующую строку из секции plugins внутри webpack.config.js

Last updated