ES2015, React HMR

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

Babel 6

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

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

Установятся babel-core версии 6.26.0, а babel-loader даже 7.1.4.

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

# Для поддержки ES6/ES2015 вместо babel-preset-es2015 рекомендуется babel-preset-env (на данный момент версия 1.6.1)
npm install babel-preset-env --save-dev

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

# Для поддержки экспериментальных возможностей ES7
npm install babel-preset-stage-0 --save-dev

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

npm install babel-polyfill --save

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

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, см. также babeljs.io/env и Runtime transform*

В данный момент у нас достаточно «пакетов», чтобы писать «современый» код и использовать 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.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin()
  ],
  module: { // Обновлено
    rules: [ // добавили babel-loader
      {
        loaders: ['babel-loader'],
        include: [
          path.resolve(__dirname, "src"),
        ],
        test: /\.jsx?$/,
      }
    ]
  }
}

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

{
  "presets": ["env", "stage-0", "react"], // поддержка ES2015, ES7 и JSX
  "plugins": ["transform-runtime"]
}

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

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

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 в раздел "plugins" .babelrc-файла:

{
  "presets": ["env", "stage-0", "react"],
  "plugins": [
    "transform-runtime",
    "react-hot-loader/babel" // добавили loader "react-hot-loader/babel"
  ]
}

Затем пометить root-компонент как hot-exported и мы получим hot-reload для React компонентов. (См. React Hot Loader Getting started.)

src/containers/App.js

import React from 'react'
import { hot } from 'react-hot-loader'

const App = () => 'Привет из App'

export default hot(module)(App)

Правда, для этой цели лучше выделить в качестве root-компонента отдельный файл (src/containers/index.js), сделав на него ссылку в src/index.js:

src/index.js

import 'babel-polyfill'
import React from 'react'
import { render } from 'react-dom'
import Containers from './containers' // ссылка на src/containers/index.js


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

src/containers/index.js

import React from 'react'
import { hot } from 'react-hot-loader'
import App from './App'

const Containers = () => <App />

export default hot(module)(Containers)

или так:

src/index.js

import 'babel-polyfill'
import React from 'react'
import { render } from 'react-dom'
import { App } from './containers' // ссылка на src/containers/index.js


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

src/containers/index.js

import { hot } from 'react-hot-loader'
import App from './App'


export default hot(module)(App)

А файл src/containers/App.js оставить пока без изменений:

src/containers/App.js

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

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

Перезапускаем сборку и проверяем. Теперь HMR работает и для React компонентов, если же нет — сверьтесь с исходным кодом данного раздела.

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


P.S. React Transform, о котором упоминалось в предыдущем издании, что он станет логическим продолжением решений React-hot-loader'а, объявлен устаревшим, и на смену React Transform и React-hot-loader 2 пришел React-hot-loader 3. На данный момент (14.04.2018) вышел React-hot-loader 4. Смотрите также React-hot-loader Getting Started и webpack documentation Hot Module replacement. Выпущен также babel-plugin-react-hot-loader 3. Чтобы установить его, введите:

npm install babel-plugin-react-hot-loader --save

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

results matching ""

    No results matching ""